blob: 924fc0d7e85812045fbc8b8831ca2cbdbe150786 [file] [log] [blame]
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001/*
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
Andy McFadden2adaf042012-12-18 09:49:45 -080017#define LOG_TAG "GLConsumer"
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080018#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Jamie Gennise70d8b42011-01-09 13:24:09 -080019//#define LOG_NDEBUG 0
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080020
21#define GL_GLEXT_PROTOTYPES
22#define EGL_EGLEXT_PROTOTYPES
23
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#include <GLES2/gl2.h>
27#include <GLES2/gl2ext.h>
Mathias Agopianad678e12013-07-23 17:28:53 -070028#include <cutils/compiler.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080029
Jamie Gennis9fea3422012-08-07 18:03:04 -070030#include <hardware/hardware.h>
31
Mathias Agopianca088332013-03-28 17:44:13 -070032#include <gui/GLConsumer.h>
Mathias Agopian90ac7992012-02-25 18:48:35 -080033#include <gui/IGraphicBufferAlloc.h>
34#include <gui/ISurfaceComposer.h>
35#include <gui/SurfaceComposerClient.h>
Mathias Agopian41f673c2011-11-17 17:48:35 -080036
Mathias Agopian90ac7992012-02-25 18:48:35 -080037#include <private/gui/ComposerService.h>
Mathias Agopianca088332013-03-28 17:44:13 -070038#include <private/gui/SyncFeatures.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080039
40#include <utils/Log.h>
Mathias Agopian68c77942011-05-09 19:08:33 -070041#include <utils/String8.h>
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080042#include <utils/Trace.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080043
Jamie Gennisdbe92452013-09-23 17:22:10 -070044EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
45#define CROP_EXT_STR "EGL_ANDROID_image_crop"
46
Andy McFadden97eba892012-12-11 15:21:45 -080047namespace android {
48
Andy McFadden2adaf042012-12-18 09:49:45 -080049// Macros for including the GLConsumer name in log messages
Steve Block6807e592011-10-20 11:56:00 +010050#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Block9d453682011-12-20 16:23:08 +000051#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Blocka19954a2012-01-04 20:05:49 +000052#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Block32397c12012-01-05 23:22:43 +000053#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Blocke6f43dd2012-01-06 19:20:56 +000054#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
Mathias Agopian29b57622011-08-17 15:42:04 -070055
Mathias Agopianad678e12013-07-23 17:28:53 -070056static const struct {
57 size_t width, height;
58 char const* bits;
Mathias Agopian45263e22013-08-07 13:35:20 -070059} kDebugData = { 15, 12,
60 "___________________________________XX_XX_______X_X_____X_X____X_XXXXXXX_X____XXXXXXXXXXX__"
61 "___XX_XXX_XX_______XXXXXXX_________X___X_________X_____X__________________________________"
62};
Mathias Agopianad678e12013-07-23 17:28:53 -070063
Jamie Gennisf238e282011-01-09 16:33:17 -080064// Transform matrices
65static float mtxIdentity[16] = {
66 1, 0, 0, 0,
67 0, 1, 0, 0,
68 0, 0, 1, 0,
69 0, 0, 0, 1,
70};
71static float mtxFlipH[16] = {
72 -1, 0, 0, 0,
73 0, 1, 0, 0,
74 0, 0, 1, 0,
75 1, 0, 0, 1,
76};
77static float mtxFlipV[16] = {
78 1, 0, 0, 0,
79 0, -1, 0, 0,
80 0, 0, 1, 0,
81 0, 1, 0, 1,
82};
83static float mtxRot90[16] = {
84 0, 1, 0, 0,
85 -1, 0, 0, 0,
86 0, 0, 1, 0,
87 1, 0, 0, 1,
88};
Jamie Gennisf238e282011-01-09 16:33:17 -080089
90static void mtxMul(float out[16], const float a[16], const float b[16]);
91
Mathias Agopian9870c9b2013-08-08 17:46:48 -070092Mutex GLConsumer::sStaticInitLock;
93sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
Jamie Gennisfa28c352011-09-16 17:30:26 -070094
Jamie Gennisdbe92452013-09-23 17:22:10 -070095static bool hasEglAndroidImageCropImpl() {
96 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
97 const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
98 size_t cropExtLen = strlen(CROP_EXT_STR);
99 size_t extsLen = strlen(exts);
100 bool equal = !strcmp(CROP_EXT_STR, exts);
101 bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
102 bool atEnd = (cropExtLen+1) < extsLen &&
103 !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
104 bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
105 return equal || atStart || atEnd || inMiddle;
106}
107
108static bool hasEglAndroidImageCrop() {
109 // Only compute whether the extension is present once the first time this
110 // function is called.
111 static bool hasIt = hasEglAndroidImageCropImpl();
112 return hasIt;
113}
114
115static bool isEglImageCroppable(const Rect& crop) {
116 return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
117}
118
Mathias Agopian3f844832013-08-07 21:24:32 -0700119GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
120 uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
Mathias Agopian595264f2013-07-16 22:56:09 -0700121 ConsumerBase(bq, isControlledByApp),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800122 mCurrentTransform(0),
Mathias Agopiane692ab92013-04-22 11:24:02 +0200123 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
Jamie Gennis1df8c342012-12-20 14:05:45 -0800124 mCurrentFence(Fence::NO_FENCE),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800125 mCurrentTimestamp(0),
Eino-Ville Talvalad171da92013-09-19 13:36:07 -0700126 mCurrentFrameNumber(0),
Mathias Agopiane692ab92013-04-22 11:24:02 +0200127 mDefaultWidth(1),
128 mDefaultHeight(1),
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700129 mFilteringEnabled(true),
Mathias Agopianb3e518c2011-04-21 18:52:51 -0700130 mTexName(tex),
Jamie Gennis86edf4f2011-11-14 14:51:01 -0800131 mUseFenceSync(useFenceSync),
Daniel Lameae59d22012-01-22 15:26:27 -0800132 mTexTarget(texTarget),
Jamie Gennisce561372012-03-19 18:33:05 -0700133 mEglDisplay(EGL_NO_DISPLAY),
134 mEglContext(EGL_NO_CONTEXT),
Jamie Gennis74bed552012-03-28 19:05:54 -0700135 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
136 mAttached(true)
Daniel Lam6b091c52012-01-22 15:26:27 -0800137{
Andy McFadden2adaf042012-12-18 09:49:45 -0800138 ST_LOGV("GLConsumer");
Daniel Lamb2675792012-02-23 14:35:13 -0800139
Jamie Gennisfa28c352011-09-16 17:30:26 -0700140 memcpy(mCurrentTransformMatrix, mtxIdentity,
141 sizeof(mCurrentTransformMatrix));
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700142
Mathias Agopiandb89edc2013-08-02 01:40:18 -0700143 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800144}
145
Dan Stozaab574912014-06-25 14:21:45 -0700146GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
147 bool useFenceSync, bool isControlledByApp) :
148 ConsumerBase(bq, isControlledByApp),
149 mCurrentTransform(0),
150 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
151 mCurrentFence(Fence::NO_FENCE),
152 mCurrentTimestamp(0),
153 mCurrentFrameNumber(0),
154 mDefaultWidth(1),
155 mDefaultHeight(1),
156 mFilteringEnabled(true),
157 mTexName(-1),
158 mUseFenceSync(useFenceSync),
159 mTexTarget(texTarget),
160 mEglDisplay(EGL_NO_DISPLAY),
161 mEglContext(EGL_NO_CONTEXT),
162 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
163 mAttached(false)
164{
165 ST_LOGV("GLConsumer");
166
167 memcpy(mCurrentTransformMatrix, mtxIdentity,
168 sizeof(mCurrentTransformMatrix));
169
170 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
171}
172
Andy McFadden2adaf042012-12-18 09:49:45 -0800173status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
Mathias Agopian80727112011-05-02 19:51:12 -0700174 Mutex::Autolock lock(mMutex);
Mathias Agopiandb89edc2013-08-02 01:40:18 -0700175 return mConsumer->setDefaultMaxBufferCount(bufferCount);
Mathias Agopian80727112011-05-02 19:51:12 -0700176}
177
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800178
Andy McFadden2adaf042012-12-18 09:49:45 -0800179status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700180{
Daniel Lamb2675792012-02-23 14:35:13 -0800181 Mutex::Autolock lock(mMutex);
Daniel Lam016c8cb2012-04-03 15:54:58 -0700182 mDefaultWidth = w;
183 mDefaultHeight = h;
Mathias Agopiandb89edc2013-08-02 01:40:18 -0700184 return mConsumer->setDefaultBufferSize(w, h);
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700185}
186
Andy McFadden2adaf042012-12-18 09:49:45 -0800187status_t GLConsumer::updateTexImage() {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800188 ATRACE_CALL();
189 ST_LOGV("updateTexImage");
190 Mutex::Autolock lock(mMutex);
191
192 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800193 ST_LOGE("updateTexImage: GLConsumer is abandoned!");
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800194 return NO_INIT;
195 }
196
197 // Make sure the EGL state is the same as in previous calls.
198 status_t err = checkAndUpdateEglStateLocked();
199 if (err != NO_ERROR) {
200 return err;
201 }
202
203 BufferQueue::BufferItem item;
204
205 // Acquire the next buffer.
206 // In asynchronous mode the list is guaranteed to be one buffer
207 // deep, while in synchronous mode we use the oldest buffer.
Andy McFadden1585c4d2013-06-28 13:52:40 -0700208 err = acquireBufferLocked(&item, 0);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800209 if (err != NO_ERROR) {
210 if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
211 // We always bind the texture even if we don't update its contents.
212 ST_LOGV("updateTexImage: no buffers were available");
213 glBindTexture(mTexTarget, mTexName);
214 err = NO_ERROR;
215 } else {
216 ST_LOGE("updateTexImage: acquire failed: %s (%d)",
217 strerror(-err), err);
218 }
219 return err;
220 }
221
222 // Release the previous buffer.
Mathias Agopianad678e12013-07-23 17:28:53 -0700223 err = updateAndReleaseLocked(item);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800224 if (err != NO_ERROR) {
225 // We always bind the texture.
226 glBindTexture(mTexTarget, mTexName);
227 return err;
228 }
229
Andy McFadden97eba892012-12-11 15:21:45 -0800230 // Bind the new buffer to the GL texture, and wait until it's ready.
231 return bindTextureImageLocked();
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700232}
233
Mathias Agopianad678e12013-07-23 17:28:53 -0700234
235status_t GLConsumer::releaseTexImage() {
236 ATRACE_CALL();
237 ST_LOGV("releaseTexImage");
238 Mutex::Autolock lock(mMutex);
239
240 if (mAbandoned) {
241 ST_LOGE("releaseTexImage: GLConsumer is abandoned!");
242 return NO_INIT;
243 }
244
245 // Make sure the EGL state is the same as in previous calls.
Mathias Agopian45155962013-08-08 18:16:21 -0700246 status_t err = NO_ERROR;
247
248 if (mAttached) {
249 err = checkAndUpdateEglStateLocked(true);
250 if (err != NO_ERROR) {
251 return err;
252 }
253 } else {
254 // if we're detached, no need to validate EGL's state -- we won't use it.
Mathias Agopianad678e12013-07-23 17:28:53 -0700255 }
256
257 // Update the GLConsumer state.
258 int buf = mCurrentTexture;
259 if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
260
Mathias Agopian45155962013-08-08 18:16:21 -0700261 ST_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached);
Mathias Agopianad678e12013-07-23 17:28:53 -0700262
Mathias Agopian45155962013-08-08 18:16:21 -0700263 if (mAttached) {
264 // Do whatever sync ops we need to do before releasing the slot.
265 err = syncForReleaseLocked(mEglDisplay);
266 if (err != NO_ERROR) {
267 ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
268 return err;
269 }
270 } else {
271 // if we're detached, we just use the fence that was created in detachFromContext()
272 // so... basically, nothing more to do here.
Mathias Agopianad678e12013-07-23 17:28:53 -0700273 }
274
Mathias Agopian45155962013-08-08 18:16:21 -0700275 err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
Mathias Agopianad678e12013-07-23 17:28:53 -0700276 if (err < NO_ERROR) {
277 ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)",
278 strerror(-err), err);
279 return err;
280 }
281
Mathias Agopianad678e12013-07-23 17:28:53 -0700282 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
Mathias Agopian9870c9b2013-08-08 17:46:48 -0700283 mCurrentTextureBuf = getDebugTexImageBuffer();
Mathias Agopianad678e12013-07-23 17:28:53 -0700284 mCurrentCrop.makeInvalid();
285 mCurrentTransform = 0;
286 mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
287 mCurrentTimestamp = 0;
288 mCurrentFence = Fence::NO_FENCE;
289
Mathias Agopian45155962013-08-08 18:16:21 -0700290 if (mAttached) {
291 // bind a dummy texture
292 glBindTexture(mTexTarget, mTexName);
293 bindUnslottedBufferLocked(mEglDisplay);
294 } else {
295 // detached, don't touch the texture (and we may not even have an
296 // EGLDisplay here.
297 }
Mathias Agopianad678e12013-07-23 17:28:53 -0700298 }
299
300 return NO_ERROR;
301}
302
Mathias Agopian9870c9b2013-08-08 17:46:48 -0700303sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
304 Mutex::Autolock _l(sStaticInitLock);
305 if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
306 // The first time, create the debug texture in case the application
307 // continues to use it.
308 sp<GraphicBuffer> buffer = new GraphicBuffer(
309 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
310 GraphicBuffer::USAGE_SW_WRITE_RARELY);
311 uint32_t* bits;
312 buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
313 size_t w = buffer->getStride();
314 size_t h = buffer->getHeight();
315 memset(bits, 0, w*h*4);
316 for (size_t y=0 ; y<kDebugData.height ; y++) {
317 for (size_t x=0 ; x<kDebugData.width ; x++) {
318 bits[x] = (kDebugData.bits[y*kDebugData.width+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF;
319 }
320 bits += w;
321 }
322 buffer->unlock();
323 sReleasedTexImageBuffer = buffer;
324 }
325 return sReleasedTexImageBuffer;
326}
327
Andy McFadden1585c4d2013-06-28 13:52:40 -0700328status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
329 nsecs_t presentWhen) {
330 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
Jamie Gennis9fea3422012-08-07 18:03:04 -0700331 if (err != NO_ERROR) {
332 return err;
333 }
334
335 int slot = item->mBuf;
Jamie Gennisdbe92452013-09-23 17:22:10 -0700336 bool destroyEglImage = false;
337
338 if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
339 if (item->mGraphicBuffer != NULL) {
340 // This buffer has not been acquired before, so we must assume
341 // that any EGLImage in mEglSlots is stale.
342 destroyEglImage = true;
343 } else if (mEglSlots[slot].mCropRect != item->mCrop) {
344 // We've already seen this buffer before, but it now has a
345 // different crop rect, so we'll need to recreate the EGLImage if
346 // we're using the EGL_ANDROID_image_crop extension.
347 destroyEglImage = hasEglAndroidImageCrop();
Jamie Gennis9fea3422012-08-07 18:03:04 -0700348 }
349 }
350
Jamie Gennisdbe92452013-09-23 17:22:10 -0700351 if (destroyEglImage) {
352 if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
353 ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
354 slot);
355 // keep going
356 }
357 mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
358 }
359
Jamie Gennis9fea3422012-08-07 18:03:04 -0700360 return NO_ERROR;
361}
362
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700363status_t GLConsumer::releaseBufferLocked(int buf,
364 sp<GraphicBuffer> graphicBuffer,
365 EGLDisplay display, EGLSyncKHR eglFence) {
366 // release the buffer if it hasn't already been discarded by the
367 // BufferQueue. This can happen, for example, when the producer of this
368 // buffer has reallocated the original buffer slot after this buffer
369 // was acquired.
370 status_t err = ConsumerBase::releaseBufferLocked(
371 buf, graphicBuffer, display, eglFence);
Jamie Gennisd1b330d2012-09-21 11:55:35 -0700372 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700373 return err;
374}
375
Mathias Agopianad678e12013-07-23 17:28:53 -0700376status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800377{
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700378 status_t err = NO_ERROR;
379
Andy McFadden87a67842014-04-04 15:37:08 -0700380 int buf = item.mBuf;
381
Jamie Gennis74bed552012-03-28 19:05:54 -0700382 if (!mAttached) {
Mathias Agopianad678e12013-07-23 17:28:53 -0700383 ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
Jamie Gennis74bed552012-03-28 19:05:54 -0700384 "ES context");
Andy McFadden87a67842014-04-04 15:37:08 -0700385 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
386 mEglDisplay, EGL_NO_SYNC_KHR);
Jamie Gennis74bed552012-03-28 19:05:54 -0700387 return INVALID_OPERATION;
388 }
389
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800390 // Confirm state.
391 err = checkAndUpdateEglStateLocked();
392 if (err != NO_ERROR) {
Andy McFadden87a67842014-04-04 15:37:08 -0700393 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
394 mEglDisplay, EGL_NO_SYNC_KHR);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800395 return err;
396 }
397
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800398 // If the mEglSlot entry is empty, create an EGLImage for the gralloc
399 // buffer currently in the slot in ConsumerBase.
400 //
401 // We may have to do this even when item.mGraphicBuffer == NULL (which
402 // means the buffer was previously acquired), if we destroyed the
403 // EGLImage when detaching from a context but the buffer has not been
404 // re-allocated.
405 if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
Jamie Gennisdbe92452013-09-23 17:22:10 -0700406 EGLImageKHR image = createImage(mEglDisplay,
407 mSlots[buf].mGraphicBuffer, item.mCrop);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800408 if (image == EGL_NO_IMAGE_KHR) {
Mathias Agopianad678e12013-07-23 17:28:53 -0700409 ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800410 mEglDisplay, buf);
Andy McFadden87a67842014-04-04 15:37:08 -0700411 const sp<GraphicBuffer>& gb = mSlots[buf].mGraphicBuffer;
412 ST_LOGW("buffer size=%ux%u st=%u usage=0x%x fmt=%d",
413 gb->getWidth(), gb->getHeight(), gb->getStride(),
414 gb->getUsage(), gb->getPixelFormat());
415 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
416 mEglDisplay, EGL_NO_SYNC_KHR);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800417 return UNKNOWN_ERROR;
418 }
419 mEglSlots[buf].mEglImage = image;
Jamie Gennisdbe92452013-09-23 17:22:10 -0700420 mEglSlots[buf].mCropRect = item.mCrop;
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800421 }
422
423 // Do whatever sync ops we need to do before releasing the old slot.
424 err = syncForReleaseLocked(mEglDisplay);
425 if (err != NO_ERROR) {
426 // Release the buffer we just acquired. It's not safe to
427 // release the old buffer, so instead we just drop the new frame.
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700428 // As we are still under lock since acquireBuffer, it is safe to
429 // release by slot.
430 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
431 mEglDisplay, EGL_NO_SYNC_KHR);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800432 return err;
433 }
434
Mathias Agopianad678e12013-07-23 17:28:53 -0700435 ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800436 mCurrentTexture,
437 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
438 buf, mSlots[buf].mGraphicBuffer->handle);
439
440 // release old buffer
441 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700442 status_t status = releaseBufferLocked(
443 mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800444 mEglSlots[mCurrentTexture].mEglFence);
Mathias Agopianad678e12013-07-23 17:28:53 -0700445 if (status < NO_ERROR) {
446 ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800447 strerror(-status), status);
448 err = status;
449 // keep going, with error raised [?]
450 }
451 }
452
Andy McFadden2adaf042012-12-18 09:49:45 -0800453 // Update the GLConsumer state.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800454 mCurrentTexture = buf;
455 mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
456 mCurrentCrop = item.mCrop;
457 mCurrentTransform = item.mTransform;
458 mCurrentScalingMode = item.mScalingMode;
459 mCurrentTimestamp = item.mTimestamp;
460 mCurrentFence = item.mFence;
Eino-Ville Talvalad171da92013-09-19 13:36:07 -0700461 mCurrentFrameNumber = item.mFrameNumber;
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800462
463 computeCurrentTransformMatrixLocked();
464
465 return err;
466}
467
Andy McFadden2adaf042012-12-18 09:49:45 -0800468status_t GLConsumer::bindTextureImageLocked() {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800469 if (mEglDisplay == EGL_NO_DISPLAY) {
470 ALOGE("bindTextureImage: invalid display");
471 return INVALID_OPERATION;
472 }
473
474 GLint error;
475 while ((error = glGetError()) != GL_NO_ERROR) {
476 ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
477 }
478
479 glBindTexture(mTexTarget, mTexName);
480 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
481 if (mCurrentTextureBuf == NULL) {
482 ST_LOGE("bindTextureImage: no currently-bound texture");
483 return NO_INIT;
484 }
Andy McFadden97eba892012-12-11 15:21:45 -0800485 status_t err = bindUnslottedBufferLocked(mEglDisplay);
486 if (err != NO_ERROR) {
487 return err;
488 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800489 } else {
490 EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
491
492 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
493
494 while ((error = glGetError()) != GL_NO_ERROR) {
495 ST_LOGE("bindTextureImage: error binding external texture image %p"
496 ": %#04x", image, error);
497 return UNKNOWN_ERROR;
498 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800499 }
Andy McFadden97eba892012-12-11 15:21:45 -0800500
501 // Wait for the new buffer to be ready.
502 return doGLFenceWaitLocked();
503
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800504}
505
Mathias Agopian45155962013-08-08 18:16:21 -0700506status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
Jamie Gennisce561372012-03-19 18:33:05 -0700507 EGLDisplay dpy = eglGetCurrentDisplay();
508 EGLContext ctx = eglGetCurrentContext();
509
Mathias Agopian45155962013-08-08 18:16:21 -0700510 if (!contextCheck) {
511 // if this is the first time we're called, mEglDisplay/mEglContext have
512 // never been set, so don't error out (below).
513 if (mEglDisplay == EGL_NO_DISPLAY) {
514 mEglDisplay = dpy;
515 }
516 if (mEglContext == EGL_NO_DISPLAY) {
517 mEglContext = ctx;
518 }
519 }
520
521 if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800522 ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
Jamie Gennis74bed552012-03-28 19:05:54 -0700523 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700524 }
525
Mathias Agopian45155962013-08-08 18:16:21 -0700526 if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800527 ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
Jamie Gennis74bed552012-03-28 19:05:54 -0700528 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700529 }
530
531 mEglDisplay = dpy;
532 mEglContext = ctx;
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800533 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800534}
535
Jesse Hall13f01cb2013-03-20 11:37:21 -0700536void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
537 if (fence->isValid() &&
538 mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700539 status_t err = addReleaseFence(mCurrentTexture,
540 mCurrentTextureBuf, fence);
Jesse Hall13f01cb2013-03-20 11:37:21 -0700541 if (err != OK) {
542 ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
543 strerror(-err), err);
544 }
Jesse Hallef194142012-06-14 14:45:17 -0700545 }
546}
547
Andy McFadden2adaf042012-12-18 09:49:45 -0800548status_t GLConsumer::detachFromContext() {
Jamie Gennis74bed552012-03-28 19:05:54 -0700549 ATRACE_CALL();
550 ST_LOGV("detachFromContext");
551 Mutex::Autolock lock(mMutex);
552
553 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800554 ST_LOGE("detachFromContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700555 return NO_INIT;
556 }
557
558 if (!mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800559 ST_LOGE("detachFromContext: GLConsumer is not attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700560 "context");
561 return INVALID_OPERATION;
562 }
563
564 EGLDisplay dpy = eglGetCurrentDisplay();
565 EGLContext ctx = eglGetCurrentContext();
566
567 if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
568 ST_LOGE("detachFromContext: invalid current EGLDisplay");
569 return INVALID_OPERATION;
570 }
571
572 if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
573 ST_LOGE("detachFromContext: invalid current EGLContext");
574 return INVALID_OPERATION;
575 }
576
577 if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
578 status_t err = syncForReleaseLocked(dpy);
579 if (err != OK) {
580 return err;
581 }
582
583 glDeleteTextures(1, &mTexName);
584 }
585
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700586 // Because we're giving up the EGLDisplay we need to free all the EGLImages
587 // that are associated with it. They'll be recreated when the
Andy McFadden2adaf042012-12-18 09:49:45 -0800588 // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700589 // new EGLDisplay).
590 for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700591 EGLImageKHR img = mEglSlots[i].mEglImage;
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700592 if (img != EGL_NO_IMAGE_KHR) {
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700593 eglDestroyImageKHR(mEglDisplay, img);
Jamie Gennis9fea3422012-08-07 18:03:04 -0700594 mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700595 }
596 }
597
Jamie Gennis74bed552012-03-28 19:05:54 -0700598 mEglDisplay = EGL_NO_DISPLAY;
599 mEglContext = EGL_NO_CONTEXT;
600 mAttached = false;
601
602 return OK;
603}
604
Mathias Agopian3f844832013-08-07 21:24:32 -0700605status_t GLConsumer::attachToContext(uint32_t tex) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700606 ATRACE_CALL();
607 ST_LOGV("attachToContext");
608 Mutex::Autolock lock(mMutex);
609
610 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800611 ST_LOGE("attachToContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700612 return NO_INIT;
613 }
614
615 if (mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800616 ST_LOGE("attachToContext: GLConsumer is already attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700617 "context");
618 return INVALID_OPERATION;
619 }
620
621 EGLDisplay dpy = eglGetCurrentDisplay();
622 EGLContext ctx = eglGetCurrentContext();
623
624 if (dpy == EGL_NO_DISPLAY) {
625 ST_LOGE("attachToContext: invalid current EGLDisplay");
626 return INVALID_OPERATION;
627 }
628
629 if (ctx == EGL_NO_CONTEXT) {
630 ST_LOGE("attachToContext: invalid current EGLContext");
631 return INVALID_OPERATION;
632 }
633
634 // We need to bind the texture regardless of whether there's a current
635 // buffer.
Mathias Agopian3f844832013-08-07 21:24:32 -0700636 glBindTexture(mTexTarget, GLuint(tex));
Jamie Gennis74bed552012-03-28 19:05:54 -0700637
638 if (mCurrentTextureBuf != NULL) {
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700639 // The EGLImageKHR that was associated with the slot was destroyed when
Andy McFadden2adaf042012-12-18 09:49:45 -0800640 // the GLConsumer was detached from the old context, so we need to
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700641 // recreate it here.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800642 status_t err = bindUnslottedBufferLocked(dpy);
643 if (err != NO_ERROR) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700644 return err;
645 }
646 }
647
648 mEglDisplay = dpy;
649 mEglContext = ctx;
650 mTexName = tex;
651 mAttached = true;
652
653 return OK;
654}
655
Andy McFadden2adaf042012-12-18 09:49:45 -0800656status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800657 ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
658 mCurrentTexture, mCurrentTextureBuf.get());
659
660 // Create a temporary EGLImageKHR.
Jamie Gennisdbe92452013-09-23 17:22:10 -0700661 Rect crop;
662 EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800663 if (image == EGL_NO_IMAGE_KHR) {
664 return UNKNOWN_ERROR;
665 }
666
667 // Attach the current buffer to the GL texture.
668 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
669
670 GLint error;
671 status_t err = OK;
672 while ((error = glGetError()) != GL_NO_ERROR) {
673 ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
674 "(slot %d): %#04x", image, mCurrentTexture, error);
675 err = UNKNOWN_ERROR;
676 }
677
678 // We destroy the EGLImageKHR here because the current buffer may no
679 // longer be associated with one of the buffer slots, so we have
680 // nowhere to to store it. If the buffer is still associated with a
681 // slot then another EGLImageKHR will be created next time that buffer
682 // gets acquired in updateTexImage.
683 eglDestroyImageKHR(dpy, image);
684
685 return err;
686}
687
688
Andy McFadden2adaf042012-12-18 09:49:45 -0800689status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700690 ST_LOGV("syncForReleaseLocked");
691
Jamie Gennis01dbf552012-09-06 14:54:19 -0700692 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Mathias Agopianca088332013-03-28 17:44:13 -0700693 if (SyncFeatures::getInstance().useNativeFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700694 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
695 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
696 if (sync == EGL_NO_SYNC_KHR) {
697 ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
698 eglGetError());
Jamie Gennis74bed552012-03-28 19:05:54 -0700699 return UNKNOWN_ERROR;
Jamie Gennis74bed552012-03-28 19:05:54 -0700700 }
Jamie Gennis01dbf552012-09-06 14:54:19 -0700701 glFlush();
702 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
Jamie Gennis98ff0592012-09-10 14:49:42 -0700703 eglDestroySyncKHR(dpy, sync);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700704 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
705 ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
706 "fd: %#x", eglGetError());
707 return UNKNOWN_ERROR;
708 }
709 sp<Fence> fence(new Fence(fenceFd));
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700710 status_t err = addReleaseFenceLocked(mCurrentTexture,
711 mCurrentTextureBuf, fence);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700712 if (err != OK) {
713 ST_LOGE("syncForReleaseLocked: error adding release fence: "
714 "%s (%d)", strerror(-err), err);
715 return err;
716 }
Mathias Agopianca088332013-03-28 17:44:13 -0700717 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700718 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
719 if (fence != EGL_NO_SYNC_KHR) {
720 // There is already a fence for the current slot. We need to
721 // wait on that before replacing it with another fence to
722 // ensure that all outstanding buffer accesses have completed
723 // before the producer accesses it.
724 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
725 if (result == EGL_FALSE) {
726 ST_LOGE("syncForReleaseLocked: error waiting for previous "
727 "fence: %#x", eglGetError());
728 return UNKNOWN_ERROR;
729 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
730 ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
731 "fence");
732 return TIMED_OUT;
733 }
734 eglDestroySyncKHR(dpy, fence);
735 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700736
Jamie Gennis01dbf552012-09-06 14:54:19 -0700737 // Create a fence for the outstanding accesses in the current
738 // OpenGL ES context.
739 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
740 if (fence == EGL_NO_SYNC_KHR) {
741 ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
742 eglGetError());
743 return UNKNOWN_ERROR;
744 }
745 glFlush();
746 mEglSlots[mCurrentTexture].mEglFence = fence;
Jamie Gennis74bed552012-03-28 19:05:54 -0700747 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700748 }
749
750 return OK;
751}
752
Andy McFadden2adaf042012-12-18 09:49:45 -0800753bool GLConsumer::isExternalFormat(uint32_t format)
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700754{
755 switch (format) {
756 // supported YUV formats
757 case HAL_PIXEL_FORMAT_YV12:
758 // Legacy/deprecated YUV formats
759 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
760 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
761 case HAL_PIXEL_FORMAT_YCbCr_422_I:
762 return true;
763 }
764
765 // Any OEM format needs to be considered
766 if (format>=0x100 && format<=0x1FF)
767 return true;
768
769 return false;
770}
771
Mathias Agopian3f844832013-08-07 21:24:32 -0700772uint32_t GLConsumer::getCurrentTextureTarget() const {
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700773 return mTexTarget;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700774}
775
Andy McFadden2adaf042012-12-18 09:49:45 -0800776void GLConsumer::getTransformMatrix(float mtx[16]) {
Jamie Gennisf238e282011-01-09 16:33:17 -0800777 Mutex::Autolock lock(mMutex);
Jamie Gennis736aa952011-06-12 17:03:06 -0700778 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
779}
780
Andy McFadden2adaf042012-12-18 09:49:45 -0800781void GLConsumer::setFilteringEnabled(bool enabled) {
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700782 Mutex::Autolock lock(mMutex);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700783 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800784 ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700785 return;
786 }
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700787 bool needsRecompute = mFilteringEnabled != enabled;
788 mFilteringEnabled = enabled;
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700789
790 if (needsRecompute && mCurrentTextureBuf==NULL) {
791 ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
792 }
793
794 if (needsRecompute && mCurrentTextureBuf != NULL) {
795 computeCurrentTransformMatrixLocked();
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700796 }
797}
798
Andy McFadden2adaf042012-12-18 09:49:45 -0800799void GLConsumer::computeCurrentTransformMatrixLocked() {
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700800 ST_LOGV("computeCurrentTransformMatrixLocked");
Jamie Gennisf238e282011-01-09 16:33:17 -0800801
Jamie Gennisa214c642011-01-14 13:53:31 -0800802 float xform[16];
803 for (int i = 0; i < 16; i++) {
804 xform[i] = mtxIdentity[i];
805 }
806 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
807 float result[16];
808 mtxMul(result, xform, mtxFlipH);
809 for (int i = 0; i < 16; i++) {
810 xform[i] = result[i];
811 }
812 }
813 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
814 float result[16];
815 mtxMul(result, xform, mtxFlipV);
816 for (int i = 0; i < 16; i++) {
817 xform[i] = result[i];
818 }
819 }
820 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
821 float result[16];
822 mtxMul(result, xform, mtxRot90);
823 for (int i = 0; i < 16; i++) {
824 xform[i] = result[i];
825 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800826 }
827
Daniel Lameae59d22012-01-22 15:26:27 -0800828 sp<GraphicBuffer>& buf(mCurrentTextureBuf);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700829
830 if (buf == NULL) {
831 ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
832 }
833
Jamie Gennisdbe92452013-09-23 17:22:10 -0700834 float mtxBeforeFlipV[16];
835 if (!isEglImageCroppable(mCurrentCrop)) {
836 Rect cropRect = mCurrentCrop;
837 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
838 float bufferWidth = buf->getWidth();
839 float bufferHeight = buf->getHeight();
840 if (!cropRect.isEmpty()) {
841 float shrinkAmount = 0.0f;
842 if (mFilteringEnabled) {
843 // In order to prevent bilinear sampling beyond the edge of the
844 // crop rectangle we may need to shrink it by 2 texels in each
845 // dimension. Normally this would just need to take 1/2 a texel
846 // off each end, but because the chroma channels of YUV420 images
847 // are subsampled we may need to shrink the crop region by a whole
848 // texel on each side.
849 switch (buf->getPixelFormat()) {
850 case PIXEL_FORMAT_RGBA_8888:
851 case PIXEL_FORMAT_RGBX_8888:
852 case PIXEL_FORMAT_RGB_888:
853 case PIXEL_FORMAT_RGB_565:
854 case PIXEL_FORMAT_BGRA_8888:
855 // We know there's no subsampling of any channels, so we
856 // only need to shrink by a half a pixel.
857 shrinkAmount = 0.5;
858 break;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700859
Jamie Gennisdbe92452013-09-23 17:22:10 -0700860 default:
861 // If we don't recognize the format, we must assume the
862 // worst case (that we care about), which is YUV420.
863 shrinkAmount = 1.0;
864 break;
865 }
866 }
867
868 // Only shrink the dimensions that are not the size of the buffer.
869 if (cropRect.width() < bufferWidth) {
870 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
871 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
872 bufferWidth;
873 }
874 if (cropRect.height() < bufferHeight) {
875 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
876 bufferHeight;
877 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
878 bufferHeight;
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700879 }
880 }
Jamie Gennisdbe92452013-09-23 17:22:10 -0700881 float crop[16] = {
882 sx, 0, 0, 0,
883 0, sy, 0, 0,
884 0, 0, 1, 0,
885 tx, ty, 0, 1,
886 };
Jamie Gennisd72f2332012-05-07 13:50:11 -0700887
Jamie Gennisdbe92452013-09-23 17:22:10 -0700888 mtxMul(mtxBeforeFlipV, crop, xform);
889 } else {
890 for (int i = 0; i < 16; i++) {
891 mtxBeforeFlipV[i] = xform[i];
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700892 }
Jamie Gennisa214c642011-01-14 13:53:31 -0800893 }
Jamie Gennisa214c642011-01-14 13:53:31 -0800894
895 // SurfaceFlinger expects the top of its window textures to be at a Y
Andy McFadden2adaf042012-12-18 09:49:45 -0800896 // coordinate of 0, so GLConsumer must behave the same way. We don't
Jamie Gennisa214c642011-01-14 13:53:31 -0800897 // want to expose this to applications, however, so we must add an
898 // additional vertical flip to the transform after all the other transforms.
Jamie Gennis736aa952011-06-12 17:03:06 -0700899 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
Jamie Gennisf238e282011-01-09 16:33:17 -0800900}
901
Andy McFadden2adaf042012-12-18 09:49:45 -0800902nsecs_t GLConsumer::getTimestamp() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700903 ST_LOGV("getTimestamp");
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800904 Mutex::Autolock lock(mMutex);
905 return mCurrentTimestamp;
906}
907
Eino-Ville Talvalad171da92013-09-19 13:36:07 -0700908nsecs_t GLConsumer::getFrameNumber() {
909 ST_LOGV("getFrameNumber");
910 Mutex::Autolock lock(mMutex);
911 return mCurrentFrameNumber;
912}
913
Andy McFadden2adaf042012-12-18 09:49:45 -0800914EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
Jamie Gennisdbe92452013-09-23 17:22:10 -0700915 const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800916 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
917 EGLint attrs[] = {
Jamie Gennisdbe92452013-09-23 17:22:10 -0700918 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
919 EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
920 EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
921 EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
922 EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800923 EGL_NONE,
924 };
Jamie Gennisdbe92452013-09-23 17:22:10 -0700925 if (!crop.isValid()) {
926 // No crop rect to set, so terminate the attrib array before the crop.
927 attrs[2] = EGL_NONE;
928 } else if (!isEglImageCroppable(crop)) {
929 // The crop rect is not at the origin, so we can't set the crop on the
930 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
931 // extension. In the future we can add a layered extension that
932 // removes this restriction if there is hardware that can support it.
933 attrs[2] = EGL_NONE;
934 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800935 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
936 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700937 if (image == EGL_NO_IMAGE_KHR) {
938 EGLint error = eglGetError();
Jamie Gennisfa28c352011-09-16 17:30:26 -0700939 ST_LOGE("error creating EGLImage: %#x", error);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800940 }
941 return image;
942}
943
Andy McFadden2adaf042012-12-18 09:49:45 -0800944sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700945 Mutex::Autolock lock(mMutex);
946 return mCurrentTextureBuf;
947}
948
Andy McFadden2adaf042012-12-18 09:49:45 -0800949Rect GLConsumer::getCurrentCrop() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700950 Mutex::Autolock lock(mMutex);
Daniel Lam016c8cb2012-04-03 15:54:58 -0700951
952 Rect outCrop = mCurrentCrop;
953 if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
954 int32_t newWidth = mCurrentCrop.width();
955 int32_t newHeight = mCurrentCrop.height();
956
957 if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
958 newWidth = newHeight * mDefaultWidth / mDefaultHeight;
959 ST_LOGV("too wide: newWidth = %d", newWidth);
960 } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
961 newHeight = newWidth * mDefaultHeight / mDefaultWidth;
962 ST_LOGV("too tall: newHeight = %d", newHeight);
963 }
964
965 // The crop is too wide
966 if (newWidth < mCurrentCrop.width()) {
967 int32_t dw = (newWidth - mCurrentCrop.width())/2;
968 outCrop.left -=dw;
969 outCrop.right += dw;
970 // The crop is too tall
971 } else if (newHeight < mCurrentCrop.height()) {
972 int32_t dh = (newHeight - mCurrentCrop.height())/2;
973 outCrop.top -= dh;
974 outCrop.bottom += dh;
975 }
976
977 ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
978 outCrop.left, outCrop.top,
979 outCrop.right,outCrop.bottom);
980 }
981
Daniel Lam016c8cb2012-04-03 15:54:58 -0700982 return outCrop;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700983}
984
Andy McFadden2adaf042012-12-18 09:49:45 -0800985uint32_t GLConsumer::getCurrentTransform() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700986 Mutex::Autolock lock(mMutex);
987 return mCurrentTransform;
988}
989
Andy McFadden2adaf042012-12-18 09:49:45 -0800990uint32_t GLConsumer::getCurrentScalingMode() const {
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700991 Mutex::Autolock lock(mMutex);
992 return mCurrentScalingMode;
993}
994
Andy McFadden2adaf042012-12-18 09:49:45 -0800995sp<Fence> GLConsumer::getCurrentFence() const {
Jesse Halldc5b4852012-06-29 15:21:18 -0700996 Mutex::Autolock lock(mMutex);
997 return mCurrentFence;
998}
999
Andy McFadden2adaf042012-12-18 09:49:45 -08001000status_t GLConsumer::doGLFenceWait() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -07001001 Mutex::Autolock lock(mMutex);
Jamie Gennis3941cb22012-09-17 16:58:17 -07001002 return doGLFenceWaitLocked();
1003}
1004
Andy McFadden2adaf042012-12-18 09:49:45 -08001005status_t GLConsumer::doGLFenceWaitLocked() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -07001006
1007 EGLDisplay dpy = eglGetCurrentDisplay();
1008 EGLContext ctx = eglGetCurrentContext();
1009
1010 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
1011 ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
1012 return INVALID_OPERATION;
1013 }
1014
1015 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
1016 ST_LOGE("doGLFenceWait: invalid current EGLContext");
1017 return INVALID_OPERATION;
1018 }
1019
Jamie Gennis1df8c342012-12-20 14:05:45 -08001020 if (mCurrentFence->isValid()) {
Mathias Agopianca088332013-03-28 17:44:13 -07001021 if (SyncFeatures::getInstance().useWaitSync()) {
Jamie Gennis61e04b92012-09-09 17:48:42 -07001022 // Create an EGLSyncKHR from the current fence.
1023 int fenceFd = mCurrentFence->dup();
1024 if (fenceFd == -1) {
1025 ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
1026 return -errno;
1027 }
1028 EGLint attribs[] = {
1029 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
1030 EGL_NONE
1031 };
1032 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
1033 EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
1034 if (sync == EGL_NO_SYNC_KHR) {
1035 close(fenceFd);
1036 ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
1037 eglGetError());
1038 return UNKNOWN_ERROR;
1039 }
1040
1041 // XXX: The spec draft is inconsistent as to whether this should
1042 // return an EGLint or void. Ignore the return value for now, as
1043 // it's not strictly needed.
Mathias Agopian2bb71682013-03-27 17:32:41 -07001044 eglWaitSyncKHR(dpy, sync, 0);
Jamie Gennis61e04b92012-09-09 17:48:42 -07001045 EGLint eglErr = eglGetError();
1046 eglDestroySyncKHR(dpy, sync);
1047 if (eglErr != EGL_SUCCESS) {
1048 ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
1049 eglErr);
1050 return UNKNOWN_ERROR;
1051 }
1052 } else {
Mathias Agopianea74d3b2013-05-16 18:03:22 -07001053 status_t err = mCurrentFence->waitForever(
Andy McFadden2adaf042012-12-18 09:49:45 -08001054 "GLConsumer::doGLFenceWaitLocked");
Jamie Gennis61e04b92012-09-09 17:48:42 -07001055 if (err != NO_ERROR) {
1056 ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
1057 return err;
1058 }
1059 }
1060 }
1061
1062 return NO_ERROR;
1063}
1064
Andy McFadden2adaf042012-12-18 09:49:45 -08001065void GLConsumer::freeBufferLocked(int slotIndex) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001066 ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
Daniel Lam9abe1eb2012-03-26 20:37:15 -07001067 if (slotIndex == mCurrentTexture) {
1068 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
1069 }
Jamie Gennis9fea3422012-08-07 18:03:04 -07001070 EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
Jamie Gennis9aa74db2012-04-17 13:07:45 -07001071 if (img != EGL_NO_IMAGE_KHR) {
1072 ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
1073 eglDestroyImageKHR(mEglDisplay, img);
Daniel Lameae59d22012-01-22 15:26:27 -08001074 }
Jamie Gennis9fea3422012-08-07 18:03:04 -07001075 mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
1076 ConsumerBase::freeBufferLocked(slotIndex);
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001077}
Daniel Lameae59d22012-01-22 15:26:27 -08001078
Andy McFadden2adaf042012-12-18 09:49:45 -08001079void GLConsumer::abandonLocked() {
Jamie Gennis9fea3422012-08-07 18:03:04 -07001080 ST_LOGV("abandonLocked");
1081 mCurrentTextureBuf.clear();
1082 ConsumerBase::abandonLocked();
Jamie Gennis7b305ff2011-07-19 12:08:33 -07001083}
1084
Andy McFadden2adaf042012-12-18 09:49:45 -08001085void GLConsumer::setName(const String8& name) {
Daniel Lameae59d22012-01-22 15:26:27 -08001086 Mutex::Autolock _l(mMutex);
Jamie Gennisfa28c352011-09-16 17:30:26 -07001087 mName = name;
Mathias Agopiandb89edc2013-08-02 01:40:18 -07001088 mConsumer->setConsumerName(name);
Daniel Lamb2675792012-02-23 14:35:13 -08001089}
1090
Andy McFadden2adaf042012-12-18 09:49:45 -08001091status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
Daniel Lamb2675792012-02-23 14:35:13 -08001092 Mutex::Autolock lock(mMutex);
Mathias Agopiandb89edc2013-08-02 01:40:18 -07001093 return mConsumer->setDefaultBufferFormat(defaultFormat);
Daniel Lamb2675792012-02-23 14:35:13 -08001094}
1095
Andy McFadden2adaf042012-12-18 09:49:45 -08001096status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
Daniel Lamb2675792012-02-23 14:35:13 -08001097 Mutex::Autolock lock(mMutex);
Eino-Ville Talvala85b21762012-04-13 15:16:31 -07001098 usage |= DEFAULT_USAGE_FLAGS;
Mathias Agopiandb89edc2013-08-02 01:40:18 -07001099 return mConsumer->setConsumerUsageBits(usage);
Daniel Lamb2675792012-02-23 14:35:13 -08001100}
1101
Andy McFadden2adaf042012-12-18 09:49:45 -08001102status_t GLConsumer::setTransformHint(uint32_t hint) {
Daniel Lamb2675792012-02-23 14:35:13 -08001103 Mutex::Autolock lock(mMutex);
Mathias Agopiandb89edc2013-08-02 01:40:18 -07001104 return mConsumer->setTransformHint(hint);
Daniel Lamb2675792012-02-23 14:35:13 -08001105}
1106
Mathias Agopian74d211a2013-04-22 16:55:35 +02001107void GLConsumer::dumpLocked(String8& result, const char* prefix) const
Mathias Agopian68c77942011-05-09 19:08:33 -07001108{
Mathias Agopian74d211a2013-04-22 16:55:35 +02001109 result.appendFormat(
Jamie Gennis9fea3422012-08-07 18:03:04 -07001110 "%smTexName=%d mCurrentTexture=%d\n"
1111 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
1112 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
1113 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
1114 mCurrentTransform);
Mathias Agopian68c77942011-05-09 19:08:33 -07001115
Mathias Agopian74d211a2013-04-22 16:55:35 +02001116 ConsumerBase::dumpLocked(result, prefix);
Mathias Agopian68c77942011-05-09 19:08:33 -07001117}
1118
Jamie Gennisf238e282011-01-09 16:33:17 -08001119static void mtxMul(float out[16], const float a[16], const float b[16]) {
1120 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
1121 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
1122 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
1123 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
1124
1125 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
1126 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
1127 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
1128 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
1129
1130 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
1131 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
1132 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
1133 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
1134
1135 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
1136 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
1137 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
1138 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
1139}
1140
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001141}; // namespace android