blob: 92f07eb57c4f782ba4f672c287355c2b3bab6848 [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>
28
Jamie Gennis9fea3422012-08-07 18:03:04 -070029#include <hardware/hardware.h>
30
Mathias Agopianca088332013-03-28 17:44:13 -070031#include <gui/GLConsumer.h>
Mathias Agopian90ac7992012-02-25 18:48:35 -080032#include <gui/IGraphicBufferAlloc.h>
33#include <gui/ISurfaceComposer.h>
34#include <gui/SurfaceComposerClient.h>
Mathias Agopian41f673c2011-11-17 17:48:35 -080035
Mathias Agopian90ac7992012-02-25 18:48:35 -080036#include <private/gui/ComposerService.h>
Mathias Agopianca088332013-03-28 17:44:13 -070037#include <private/gui/SyncFeatures.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080038
39#include <utils/Log.h>
Mathias Agopian68c77942011-05-09 19:08:33 -070040#include <utils/String8.h>
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080041#include <utils/Trace.h>
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080042
Andy McFadden97eba892012-12-11 15:21:45 -080043namespace android {
44
Andy McFadden2adaf042012-12-18 09:49:45 -080045// Macros for including the GLConsumer name in log messages
Steve Block6807e592011-10-20 11:56:00 +010046#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Block9d453682011-12-20 16:23:08 +000047#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Blocka19954a2012-01-04 20:05:49 +000048#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Block32397c12012-01-05 23:22:43 +000049#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
Steve Blocke6f43dd2012-01-06 19:20:56 +000050#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
Mathias Agopian29b57622011-08-17 15:42:04 -070051
Jamie Gennisf238e282011-01-09 16:33:17 -080052// Transform matrices
53static float mtxIdentity[16] = {
54 1, 0, 0, 0,
55 0, 1, 0, 0,
56 0, 0, 1, 0,
57 0, 0, 0, 1,
58};
59static float mtxFlipH[16] = {
60 -1, 0, 0, 0,
61 0, 1, 0, 0,
62 0, 0, 1, 0,
63 1, 0, 0, 1,
64};
65static float mtxFlipV[16] = {
66 1, 0, 0, 0,
67 0, -1, 0, 0,
68 0, 0, 1, 0,
69 0, 1, 0, 1,
70};
71static float mtxRot90[16] = {
72 0, 1, 0, 0,
73 -1, 0, 0, 0,
74 0, 0, 1, 0,
75 1, 0, 0, 1,
76};
Jamie Gennisf238e282011-01-09 16:33:17 -080077
78static void mtxMul(float out[16], const float a[16], const float b[16]);
79
Jamie Gennisfa28c352011-09-16 17:30:26 -070080
Mathias Agopian8f938a52013-07-12 22:06:26 -070081GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex,
Mathias Agopian595264f2013-07-16 22:56:09 -070082 GLenum texTarget, bool useFenceSync, bool isControlledByApp) :
83 ConsumerBase(bq, isControlledByApp),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -080084 mCurrentTransform(0),
Mathias Agopiane692ab92013-04-22 11:24:02 +020085 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
Jamie Gennis1df8c342012-12-20 14:05:45 -080086 mCurrentFence(Fence::NO_FENCE),
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -080087 mCurrentTimestamp(0),
Mathias Agopiane692ab92013-04-22 11:24:02 +020088 mDefaultWidth(1),
89 mDefaultHeight(1),
Jamie Gennis5c1139f2012-05-08 16:56:34 -070090 mFilteringEnabled(true),
Mathias Agopianb3e518c2011-04-21 18:52:51 -070091 mTexName(tex),
Jamie Gennis86edf4f2011-11-14 14:51:01 -080092 mUseFenceSync(useFenceSync),
Daniel Lameae59d22012-01-22 15:26:27 -080093 mTexTarget(texTarget),
Jamie Gennisce561372012-03-19 18:33:05 -070094 mEglDisplay(EGL_NO_DISPLAY),
95 mEglContext(EGL_NO_CONTEXT),
Jamie Gennis74bed552012-03-28 19:05:54 -070096 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
97 mAttached(true)
Daniel Lam6b091c52012-01-22 15:26:27 -080098{
Andy McFadden2adaf042012-12-18 09:49:45 -080099 ST_LOGV("GLConsumer");
Daniel Lamb2675792012-02-23 14:35:13 -0800100
Jamie Gennisfa28c352011-09-16 17:30:26 -0700101 memcpy(mCurrentTransformMatrix, mtxIdentity,
102 sizeof(mCurrentTransformMatrix));
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700103
Jamie Gennis9fea3422012-08-07 18:03:04 -0700104 mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800105}
106
Andy McFadden2adaf042012-12-18 09:49:45 -0800107status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
Mathias Agopian80727112011-05-02 19:51:12 -0700108 Mutex::Autolock lock(mMutex);
Jamie Gennis31a353d2012-08-24 17:25:13 -0700109 return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
Mathias Agopian80727112011-05-02 19:51:12 -0700110}
111
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800112
Andy McFadden2adaf042012-12-18 09:49:45 -0800113status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700114{
Daniel Lamb2675792012-02-23 14:35:13 -0800115 Mutex::Autolock lock(mMutex);
Daniel Lam016c8cb2012-04-03 15:54:58 -0700116 mDefaultWidth = w;
117 mDefaultHeight = h;
Daniel Lamb2675792012-02-23 14:35:13 -0800118 return mBufferQueue->setDefaultBufferSize(w, h);
Mathias Agopiana5c75c02011-03-31 19:10:24 -0700119}
120
Andy McFadden2adaf042012-12-18 09:49:45 -0800121status_t GLConsumer::updateTexImage() {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800122 ATRACE_CALL();
123 ST_LOGV("updateTexImage");
124 Mutex::Autolock lock(mMutex);
125
126 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800127 ST_LOGE("updateTexImage: GLConsumer is abandoned!");
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800128 return NO_INIT;
129 }
130
131 // Make sure the EGL state is the same as in previous calls.
132 status_t err = checkAndUpdateEglStateLocked();
133 if (err != NO_ERROR) {
134 return err;
135 }
136
137 BufferQueue::BufferItem item;
138
139 // Acquire the next buffer.
140 // In asynchronous mode the list is guaranteed to be one buffer
141 // deep, while in synchronous mode we use the oldest buffer.
Andy McFadden1585c4d2013-06-28 13:52:40 -0700142 err = acquireBufferLocked(&item, 0);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800143 if (err != NO_ERROR) {
144 if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
145 // We always bind the texture even if we don't update its contents.
146 ST_LOGV("updateTexImage: no buffers were available");
147 glBindTexture(mTexTarget, mTexName);
148 err = NO_ERROR;
149 } else {
150 ST_LOGE("updateTexImage: acquire failed: %s (%d)",
151 strerror(-err), err);
152 }
153 return err;
154 }
155
156 // Release the previous buffer.
157 err = releaseAndUpdateLocked(item);
158 if (err != NO_ERROR) {
159 // We always bind the texture.
160 glBindTexture(mTexTarget, mTexName);
161 return err;
162 }
163
Andy McFadden97eba892012-12-11 15:21:45 -0800164 // Bind the new buffer to the GL texture, and wait until it's ready.
165 return bindTextureImageLocked();
Mathias Agopian2c8207e2012-05-23 17:56:42 -0700166}
167
Andy McFadden1585c4d2013-06-28 13:52:40 -0700168status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
169 nsecs_t presentWhen) {
170 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
Jamie Gennis9fea3422012-08-07 18:03:04 -0700171 if (err != NO_ERROR) {
172 return err;
173 }
174
175 int slot = item->mBuf;
176 if (item->mGraphicBuffer != NULL) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800177 // This buffer has not been acquired before, so we must assume
178 // that any EGLImage in mEglSlots is stale.
Jamie Gennis9fea3422012-08-07 18:03:04 -0700179 if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800180 if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
181 ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
182 slot);
183 // keep going
184 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700185 mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
186 }
187 }
188
Jamie Gennis9fea3422012-08-07 18:03:04 -0700189 return NO_ERROR;
190}
191
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700192status_t GLConsumer::releaseBufferLocked(int buf,
193 sp<GraphicBuffer> graphicBuffer,
194 EGLDisplay display, EGLSyncKHR eglFence) {
195 // release the buffer if it hasn't already been discarded by the
196 // BufferQueue. This can happen, for example, when the producer of this
197 // buffer has reallocated the original buffer slot after this buffer
198 // was acquired.
199 status_t err = ConsumerBase::releaseBufferLocked(
200 buf, graphicBuffer, display, eglFence);
Jamie Gennisd1b330d2012-09-21 11:55:35 -0700201 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700202 return err;
203}
204
Andy McFadden2adaf042012-12-18 09:49:45 -0800205status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800206{
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700207 status_t err = NO_ERROR;
208
Jamie Gennis74bed552012-03-28 19:05:54 -0700209 if (!mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800210 ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL "
Jamie Gennis74bed552012-03-28 19:05:54 -0700211 "ES context");
212 return INVALID_OPERATION;
213 }
214
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800215 // Confirm state.
216 err = checkAndUpdateEglStateLocked();
217 if (err != NO_ERROR) {
218 return err;
219 }
220
221 int buf = item.mBuf;
222
223 // If the mEglSlot entry is empty, create an EGLImage for the gralloc
224 // buffer currently in the slot in ConsumerBase.
225 //
226 // We may have to do this even when item.mGraphicBuffer == NULL (which
227 // means the buffer was previously acquired), if we destroyed the
228 // EGLImage when detaching from a context but the buffer has not been
229 // re-allocated.
230 if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
231 EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
232 if (image == EGL_NO_IMAGE_KHR) {
233 ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d",
234 mEglDisplay, buf);
235 return UNKNOWN_ERROR;
236 }
237 mEglSlots[buf].mEglImage = image;
238 }
239
240 // Do whatever sync ops we need to do before releasing the old slot.
241 err = syncForReleaseLocked(mEglDisplay);
242 if (err != NO_ERROR) {
243 // Release the buffer we just acquired. It's not safe to
244 // release the old buffer, so instead we just drop the new frame.
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700245 // As we are still under lock since acquireBuffer, it is safe to
246 // release by slot.
247 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
248 mEglDisplay, EGL_NO_SYNC_KHR);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800249 return err;
250 }
251
252 ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)",
253 mCurrentTexture,
254 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
255 buf, mSlots[buf].mGraphicBuffer->handle);
256
257 // release old buffer
258 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700259 status_t status = releaseBufferLocked(
260 mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800261 mEglSlots[mCurrentTexture].mEglFence);
262 if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
263 ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)",
264 strerror(-status), status);
265 err = status;
266 // keep going, with error raised [?]
267 }
268 }
269
Andy McFadden2adaf042012-12-18 09:49:45 -0800270 // Update the GLConsumer state.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800271 mCurrentTexture = buf;
272 mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
273 mCurrentCrop = item.mCrop;
274 mCurrentTransform = item.mTransform;
275 mCurrentScalingMode = item.mScalingMode;
276 mCurrentTimestamp = item.mTimestamp;
277 mCurrentFence = item.mFence;
278
279 computeCurrentTransformMatrixLocked();
280
281 return err;
282}
283
Andy McFadden2adaf042012-12-18 09:49:45 -0800284status_t GLConsumer::bindTextureImageLocked() {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800285 if (mEglDisplay == EGL_NO_DISPLAY) {
286 ALOGE("bindTextureImage: invalid display");
287 return INVALID_OPERATION;
288 }
289
290 GLint error;
291 while ((error = glGetError()) != GL_NO_ERROR) {
292 ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
293 }
294
295 glBindTexture(mTexTarget, mTexName);
296 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
297 if (mCurrentTextureBuf == NULL) {
298 ST_LOGE("bindTextureImage: no currently-bound texture");
299 return NO_INIT;
300 }
Andy McFadden97eba892012-12-11 15:21:45 -0800301 status_t err = bindUnslottedBufferLocked(mEglDisplay);
302 if (err != NO_ERROR) {
303 return err;
304 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800305 } else {
306 EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
307
308 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
309
310 while ((error = glGetError()) != GL_NO_ERROR) {
311 ST_LOGE("bindTextureImage: error binding external texture image %p"
312 ": %#04x", image, error);
313 return UNKNOWN_ERROR;
314 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800315 }
Andy McFadden97eba892012-12-11 15:21:45 -0800316
317 // Wait for the new buffer to be ready.
318 return doGLFenceWaitLocked();
319
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800320}
321
Andy McFadden2adaf042012-12-18 09:49:45 -0800322status_t GLConsumer::checkAndUpdateEglStateLocked() {
Jamie Gennisce561372012-03-19 18:33:05 -0700323 EGLDisplay dpy = eglGetCurrentDisplay();
324 EGLContext ctx = eglGetCurrentContext();
325
Jamie Gennis74bed552012-03-28 19:05:54 -0700326 if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
327 dpy == EGL_NO_DISPLAY) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800328 ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
Jamie Gennis74bed552012-03-28 19:05:54 -0700329 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700330 }
331
Jamie Gennis74bed552012-03-28 19:05:54 -0700332 if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
333 ctx == EGL_NO_CONTEXT) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800334 ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
Jamie Gennis74bed552012-03-28 19:05:54 -0700335 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700336 }
337
338 mEglDisplay = dpy;
339 mEglContext = ctx;
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800340 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800341}
342
Jesse Hall13f01cb2013-03-20 11:37:21 -0700343void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
344 if (fence->isValid() &&
345 mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700346 status_t err = addReleaseFence(mCurrentTexture,
347 mCurrentTextureBuf, fence);
Jesse Hall13f01cb2013-03-20 11:37:21 -0700348 if (err != OK) {
349 ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
350 strerror(-err), err);
351 }
Jesse Hallef194142012-06-14 14:45:17 -0700352 }
353}
354
Andy McFadden2adaf042012-12-18 09:49:45 -0800355status_t GLConsumer::detachFromContext() {
Jamie Gennis74bed552012-03-28 19:05:54 -0700356 ATRACE_CALL();
357 ST_LOGV("detachFromContext");
358 Mutex::Autolock lock(mMutex);
359
360 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800361 ST_LOGE("detachFromContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700362 return NO_INIT;
363 }
364
365 if (!mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800366 ST_LOGE("detachFromContext: GLConsumer is not attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700367 "context");
368 return INVALID_OPERATION;
369 }
370
371 EGLDisplay dpy = eglGetCurrentDisplay();
372 EGLContext ctx = eglGetCurrentContext();
373
374 if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
375 ST_LOGE("detachFromContext: invalid current EGLDisplay");
376 return INVALID_OPERATION;
377 }
378
379 if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
380 ST_LOGE("detachFromContext: invalid current EGLContext");
381 return INVALID_OPERATION;
382 }
383
384 if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
385 status_t err = syncForReleaseLocked(dpy);
386 if (err != OK) {
387 return err;
388 }
389
390 glDeleteTextures(1, &mTexName);
391 }
392
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700393 // Because we're giving up the EGLDisplay we need to free all the EGLImages
394 // that are associated with it. They'll be recreated when the
Andy McFadden2adaf042012-12-18 09:49:45 -0800395 // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700396 // new EGLDisplay).
397 for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700398 EGLImageKHR img = mEglSlots[i].mEglImage;
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700399 if (img != EGL_NO_IMAGE_KHR) {
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700400 eglDestroyImageKHR(mEglDisplay, img);
Jamie Gennis9fea3422012-08-07 18:03:04 -0700401 mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700402 }
403 }
404
Jamie Gennis74bed552012-03-28 19:05:54 -0700405 mEglDisplay = EGL_NO_DISPLAY;
406 mEglContext = EGL_NO_CONTEXT;
407 mAttached = false;
408
409 return OK;
410}
411
Andy McFadden2adaf042012-12-18 09:49:45 -0800412status_t GLConsumer::attachToContext(GLuint tex) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700413 ATRACE_CALL();
414 ST_LOGV("attachToContext");
415 Mutex::Autolock lock(mMutex);
416
417 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800418 ST_LOGE("attachToContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700419 return NO_INIT;
420 }
421
422 if (mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800423 ST_LOGE("attachToContext: GLConsumer is already attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700424 "context");
425 return INVALID_OPERATION;
426 }
427
428 EGLDisplay dpy = eglGetCurrentDisplay();
429 EGLContext ctx = eglGetCurrentContext();
430
431 if (dpy == EGL_NO_DISPLAY) {
432 ST_LOGE("attachToContext: invalid current EGLDisplay");
433 return INVALID_OPERATION;
434 }
435
436 if (ctx == EGL_NO_CONTEXT) {
437 ST_LOGE("attachToContext: invalid current EGLContext");
438 return INVALID_OPERATION;
439 }
440
441 // We need to bind the texture regardless of whether there's a current
442 // buffer.
443 glBindTexture(mTexTarget, tex);
444
445 if (mCurrentTextureBuf != NULL) {
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700446 // The EGLImageKHR that was associated with the slot was destroyed when
Andy McFadden2adaf042012-12-18 09:49:45 -0800447 // the GLConsumer was detached from the old context, so we need to
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700448 // recreate it here.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800449 status_t err = bindUnslottedBufferLocked(dpy);
450 if (err != NO_ERROR) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700451 return err;
452 }
453 }
454
455 mEglDisplay = dpy;
456 mEglContext = ctx;
457 mTexName = tex;
458 mAttached = true;
459
460 return OK;
461}
462
Andy McFadden2adaf042012-12-18 09:49:45 -0800463status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800464 ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
465 mCurrentTexture, mCurrentTextureBuf.get());
466
467 // Create a temporary EGLImageKHR.
468 EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
469 if (image == EGL_NO_IMAGE_KHR) {
470 return UNKNOWN_ERROR;
471 }
472
473 // Attach the current buffer to the GL texture.
474 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
475
476 GLint error;
477 status_t err = OK;
478 while ((error = glGetError()) != GL_NO_ERROR) {
479 ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
480 "(slot %d): %#04x", image, mCurrentTexture, error);
481 err = UNKNOWN_ERROR;
482 }
483
484 // We destroy the EGLImageKHR here because the current buffer may no
485 // longer be associated with one of the buffer slots, so we have
486 // nowhere to to store it. If the buffer is still associated with a
487 // slot then another EGLImageKHR will be created next time that buffer
488 // gets acquired in updateTexImage.
489 eglDestroyImageKHR(dpy, image);
490
491 return err;
492}
493
494
Andy McFadden2adaf042012-12-18 09:49:45 -0800495status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700496 ST_LOGV("syncForReleaseLocked");
497
Jamie Gennis01dbf552012-09-06 14:54:19 -0700498 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Mathias Agopianca088332013-03-28 17:44:13 -0700499 if (SyncFeatures::getInstance().useNativeFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700500 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
501 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
502 if (sync == EGL_NO_SYNC_KHR) {
503 ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
504 eglGetError());
Jamie Gennis74bed552012-03-28 19:05:54 -0700505 return UNKNOWN_ERROR;
Jamie Gennis74bed552012-03-28 19:05:54 -0700506 }
Jamie Gennis01dbf552012-09-06 14:54:19 -0700507 glFlush();
508 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
Jamie Gennis98ff0592012-09-10 14:49:42 -0700509 eglDestroySyncKHR(dpy, sync);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700510 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
511 ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
512 "fd: %#x", eglGetError());
513 return UNKNOWN_ERROR;
514 }
515 sp<Fence> fence(new Fence(fenceFd));
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700516 status_t err = addReleaseFenceLocked(mCurrentTexture,
517 mCurrentTextureBuf, fence);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700518 if (err != OK) {
519 ST_LOGE("syncForReleaseLocked: error adding release fence: "
520 "%s (%d)", strerror(-err), err);
521 return err;
522 }
Mathias Agopianca088332013-03-28 17:44:13 -0700523 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700524 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
525 if (fence != EGL_NO_SYNC_KHR) {
526 // There is already a fence for the current slot. We need to
527 // wait on that before replacing it with another fence to
528 // ensure that all outstanding buffer accesses have completed
529 // before the producer accesses it.
530 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
531 if (result == EGL_FALSE) {
532 ST_LOGE("syncForReleaseLocked: error waiting for previous "
533 "fence: %#x", eglGetError());
534 return UNKNOWN_ERROR;
535 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
536 ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
537 "fence");
538 return TIMED_OUT;
539 }
540 eglDestroySyncKHR(dpy, fence);
541 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700542
Jamie Gennis01dbf552012-09-06 14:54:19 -0700543 // Create a fence for the outstanding accesses in the current
544 // OpenGL ES context.
545 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
546 if (fence == EGL_NO_SYNC_KHR) {
547 ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
548 eglGetError());
549 return UNKNOWN_ERROR;
550 }
551 glFlush();
552 mEglSlots[mCurrentTexture].mEglFence = fence;
Jamie Gennis74bed552012-03-28 19:05:54 -0700553 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700554 }
555
556 return OK;
557}
558
Andy McFadden2adaf042012-12-18 09:49:45 -0800559bool GLConsumer::isExternalFormat(uint32_t format)
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700560{
561 switch (format) {
562 // supported YUV formats
563 case HAL_PIXEL_FORMAT_YV12:
564 // Legacy/deprecated YUV formats
565 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
566 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
567 case HAL_PIXEL_FORMAT_YCbCr_422_I:
568 return true;
569 }
570
571 // Any OEM format needs to be considered
572 if (format>=0x100 && format<=0x1FF)
573 return true;
574
575 return false;
576}
577
Andy McFadden2adaf042012-12-18 09:49:45 -0800578GLenum GLConsumer::getCurrentTextureTarget() const {
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700579 return mTexTarget;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700580}
581
Andy McFadden2adaf042012-12-18 09:49:45 -0800582void GLConsumer::getTransformMatrix(float mtx[16]) {
Jamie Gennisf238e282011-01-09 16:33:17 -0800583 Mutex::Autolock lock(mMutex);
Jamie Gennis736aa952011-06-12 17:03:06 -0700584 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
585}
586
Andy McFadden2adaf042012-12-18 09:49:45 -0800587void GLConsumer::setFilteringEnabled(bool enabled) {
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700588 Mutex::Autolock lock(mMutex);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700589 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800590 ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700591 return;
592 }
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700593 bool needsRecompute = mFilteringEnabled != enabled;
594 mFilteringEnabled = enabled;
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700595
596 if (needsRecompute && mCurrentTextureBuf==NULL) {
597 ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
598 }
599
600 if (needsRecompute && mCurrentTextureBuf != NULL) {
601 computeCurrentTransformMatrixLocked();
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700602 }
603}
604
Andy McFadden2adaf042012-12-18 09:49:45 -0800605void GLConsumer::computeCurrentTransformMatrixLocked() {
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700606 ST_LOGV("computeCurrentTransformMatrixLocked");
Jamie Gennisf238e282011-01-09 16:33:17 -0800607
Jamie Gennisa214c642011-01-14 13:53:31 -0800608 float xform[16];
609 for (int i = 0; i < 16; i++) {
610 xform[i] = mtxIdentity[i];
611 }
612 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
613 float result[16];
614 mtxMul(result, xform, mtxFlipH);
615 for (int i = 0; i < 16; i++) {
616 xform[i] = result[i];
617 }
618 }
619 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
620 float result[16];
621 mtxMul(result, xform, mtxFlipV);
622 for (int i = 0; i < 16; i++) {
623 xform[i] = result[i];
624 }
625 }
626 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
627 float result[16];
628 mtxMul(result, xform, mtxRot90);
629 for (int i = 0; i < 16; i++) {
630 xform[i] = result[i];
631 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800632 }
633
Daniel Lameae59d22012-01-22 15:26:27 -0800634 sp<GraphicBuffer>& buf(mCurrentTextureBuf);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700635
636 if (buf == NULL) {
637 ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
638 }
639
Jamie Gennisd72f2332012-05-07 13:50:11 -0700640 Rect cropRect = mCurrentCrop;
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700641 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
642 float bufferWidth = buf->getWidth();
643 float bufferHeight = buf->getHeight();
Jamie Gennisd72f2332012-05-07 13:50:11 -0700644 if (!cropRect.isEmpty()) {
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700645 float shrinkAmount = 0.0f;
646 if (mFilteringEnabled) {
647 // In order to prevent bilinear sampling beyond the edge of the
648 // crop rectangle we may need to shrink it by 2 texels in each
649 // dimension. Normally this would just need to take 1/2 a texel
650 // off each end, but because the chroma channels of YUV420 images
651 // are subsampled we may need to shrink the crop region by a whole
652 // texel on each side.
653 switch (buf->getPixelFormat()) {
654 case PIXEL_FORMAT_RGBA_8888:
655 case PIXEL_FORMAT_RGBX_8888:
656 case PIXEL_FORMAT_RGB_888:
657 case PIXEL_FORMAT_RGB_565:
658 case PIXEL_FORMAT_BGRA_8888:
659 case PIXEL_FORMAT_RGBA_5551:
660 case PIXEL_FORMAT_RGBA_4444:
661 // We know there's no subsampling of any channels, so we
662 // only need to shrink by a half a pixel.
663 shrinkAmount = 0.5;
Romain Guy4f9c2842012-08-01 19:16:59 -0700664 break;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700665
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700666 default:
667 // If we don't recognize the format, we must assume the
668 // worst case (that we care about), which is YUV420.
669 shrinkAmount = 1.0;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700670 break;
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700671 }
672 }
Jamie Gennisd72f2332012-05-07 13:50:11 -0700673
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700674 // Only shrink the dimensions that are not the size of the buffer.
675 if (cropRect.width() < bufferWidth) {
676 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
677 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
678 bufferWidth;
679 }
680 if (cropRect.height() < bufferHeight) {
681 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
682 bufferHeight;
683 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
684 bufferHeight;
685 }
Jamie Gennisa214c642011-01-14 13:53:31 -0800686 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800687 float crop[16] = {
Jamie Gennisa214c642011-01-14 13:53:31 -0800688 sx, 0, 0, 0,
689 0, sy, 0, 0,
Jamie Gennisf238e282011-01-09 16:33:17 -0800690 0, 0, 1, 0,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800691 tx, ty, 0, 1,
Jamie Gennisf238e282011-01-09 16:33:17 -0800692 };
693
Jamie Gennisa214c642011-01-14 13:53:31 -0800694 float mtxBeforeFlipV[16];
695 mtxMul(mtxBeforeFlipV, crop, xform);
696
697 // SurfaceFlinger expects the top of its window textures to be at a Y
Andy McFadden2adaf042012-12-18 09:49:45 -0800698 // coordinate of 0, so GLConsumer must behave the same way. We don't
Jamie Gennisa214c642011-01-14 13:53:31 -0800699 // want to expose this to applications, however, so we must add an
700 // additional vertical flip to the transform after all the other transforms.
Jamie Gennis736aa952011-06-12 17:03:06 -0700701 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
Jamie Gennisf238e282011-01-09 16:33:17 -0800702}
703
Andy McFadden2adaf042012-12-18 09:49:45 -0800704nsecs_t GLConsumer::getTimestamp() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700705 ST_LOGV("getTimestamp");
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800706 Mutex::Autolock lock(mMutex);
707 return mCurrentTimestamp;
708}
709
Andy McFadden2adaf042012-12-18 09:49:45 -0800710EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800711 const sp<GraphicBuffer>& graphicBuffer) {
712 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
713 EGLint attrs[] = {
714 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
715 EGL_NONE,
716 };
717 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
718 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700719 if (image == EGL_NO_IMAGE_KHR) {
720 EGLint error = eglGetError();
Jamie Gennisfa28c352011-09-16 17:30:26 -0700721 ST_LOGE("error creating EGLImage: %#x", error);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800722 }
723 return image;
724}
725
Andy McFadden2adaf042012-12-18 09:49:45 -0800726sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700727 Mutex::Autolock lock(mMutex);
728 return mCurrentTextureBuf;
729}
730
Andy McFadden2adaf042012-12-18 09:49:45 -0800731Rect GLConsumer::getCurrentCrop() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700732 Mutex::Autolock lock(mMutex);
Daniel Lam016c8cb2012-04-03 15:54:58 -0700733
734 Rect outCrop = mCurrentCrop;
735 if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
736 int32_t newWidth = mCurrentCrop.width();
737 int32_t newHeight = mCurrentCrop.height();
738
739 if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
740 newWidth = newHeight * mDefaultWidth / mDefaultHeight;
741 ST_LOGV("too wide: newWidth = %d", newWidth);
742 } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
743 newHeight = newWidth * mDefaultHeight / mDefaultWidth;
744 ST_LOGV("too tall: newHeight = %d", newHeight);
745 }
746
747 // The crop is too wide
748 if (newWidth < mCurrentCrop.width()) {
749 int32_t dw = (newWidth - mCurrentCrop.width())/2;
750 outCrop.left -=dw;
751 outCrop.right += dw;
752 // The crop is too tall
753 } else if (newHeight < mCurrentCrop.height()) {
754 int32_t dh = (newHeight - mCurrentCrop.height())/2;
755 outCrop.top -= dh;
756 outCrop.bottom += dh;
757 }
758
759 ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
760 outCrop.left, outCrop.top,
761 outCrop.right,outCrop.bottom);
762 }
763
Daniel Lam016c8cb2012-04-03 15:54:58 -0700764 return outCrop;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700765}
766
Andy McFadden2adaf042012-12-18 09:49:45 -0800767uint32_t GLConsumer::getCurrentTransform() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700768 Mutex::Autolock lock(mMutex);
769 return mCurrentTransform;
770}
771
Andy McFadden2adaf042012-12-18 09:49:45 -0800772uint32_t GLConsumer::getCurrentScalingMode() const {
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700773 Mutex::Autolock lock(mMutex);
774 return mCurrentScalingMode;
775}
776
Andy McFadden2adaf042012-12-18 09:49:45 -0800777sp<Fence> GLConsumer::getCurrentFence() const {
Jesse Halldc5b4852012-06-29 15:21:18 -0700778 Mutex::Autolock lock(mMutex);
779 return mCurrentFence;
780}
781
Andy McFadden2adaf042012-12-18 09:49:45 -0800782status_t GLConsumer::doGLFenceWait() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700783 Mutex::Autolock lock(mMutex);
Jamie Gennis3941cb22012-09-17 16:58:17 -0700784 return doGLFenceWaitLocked();
785}
786
Andy McFadden2adaf042012-12-18 09:49:45 -0800787status_t GLConsumer::doGLFenceWaitLocked() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700788
789 EGLDisplay dpy = eglGetCurrentDisplay();
790 EGLContext ctx = eglGetCurrentContext();
791
792 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
793 ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
794 return INVALID_OPERATION;
795 }
796
797 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
798 ST_LOGE("doGLFenceWait: invalid current EGLContext");
799 return INVALID_OPERATION;
800 }
801
Jamie Gennis1df8c342012-12-20 14:05:45 -0800802 if (mCurrentFence->isValid()) {
Mathias Agopianca088332013-03-28 17:44:13 -0700803 if (SyncFeatures::getInstance().useWaitSync()) {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700804 // Create an EGLSyncKHR from the current fence.
805 int fenceFd = mCurrentFence->dup();
806 if (fenceFd == -1) {
807 ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
808 return -errno;
809 }
810 EGLint attribs[] = {
811 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
812 EGL_NONE
813 };
814 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
815 EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
816 if (sync == EGL_NO_SYNC_KHR) {
817 close(fenceFd);
818 ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
819 eglGetError());
820 return UNKNOWN_ERROR;
821 }
822
823 // XXX: The spec draft is inconsistent as to whether this should
824 // return an EGLint or void. Ignore the return value for now, as
825 // it's not strictly needed.
Mathias Agopian2bb71682013-03-27 17:32:41 -0700826 eglWaitSyncKHR(dpy, sync, 0);
Jamie Gennis61e04b92012-09-09 17:48:42 -0700827 EGLint eglErr = eglGetError();
828 eglDestroySyncKHR(dpy, sync);
829 if (eglErr != EGL_SUCCESS) {
830 ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
831 eglErr);
832 return UNKNOWN_ERROR;
833 }
834 } else {
Mathias Agopianea74d3b2013-05-16 18:03:22 -0700835 status_t err = mCurrentFence->waitForever(
Andy McFadden2adaf042012-12-18 09:49:45 -0800836 "GLConsumer::doGLFenceWaitLocked");
Jamie Gennis61e04b92012-09-09 17:48:42 -0700837 if (err != NO_ERROR) {
838 ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
839 return err;
840 }
841 }
842 }
843
844 return NO_ERROR;
845}
846
Andy McFadden2adaf042012-12-18 09:49:45 -0800847void GLConsumer::freeBufferLocked(int slotIndex) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700848 ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700849 if (slotIndex == mCurrentTexture) {
850 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
851 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700852 EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700853 if (img != EGL_NO_IMAGE_KHR) {
854 ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
855 eglDestroyImageKHR(mEglDisplay, img);
Daniel Lameae59d22012-01-22 15:26:27 -0800856 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700857 mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
858 ConsumerBase::freeBufferLocked(slotIndex);
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700859}
Daniel Lameae59d22012-01-22 15:26:27 -0800860
Andy McFadden2adaf042012-12-18 09:49:45 -0800861void GLConsumer::abandonLocked() {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700862 ST_LOGV("abandonLocked");
863 mCurrentTextureBuf.clear();
864 ConsumerBase::abandonLocked();
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700865}
866
Andy McFadden2adaf042012-12-18 09:49:45 -0800867void GLConsumer::setName(const String8& name) {
Daniel Lameae59d22012-01-22 15:26:27 -0800868 Mutex::Autolock _l(mMutex);
Jamie Gennisfa28c352011-09-16 17:30:26 -0700869 mName = name;
Daniel Lamb2675792012-02-23 14:35:13 -0800870 mBufferQueue->setConsumerName(name);
871}
872
Andy McFadden2adaf042012-12-18 09:49:45 -0800873status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
Daniel Lamb2675792012-02-23 14:35:13 -0800874 Mutex::Autolock lock(mMutex);
875 return mBufferQueue->setDefaultBufferFormat(defaultFormat);
876}
877
Andy McFadden2adaf042012-12-18 09:49:45 -0800878status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
Daniel Lamb2675792012-02-23 14:35:13 -0800879 Mutex::Autolock lock(mMutex);
Eino-Ville Talvala85b21762012-04-13 15:16:31 -0700880 usage |= DEFAULT_USAGE_FLAGS;
Daniel Lamb2675792012-02-23 14:35:13 -0800881 return mBufferQueue->setConsumerUsageBits(usage);
882}
883
Andy McFadden2adaf042012-12-18 09:49:45 -0800884status_t GLConsumer::setTransformHint(uint32_t hint) {
Daniel Lamb2675792012-02-23 14:35:13 -0800885 Mutex::Autolock lock(mMutex);
886 return mBufferQueue->setTransformHint(hint);
887}
888
Mathias Agopian74d211a2013-04-22 16:55:35 +0200889void GLConsumer::dumpLocked(String8& result, const char* prefix) const
Mathias Agopian68c77942011-05-09 19:08:33 -0700890{
Mathias Agopian74d211a2013-04-22 16:55:35 +0200891 result.appendFormat(
Jamie Gennis9fea3422012-08-07 18:03:04 -0700892 "%smTexName=%d mCurrentTexture=%d\n"
893 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
894 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
895 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
896 mCurrentTransform);
Mathias Agopian68c77942011-05-09 19:08:33 -0700897
Mathias Agopian74d211a2013-04-22 16:55:35 +0200898 ConsumerBase::dumpLocked(result, prefix);
Mathias Agopian68c77942011-05-09 19:08:33 -0700899}
900
Jamie Gennisf238e282011-01-09 16:33:17 -0800901static void mtxMul(float out[16], const float a[16], const float b[16]) {
902 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
903 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
904 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
905 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
906
907 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
908 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
909 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
910 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
911
912 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
913 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
914 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
915 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
916
917 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
918 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
919 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
920 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
921}
922
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800923}; // namespace android