SurfaceTexture.cpp revision d369dc42506ec003f1839bb9e27edada411324b5
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 mCurrentTexture = INVALID_BUFFER_SLOT; 59 mLastQueued = INVALID_BUFFER_SLOT; 60 return OK; 61} 62 63sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, 64 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { 65 LOGV("SurfaceTexture::requestBuffer"); 66 Mutex::Autolock lock(mMutex); 67 if (buf < 0 || mBufferCount <= buf) { 68 LOGE("requestBuffer: slot index out of range [0, %d]: %d", 69 mBufferCount, buf); 70 return 0; 71 } 72 usage |= GraphicBuffer::USAGE_HW_TEXTURE; 73 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 74 sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h, 75 format, usage)); 76 if (graphicBuffer == 0) { 77 LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); 78 } else { 79 mSlots[buf].mGraphicBuffer = graphicBuffer; 80 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { 81 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); 82 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; 83 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; 84 } 85 } 86 return graphicBuffer; 87} 88 89status_t SurfaceTexture::dequeueBuffer(int *buf) { 90 LOGV("SurfaceTexture::dequeueBuffer"); 91 Mutex::Autolock lock(mMutex); 92 int found = INVALID_BUFFER_SLOT; 93 for (int i = 0; i < mBufferCount; i++) { 94 if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) { 95 mSlots[i].mOwnedByClient = true; 96 found = i; 97 break; 98 } 99 } 100 if (found == INVALID_BUFFER_SLOT) { 101 return -EBUSY; 102 } 103 *buf = found; 104 return OK; 105} 106 107status_t SurfaceTexture::queueBuffer(int buf) { 108 LOGV("SurfaceTexture::queueBuffer"); 109 Mutex::Autolock lock(mMutex); 110 if (buf < 0 || mBufferCount <= buf) { 111 LOGE("queueBuffer: slot index out of range [0, %d]: %d", 112 mBufferCount, buf); 113 return -EINVAL; 114 } else if (!mSlots[buf].mOwnedByClient) { 115 LOGE("queueBuffer: slot %d is not owned by the client", buf); 116 return -EINVAL; 117 } else if (mSlots[buf].mGraphicBuffer == 0) { 118 LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", 119 buf); 120 return -EINVAL; 121 } 122 mSlots[buf].mOwnedByClient = false; 123 mLastQueued = buf; 124 return OK; 125} 126 127void SurfaceTexture::cancelBuffer(int buf) { 128 LOGV("SurfaceTexture::cancelBuffer"); 129 Mutex::Autolock lock(mMutex); 130 if (buf < 0 || mBufferCount <= buf) { 131 LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, 132 buf); 133 return; 134 } else if (!mSlots[buf].mOwnedByClient) { 135 LOGE("cancelBuffer: slot %d is not owned by the client", buf); 136 return; 137 } 138 mSlots[buf].mOwnedByClient = false; 139} 140 141status_t SurfaceTexture::setCrop(const Rect& reg) { 142 LOGV("SurfaceTexture::setCrop"); 143 Mutex::Autolock lock(mMutex); 144 // XXX: How should we handle crops? 145 return OK; 146} 147 148status_t SurfaceTexture::setTransform(uint32_t transform) { 149 LOGV("SurfaceTexture::setTransform"); 150 Mutex::Autolock lock(mMutex); 151 // XXX: How should we handle transforms? 152 return OK; 153} 154 155status_t SurfaceTexture::updateTexImage() { 156 LOGV("SurfaceTexture::updateTexImage"); 157 Mutex::Autolock lock(mMutex); 158 159 // We always bind the texture even if we don't update its contents. 160 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); 161 162 // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT, 163 // so this check will fail until a buffer gets queued. 164 if (mCurrentTexture != mLastQueued) { 165 // XXX: Figure out the right target. 166 mCurrentTexture = mLastQueued; 167 EGLImageKHR image = mSlots[mCurrentTexture].mEglImage; 168 if (image == EGL_NO_IMAGE_KHR) { 169 EGLDisplay dpy = eglGetCurrentDisplay(); 170 sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer; 171 image = createImage(dpy, graphicBuffer); 172 mSlots[mCurrentTexture].mEglImage = image; 173 mSlots[mCurrentTexture].mEglDisplay = dpy; 174 } 175 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); 176 GLint error = glGetError(); 177 if (error != GL_NO_ERROR) { 178 LOGE("error binding external texture image %p (slot %d): %#04x", 179 image, mCurrentTexture, error); 180 return -EINVAL; 181 } 182 } 183 return OK; 184} 185 186void SurfaceTexture::freeAllBuffers() { 187 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 188 mSlots[i].mGraphicBuffer = 0; 189 mSlots[i].mOwnedByClient = false; 190 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { 191 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); 192 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 193 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 194 } 195 } 196} 197 198EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, 199 const sp<GraphicBuffer>& graphicBuffer) { 200 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); 201 EGLint attrs[] = { 202 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 203 EGL_NONE, 204 }; 205 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 206 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); 207 EGLint error = eglGetError(); 208 if (error != EGL_SUCCESS) { 209 LOGE("error creating EGLImage: %#x", error); 210 } else if (image == EGL_NO_IMAGE_KHR) { 211 LOGE("no error reported, but no image was returned by " 212 "eglCreateImageKHR"); 213 } 214 return image; 215} 216 217}; // namespace android 218