SurfaceTexture.cpp revision 79d01fe8232c67a18aeb8784c2b8783358ec4e44
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#include <surfaceflinger/IGraphicBufferAlloc.h> 33 34#include <utils/Log.h> 35 36namespace android { 37 38// Transform matrices 39static float mtxIdentity[16] = { 40 1, 0, 0, 0, 41 0, 1, 0, 0, 42 0, 0, 1, 0, 43 0, 0, 0, 1, 44}; 45static float mtxFlipH[16] = { 46 -1, 0, 0, 0, 47 0, 1, 0, 0, 48 0, 0, 1, 0, 49 1, 0, 0, 1, 50}; 51static float mtxFlipV[16] = { 52 1, 0, 0, 0, 53 0, -1, 0, 0, 54 0, 0, 1, 0, 55 0, 1, 0, 1, 56}; 57static float mtxRot90[16] = { 58 0, 1, 0, 0, 59 -1, 0, 0, 0, 60 0, 0, 1, 0, 61 1, 0, 0, 1, 62}; 63static float mtxRot180[16] = { 64 -1, 0, 0, 0, 65 0, -1, 0, 0, 66 0, 0, 1, 0, 67 1, 1, 0, 1, 68}; 69static float mtxRot270[16] = { 70 0, -1, 0, 0, 71 1, 0, 0, 0, 72 0, 0, 1, 0, 73 0, 1, 0, 1, 74}; 75 76static void mtxMul(float out[16], const float a[16], const float b[16]); 77 78SurfaceTexture::SurfaceTexture(GLuint tex) : 79 mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), 80 mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) { 81 LOGV("SurfaceTexture::SurfaceTexture"); 82 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 83 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 84 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 85 mSlots[i].mOwnedByClient = false; 86 } 87 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 88 mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); 89} 90 91SurfaceTexture::~SurfaceTexture() { 92 LOGV("SurfaceTexture::~SurfaceTexture"); 93 freeAllBuffers(); 94} 95 96status_t SurfaceTexture::setBufferCount(int bufferCount) { 97 LOGV("SurfaceTexture::setBufferCount"); 98 Mutex::Autolock lock(mMutex); 99 freeAllBuffers(); 100 mBufferCount = bufferCount; 101 mCurrentTexture = INVALID_BUFFER_SLOT; 102 mLastQueued = INVALID_BUFFER_SLOT; 103 return OK; 104} 105 106sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, 107 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { 108 LOGV("SurfaceTexture::requestBuffer"); 109 Mutex::Autolock lock(mMutex); 110 if (buf < 0 || mBufferCount <= buf) { 111 LOGE("requestBuffer: slot index out of range [0, %d]: %d", 112 mBufferCount, buf); 113 return 0; 114 } 115 usage |= GraphicBuffer::USAGE_HW_TEXTURE; 116 sp<GraphicBuffer> graphicBuffer( 117 mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); 118 if (graphicBuffer == 0) { 119 LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); 120 } else { 121 mSlots[buf].mGraphicBuffer = graphicBuffer; 122 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { 123 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); 124 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; 125 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; 126 } 127 mAllocdBuffers.add(graphicBuffer); 128 } 129 return graphicBuffer; 130} 131 132status_t SurfaceTexture::dequeueBuffer(int *buf) { 133 LOGV("SurfaceTexture::dequeueBuffer"); 134 Mutex::Autolock lock(mMutex); 135 int found = INVALID_BUFFER_SLOT; 136 for (int i = 0; i < mBufferCount; i++) { 137 if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) { 138 mSlots[i].mOwnedByClient = true; 139 found = i; 140 break; 141 } 142 } 143 if (found == INVALID_BUFFER_SLOT) { 144 return -EBUSY; 145 } 146 *buf = found; 147 return OK; 148} 149 150status_t SurfaceTexture::queueBuffer(int buf) { 151 LOGV("SurfaceTexture::queueBuffer"); 152 Mutex::Autolock lock(mMutex); 153 if (buf < 0 || mBufferCount <= buf) { 154 LOGE("queueBuffer: slot index out of range [0, %d]: %d", 155 mBufferCount, buf); 156 return -EINVAL; 157 } else if (!mSlots[buf].mOwnedByClient) { 158 LOGE("queueBuffer: slot %d is not owned by the client", buf); 159 return -EINVAL; 160 } else if (mSlots[buf].mGraphicBuffer == 0) { 161 LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", 162 buf); 163 return -EINVAL; 164 } 165 mSlots[buf].mOwnedByClient = false; 166 mLastQueued = buf; 167 mLastQueuedCrop = mNextCrop; 168 mLastQueuedTransform = mNextTransform; 169 if (mFrameAvailableListener != 0) { 170 mFrameAvailableListener->onFrameAvailable(); 171 } 172 return OK; 173} 174 175void SurfaceTexture::cancelBuffer(int buf) { 176 LOGV("SurfaceTexture::cancelBuffer"); 177 Mutex::Autolock lock(mMutex); 178 if (buf < 0 || mBufferCount <= buf) { 179 LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, 180 buf); 181 return; 182 } else if (!mSlots[buf].mOwnedByClient) { 183 LOGE("cancelBuffer: slot %d is not owned by the client", buf); 184 return; 185 } 186 mSlots[buf].mOwnedByClient = false; 187} 188 189status_t SurfaceTexture::setCrop(const Rect& crop) { 190 LOGV("SurfaceTexture::setCrop"); 191 Mutex::Autolock lock(mMutex); 192 mNextCrop = crop; 193 return OK; 194} 195 196status_t SurfaceTexture::setTransform(uint32_t transform) { 197 LOGV("SurfaceTexture::setTransform"); 198 Mutex::Autolock lock(mMutex); 199 mNextTransform = transform; 200 return OK; 201} 202 203status_t SurfaceTexture::updateTexImage() { 204 LOGV("SurfaceTexture::updateTexImage"); 205 Mutex::Autolock lock(mMutex); 206 207 // We always bind the texture even if we don't update its contents. 208 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); 209 210 // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT, 211 // so this check will fail until a buffer gets queued. 212 if (mCurrentTexture != mLastQueued) { 213 // Update the GL texture object. 214 EGLImageKHR image = mSlots[mLastQueued].mEglImage; 215 if (image == EGL_NO_IMAGE_KHR) { 216 EGLDisplay dpy = eglGetCurrentDisplay(); 217 sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer; 218 image = createImage(dpy, graphicBuffer); 219 mSlots[mLastQueued].mEglImage = image; 220 mSlots[mLastQueued].mEglDisplay = dpy; 221 } 222 223 GLint error; 224 while ((error = glGetError()) != GL_NO_ERROR) { 225 LOGE("GL error cleared before updating SurfaceTexture: %#04x", error); 226 } 227 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); 228 bool failed = false; 229 while ((error = glGetError()) != GL_NO_ERROR) { 230 LOGE("error binding external texture image %p (slot %d): %#04x", 231 image, mLastQueued, error); 232 failed = true; 233 } 234 if (failed) { 235 return -EINVAL; 236 } 237 238 // Update the SurfaceTexture state. 239 mCurrentTexture = mLastQueued; 240 mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; 241 mCurrentCrop = mLastQueuedCrop; 242 mCurrentTransform = mLastQueuedTransform; 243 } 244 return OK; 245} 246 247void SurfaceTexture::getTransformMatrix(float mtx[16]) { 248 LOGV("SurfaceTexture::updateTexImage"); 249 Mutex::Autolock lock(mMutex); 250 251 float xform[16]; 252 for (int i = 0; i < 16; i++) { 253 xform[i] = mtxIdentity[i]; 254 } 255 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { 256 float result[16]; 257 mtxMul(result, xform, mtxFlipH); 258 for (int i = 0; i < 16; i++) { 259 xform[i] = result[i]; 260 } 261 } 262 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { 263 float result[16]; 264 mtxMul(result, xform, mtxFlipV); 265 for (int i = 0; i < 16; i++) { 266 xform[i] = result[i]; 267 } 268 } 269 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { 270 float result[16]; 271 mtxMul(result, xform, mtxRot90); 272 for (int i = 0; i < 16; i++) { 273 xform[i] = result[i]; 274 } 275 } 276 277 sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer); 278 float tx, ty, sx, sy; 279 if (!mCurrentCrop.isEmpty()) { 280 tx = float(mCurrentCrop.left) / float(buf->getWidth()); 281 ty = float(buf->getHeight() - mCurrentCrop.bottom) / 282 float(buf->getHeight()); 283 sx = float(mCurrentCrop.width()) / float(buf->getWidth()); 284 sy = float(mCurrentCrop.height()) / float(buf->getHeight()); 285 } else { 286 tx = 0.0f; 287 ty = 0.0f; 288 sx = 1.0f; 289 sy = 1.0f; 290 } 291 float crop[16] = { 292 sx, 0, 0, 0, 293 0, sy, 0, 0, 294 0, 0, 1, 0, 295 sx*tx, sy*ty, 0, 1, 296 }; 297 298 float mtxBeforeFlipV[16]; 299 mtxMul(mtxBeforeFlipV, crop, xform); 300 301 // SurfaceFlinger expects the top of its window textures to be at a Y 302 // coordinate of 0, so SurfaceTexture must behave the same way. We don't 303 // want to expose this to applications, however, so we must add an 304 // additional vertical flip to the transform after all the other transforms. 305 mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); 306} 307 308void SurfaceTexture::setFrameAvailableListener( 309 const sp<FrameAvailableListener>& l) { 310 LOGV("SurfaceTexture::setFrameAvailableListener"); 311 Mutex::Autolock lock(mMutex); 312 mFrameAvailableListener = l; 313} 314 315void SurfaceTexture::freeAllBuffers() { 316 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 317 mSlots[i].mGraphicBuffer = 0; 318 mSlots[i].mOwnedByClient = false; 319 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { 320 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); 321 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 322 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 323 } 324 } 325 326 int exceptBuf = -1; 327 for (size_t i = 0; i < mAllocdBuffers.size(); i++) { 328 if (mAllocdBuffers[i] == mCurrentTextureBuf) { 329 exceptBuf = i; 330 break; 331 } 332 } 333 mAllocdBuffers.clear(); 334 if (exceptBuf >= 0) { 335 mAllocdBuffers.add(mCurrentTextureBuf); 336 } 337 mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf); 338} 339 340EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, 341 const sp<GraphicBuffer>& graphicBuffer) { 342 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); 343 EGLint attrs[] = { 344 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 345 EGL_NONE, 346 }; 347 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 348 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); 349 EGLint error = eglGetError(); 350 if (error != EGL_SUCCESS) { 351 LOGE("error creating EGLImage: %#x", error); 352 } else if (image == EGL_NO_IMAGE_KHR) { 353 LOGE("no error reported, but no image was returned by " 354 "eglCreateImageKHR"); 355 } 356 return image; 357} 358 359static void mtxMul(float out[16], const float a[16], const float b[16]) { 360 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; 361 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; 362 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; 363 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; 364 365 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; 366 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; 367 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; 368 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; 369 370 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; 371 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; 372 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; 373 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; 374 375 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; 376 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; 377 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; 378 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; 379} 380 381}; // namespace android 382