SurfaceTexture.cpp revision 7dc00d5eb27de41f93a7e232b3cd374c84eb77d1
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "SurfaceTexture" 18//#define LOG_NDEBUG 0 19 20#define GL_GLEXT_PROTOTYPES 21#define EGL_EGLEXT_PROTOTYPES 22 23#include <EGL/egl.h> 24#include <EGL/eglext.h> 25#include <GLES2/gl2.h> 26#include <GLES2/gl2ext.h> 27 28#include <gui/SurfaceTexture.h> 29 30#include <surfaceflinger/ISurfaceComposer.h> 31#include <surfaceflinger/SurfaceComposerClient.h> 32 33#include <utils/Log.h> 34 35namespace android { 36 37SurfaceTexture::SurfaceTexture(GLuint tex) : 38 mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), 39 mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) { 40 LOGV("SurfaceTexture::SurfaceTexture"); 41 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 42 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 43 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 44 mSlots[i].mOwnedByClient = false; 45 } 46} 47 48SurfaceTexture::~SurfaceTexture() { 49 LOGV("SurfaceTexture::~SurfaceTexture"); 50 freeAllBuffers(); 51} 52 53status_t SurfaceTexture::setBufferCount(int bufferCount) { 54 LOGV("SurfaceTexture::setBufferCount"); 55 Mutex::Autolock lock(mMutex); 56 freeAllBuffers(); 57 mBufferCount = bufferCount; 58 return OK; 59} 60 61sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, 62 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { 63 LOGV("SurfaceTexture::requestBuffer"); 64 Mutex::Autolock lock(mMutex); 65 if (buf < 0 || mBufferCount <= buf) { 66 LOGE("requestBuffer: slot index out of range [0, %d]: %d", 67 mBufferCount, buf); 68 return 0; 69 } 70 usage |= GraphicBuffer::USAGE_HW_TEXTURE; 71 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 72 sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h, 73 format, usage)); 74 if (graphicBuffer == 0) { 75 LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); 76 } else { 77 mSlots[buf].mGraphicBuffer = graphicBuffer; 78 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { 79 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); 80 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; 81 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; 82 } 83 } 84 return graphicBuffer; 85} 86 87status_t SurfaceTexture::dequeueBuffer(int *buf) { 88 LOGV("SurfaceTexture::dequeueBuffer"); 89 Mutex::Autolock lock(mMutex); 90 int found = INVALID_BUFFER_SLOT; 91 for (int i = 0; i < mBufferCount; i++) { 92 if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) { 93 mSlots[i].mOwnedByClient = true; 94 found = i; 95 break; 96 } 97 } 98 if (found == INVALID_BUFFER_SLOT) { 99 return -EBUSY; 100 } 101 *buf = found; 102 return OK; 103} 104 105status_t SurfaceTexture::queueBuffer(int buf) { 106 LOGV("SurfaceTexture::queueBuffer"); 107 Mutex::Autolock lock(mMutex); 108 if (buf < 0 || mBufferCount <= buf) { 109 LOGE("queueBuffer: slot index out of range [0, %d]: %d", 110 mBufferCount, buf); 111 return -EINVAL; 112 } else if (!mSlots[buf].mOwnedByClient) { 113 LOGE("queueBuffer: slot %d is not owned by the client", buf); 114 return -EINVAL; 115 } else if (mSlots[buf].mGraphicBuffer == 0) { 116 LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", 117 buf); 118 return -EINVAL; 119 } 120 mSlots[buf].mOwnedByClient = false; 121 mLastQueued = buf; 122 return OK; 123} 124 125void SurfaceTexture::cancelBuffer(int buf) { 126 LOGV("SurfaceTexture::cancelBuffer"); 127 Mutex::Autolock lock(mMutex); 128 if (buf < 0 || mBufferCount <= buf) { 129 LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, 130 buf); 131 return; 132 } else if (!mSlots[buf].mOwnedByClient) { 133 LOGE("cancelBuffer: slot %d is not owned by the client", buf); 134 return; 135 } 136 mSlots[buf].mOwnedByClient = false; 137} 138 139status_t SurfaceTexture::setCrop(const Rect& reg) { 140 LOGV("SurfaceTexture::setCrop"); 141 Mutex::Autolock lock(mMutex); 142 // XXX: How should we handle crops? 143 return OK; 144} 145 146status_t SurfaceTexture::setTransform(uint32_t transform) { 147 LOGV("SurfaceTexture::setTransform"); 148 Mutex::Autolock lock(mMutex); 149 // XXX: How should we handle transforms? 150 return OK; 151} 152 153status_t SurfaceTexture::updateTexImage() { 154 LOGV("SurfaceTexture::updateTexImage"); 155 Mutex::Autolock lock(mMutex); 156 157 // We always bind the texture even if we don't update its contents. 158 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); 159 160 // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT, 161 // so this check will fail until a buffer gets queued. 162 if (mCurrentTexture != mLastQueued) { 163 // XXX: Figure out the right target. 164 mCurrentTexture = mLastQueued; 165 EGLImageKHR image = mSlots[mCurrentTexture].mEglImage; 166 if (image == EGL_NO_IMAGE_KHR) { 167 EGLDisplay dpy = eglGetCurrentDisplay(); 168 sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer; 169 image = createImage(dpy, graphicBuffer); 170 mSlots[mCurrentTexture].mEglImage = image; 171 mSlots[mCurrentTexture].mEglDisplay = dpy; 172 } 173 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); 174 GLint error = glGetError(); 175 if (error != GL_NO_ERROR) { 176 LOGE("error binding external texture image %p (slot %d): %#04x", 177 image, mCurrentTexture, error); 178 return -EINVAL; 179 } 180 } 181 return OK; 182} 183 184void SurfaceTexture::freeAllBuffers() { 185 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 186 mSlots[i].mGraphicBuffer = 0; 187 mSlots[i].mOwnedByClient = false; 188 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { 189 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); 190 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 191 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 192 } 193 } 194} 195 196EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, 197 const sp<GraphicBuffer>& graphicBuffer) { 198 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); 199 EGLint attrs[] = { 200 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 201 EGL_NONE, 202 }; 203 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 204 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); 205 EGLint error = eglGetError(); 206 if (error != EGL_SUCCESS) { 207 LOGE("error creating EGLImage: %#x", error); 208 } else if (image == EGL_NO_IMAGE_KHR) { 209 LOGE("no error reported, but no image was returned by " 210 "eglCreateImageKHR"); 211 } 212 return image; 213} 214 215}; // namespace android 216