SurfaceTexture.cpp revision 376590d668e22a918439877b55faf075427b13f3
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 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); 223 GLint error = glGetError(); 224 if (error != GL_NO_ERROR) { 225 LOGE("error binding external texture image %p (slot %d): %#04x", 226 image, mLastQueued, error); 227 return -EINVAL; 228 } 229 230 // Update the SurfaceTexture state. 231 mCurrentTexture = mLastQueued; 232 mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; 233 mCurrentCrop = mLastQueuedCrop; 234 mCurrentTransform = mLastQueuedTransform; 235 } 236 return OK; 237} 238 239void SurfaceTexture::getTransformMatrix(float mtx[16]) { 240 LOGV("SurfaceTexture::updateTexImage"); 241 Mutex::Autolock lock(mMutex); 242 243 float xform[16]; 244 for (int i = 0; i < 16; i++) { 245 xform[i] = mtxIdentity[i]; 246 } 247 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { 248 float result[16]; 249 mtxMul(result, xform, mtxFlipH); 250 for (int i = 0; i < 16; i++) { 251 xform[i] = result[i]; 252 } 253 } 254 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { 255 float result[16]; 256 mtxMul(result, xform, mtxFlipV); 257 for (int i = 0; i < 16; i++) { 258 xform[i] = result[i]; 259 } 260 } 261 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { 262 float result[16]; 263 mtxMul(result, xform, mtxRot90); 264 for (int i = 0; i < 16; i++) { 265 xform[i] = result[i]; 266 } 267 } 268 269 sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer); 270 float tx, ty, sx, sy; 271 if (!mCurrentCrop.isEmpty()) { 272 tx = float(mCurrentCrop.left) / float(buf->getWidth()); 273 ty = float(buf->getHeight() - mCurrentCrop.bottom) / 274 float(buf->getHeight()); 275 sx = float(mCurrentCrop.width()) / float(buf->getWidth()); 276 sy = float(mCurrentCrop.height()) / float(buf->getHeight()); 277 } else { 278 tx = 0.0f; 279 ty = 0.0f; 280 sx = 1.0f; 281 sy = 1.0f; 282 } 283 float crop[16] = { 284 sx, 0, 0, 0, 285 0, sy, 0, 0, 286 0, 0, 1, 0, 287 sx*tx, sy*ty, 0, 1, 288 }; 289 290 float mtxBeforeFlipV[16]; 291 mtxMul(mtxBeforeFlipV, crop, xform); 292 293 // SurfaceFlinger expects the top of its window textures to be at a Y 294 // coordinate of 0, so SurfaceTexture must behave the same way. We don't 295 // want to expose this to applications, however, so we must add an 296 // additional vertical flip to the transform after all the other transforms. 297 mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); 298} 299 300void SurfaceTexture::setFrameAvailableListener( 301 const sp<FrameAvailableListener>& l) { 302 LOGV("SurfaceTexture::setFrameAvailableListener"); 303 Mutex::Autolock lock(mMutex); 304 mFrameAvailableListener = l; 305} 306 307void SurfaceTexture::freeAllBuffers() { 308 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { 309 mSlots[i].mGraphicBuffer = 0; 310 mSlots[i].mOwnedByClient = false; 311 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { 312 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); 313 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; 314 mSlots[i].mEglDisplay = EGL_NO_DISPLAY; 315 } 316 } 317 318 int exceptBuf = -1; 319 for (size_t i = 0; i < mAllocdBuffers.size(); i++) { 320 if (mAllocdBuffers[i] == mCurrentTextureBuf) { 321 exceptBuf = i; 322 break; 323 } 324 } 325 mAllocdBuffers.clear(); 326 if (exceptBuf >= 0) { 327 mAllocdBuffers.add(mCurrentTextureBuf); 328 } 329 mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf); 330} 331 332EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, 333 const sp<GraphicBuffer>& graphicBuffer) { 334 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); 335 EGLint attrs[] = { 336 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 337 EGL_NONE, 338 }; 339 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, 340 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); 341 EGLint error = eglGetError(); 342 if (error != EGL_SUCCESS) { 343 LOGE("error creating EGLImage: %#x", error); 344 } else if (image == EGL_NO_IMAGE_KHR) { 345 LOGE("no error reported, but no image was returned by " 346 "eglCreateImageKHR"); 347 } 348 return image; 349} 350 351static void mtxMul(float out[16], const float a[16], const float b[16]) { 352 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; 353 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; 354 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; 355 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; 356 357 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; 358 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; 359 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; 360 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; 361 362 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; 363 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; 364 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; 365 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; 366 367 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; 368 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; 369 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; 370 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; 371} 372 373}; // namespace android 374