blob: 6d29edc0c4f27c85820667254e42459bc2551dd6 [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
Andy McFadden2adaf042012-12-18 09:49:45 -080081GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode,
Daniel Lamb2675792012-02-23 14:35:13 -080082 GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
Jamie Gennis9fea3422012-08-07 18:03:04 -070083 ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
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.
142 err = acquireBufferLocked(&item);
143 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 McFadden2adaf042012-12-18 09:49:45 -0800168status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700169 status_t err = ConsumerBase::acquireBufferLocked(item);
170 if (err != NO_ERROR) {
171 return err;
172 }
173
174 int slot = item->mBuf;
175 if (item->mGraphicBuffer != NULL) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800176 // This buffer has not been acquired before, so we must assume
177 // that any EGLImage in mEglSlots is stale.
Jamie Gennis9fea3422012-08-07 18:03:04 -0700178 if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800179 if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
180 ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
181 slot);
182 // keep going
183 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700184 mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
185 }
186 }
187
Jamie Gennis9fea3422012-08-07 18:03:04 -0700188 return NO_ERROR;
189}
190
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700191status_t GLConsumer::releaseBufferLocked(int buf,
192 sp<GraphicBuffer> graphicBuffer,
193 EGLDisplay display, EGLSyncKHR eglFence) {
194 // release the buffer if it hasn't already been discarded by the
195 // BufferQueue. This can happen, for example, when the producer of this
196 // buffer has reallocated the original buffer slot after this buffer
197 // was acquired.
198 status_t err = ConsumerBase::releaseBufferLocked(
199 buf, graphicBuffer, display, eglFence);
Jamie Gennisd1b330d2012-09-21 11:55:35 -0700200 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700201 return err;
202}
203
Andy McFadden2adaf042012-12-18 09:49:45 -0800204status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800205{
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700206 status_t err = NO_ERROR;
207
Jamie Gennis74bed552012-03-28 19:05:54 -0700208 if (!mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800209 ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL "
Jamie Gennis74bed552012-03-28 19:05:54 -0700210 "ES context");
211 return INVALID_OPERATION;
212 }
213
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800214 // Confirm state.
215 err = checkAndUpdateEglStateLocked();
216 if (err != NO_ERROR) {
217 return err;
218 }
219
220 int buf = item.mBuf;
221
222 // If the mEglSlot entry is empty, create an EGLImage for the gralloc
223 // buffer currently in the slot in ConsumerBase.
224 //
225 // We may have to do this even when item.mGraphicBuffer == NULL (which
226 // means the buffer was previously acquired), if we destroyed the
227 // EGLImage when detaching from a context but the buffer has not been
228 // re-allocated.
229 if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
230 EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
231 if (image == EGL_NO_IMAGE_KHR) {
232 ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d",
233 mEglDisplay, buf);
234 return UNKNOWN_ERROR;
235 }
236 mEglSlots[buf].mEglImage = image;
237 }
238
239 // Do whatever sync ops we need to do before releasing the old slot.
240 err = syncForReleaseLocked(mEglDisplay);
241 if (err != NO_ERROR) {
242 // Release the buffer we just acquired. It's not safe to
243 // release the old buffer, so instead we just drop the new frame.
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700244 // As we are still under lock since acquireBuffer, it is safe to
245 // release by slot.
246 releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
247 mEglDisplay, EGL_NO_SYNC_KHR);
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800248 return err;
249 }
250
251 ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)",
252 mCurrentTexture,
253 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
254 buf, mSlots[buf].mGraphicBuffer->handle);
255
256 // release old buffer
257 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700258 status_t status = releaseBufferLocked(
259 mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800260 mEglSlots[mCurrentTexture].mEglFence);
261 if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
262 ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)",
263 strerror(-status), status);
264 err = status;
265 // keep going, with error raised [?]
266 }
267 }
268
Andy McFadden2adaf042012-12-18 09:49:45 -0800269 // Update the GLConsumer state.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800270 mCurrentTexture = buf;
271 mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
272 mCurrentCrop = item.mCrop;
273 mCurrentTransform = item.mTransform;
274 mCurrentScalingMode = item.mScalingMode;
275 mCurrentTimestamp = item.mTimestamp;
276 mCurrentFence = item.mFence;
277
278 computeCurrentTransformMatrixLocked();
279
280 return err;
281}
282
Andy McFadden2adaf042012-12-18 09:49:45 -0800283status_t GLConsumer::bindTextureImageLocked() {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800284 if (mEglDisplay == EGL_NO_DISPLAY) {
285 ALOGE("bindTextureImage: invalid display");
286 return INVALID_OPERATION;
287 }
288
289 GLint error;
290 while ((error = glGetError()) != GL_NO_ERROR) {
291 ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
292 }
293
294 glBindTexture(mTexTarget, mTexName);
295 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
296 if (mCurrentTextureBuf == NULL) {
297 ST_LOGE("bindTextureImage: no currently-bound texture");
298 return NO_INIT;
299 }
Andy McFadden97eba892012-12-11 15:21:45 -0800300 status_t err = bindUnslottedBufferLocked(mEglDisplay);
301 if (err != NO_ERROR) {
302 return err;
303 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800304 } else {
305 EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
306
307 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
308
309 while ((error = glGetError()) != GL_NO_ERROR) {
310 ST_LOGE("bindTextureImage: error binding external texture image %p"
311 ": %#04x", image, error);
312 return UNKNOWN_ERROR;
313 }
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800314 }
Andy McFadden97eba892012-12-11 15:21:45 -0800315
316 // Wait for the new buffer to be ready.
317 return doGLFenceWaitLocked();
318
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800319}
320
Andy McFadden2adaf042012-12-18 09:49:45 -0800321status_t GLConsumer::checkAndUpdateEglStateLocked() {
Jamie Gennisce561372012-03-19 18:33:05 -0700322 EGLDisplay dpy = eglGetCurrentDisplay();
323 EGLContext ctx = eglGetCurrentContext();
324
Jamie Gennis74bed552012-03-28 19:05:54 -0700325 if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
326 dpy == EGL_NO_DISPLAY) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800327 ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
Jamie Gennis74bed552012-03-28 19:05:54 -0700328 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700329 }
330
Jamie Gennis74bed552012-03-28 19:05:54 -0700331 if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
332 ctx == EGL_NO_CONTEXT) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800333 ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
Jamie Gennis74bed552012-03-28 19:05:54 -0700334 return INVALID_OPERATION;
Jamie Gennisce561372012-03-19 18:33:05 -0700335 }
336
337 mEglDisplay = dpy;
338 mEglContext = ctx;
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800339 return NO_ERROR;
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800340}
341
Jesse Hall13f01cb2013-03-20 11:37:21 -0700342void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
343 if (fence->isValid() &&
344 mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700345 status_t err = addReleaseFence(mCurrentTexture,
346 mCurrentTextureBuf, fence);
Jesse Hall13f01cb2013-03-20 11:37:21 -0700347 if (err != OK) {
348 ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
349 strerror(-err), err);
350 }
Jesse Hallef194142012-06-14 14:45:17 -0700351 }
352}
353
Andy McFadden2adaf042012-12-18 09:49:45 -0800354status_t GLConsumer::detachFromContext() {
Jamie Gennis74bed552012-03-28 19:05:54 -0700355 ATRACE_CALL();
356 ST_LOGV("detachFromContext");
357 Mutex::Autolock lock(mMutex);
358
359 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800360 ST_LOGE("detachFromContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700361 return NO_INIT;
362 }
363
364 if (!mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800365 ST_LOGE("detachFromContext: GLConsumer is not attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700366 "context");
367 return INVALID_OPERATION;
368 }
369
370 EGLDisplay dpy = eglGetCurrentDisplay();
371 EGLContext ctx = eglGetCurrentContext();
372
373 if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
374 ST_LOGE("detachFromContext: invalid current EGLDisplay");
375 return INVALID_OPERATION;
376 }
377
378 if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
379 ST_LOGE("detachFromContext: invalid current EGLContext");
380 return INVALID_OPERATION;
381 }
382
383 if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
384 status_t err = syncForReleaseLocked(dpy);
385 if (err != OK) {
386 return err;
387 }
388
389 glDeleteTextures(1, &mTexName);
390 }
391
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700392 // Because we're giving up the EGLDisplay we need to free all the EGLImages
393 // that are associated with it. They'll be recreated when the
Andy McFadden2adaf042012-12-18 09:49:45 -0800394 // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700395 // new EGLDisplay).
396 for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700397 EGLImageKHR img = mEglSlots[i].mEglImage;
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700398 if (img != EGL_NO_IMAGE_KHR) {
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700399 eglDestroyImageKHR(mEglDisplay, img);
Jamie Gennis9fea3422012-08-07 18:03:04 -0700400 mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700401 }
402 }
403
Jamie Gennis74bed552012-03-28 19:05:54 -0700404 mEglDisplay = EGL_NO_DISPLAY;
405 mEglContext = EGL_NO_CONTEXT;
406 mAttached = false;
407
408 return OK;
409}
410
Andy McFadden2adaf042012-12-18 09:49:45 -0800411status_t GLConsumer::attachToContext(GLuint tex) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700412 ATRACE_CALL();
413 ST_LOGV("attachToContext");
414 Mutex::Autolock lock(mMutex);
415
416 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800417 ST_LOGE("attachToContext: abandoned GLConsumer");
Jamie Gennis74bed552012-03-28 19:05:54 -0700418 return NO_INIT;
419 }
420
421 if (mAttached) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800422 ST_LOGE("attachToContext: GLConsumer is already attached to a "
Jamie Gennis74bed552012-03-28 19:05:54 -0700423 "context");
424 return INVALID_OPERATION;
425 }
426
427 EGLDisplay dpy = eglGetCurrentDisplay();
428 EGLContext ctx = eglGetCurrentContext();
429
430 if (dpy == EGL_NO_DISPLAY) {
431 ST_LOGE("attachToContext: invalid current EGLDisplay");
432 return INVALID_OPERATION;
433 }
434
435 if (ctx == EGL_NO_CONTEXT) {
436 ST_LOGE("attachToContext: invalid current EGLContext");
437 return INVALID_OPERATION;
438 }
439
440 // We need to bind the texture regardless of whether there's a current
441 // buffer.
442 glBindTexture(mTexTarget, tex);
443
444 if (mCurrentTextureBuf != NULL) {
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700445 // The EGLImageKHR that was associated with the slot was destroyed when
Andy McFadden2adaf042012-12-18 09:49:45 -0800446 // the GLConsumer was detached from the old context, so we need to
Jamie Gennis5c8a6082012-05-02 13:10:56 -0700447 // recreate it here.
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800448 status_t err = bindUnslottedBufferLocked(dpy);
449 if (err != NO_ERROR) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700450 return err;
451 }
452 }
453
454 mEglDisplay = dpy;
455 mEglContext = ctx;
456 mTexName = tex;
457 mAttached = true;
458
459 return OK;
460}
461
Andy McFadden2adaf042012-12-18 09:49:45 -0800462status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
Andy McFaddenbf974ab2012-12-04 16:51:15 -0800463 ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
464 mCurrentTexture, mCurrentTextureBuf.get());
465
466 // Create a temporary EGLImageKHR.
467 EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
468 if (image == EGL_NO_IMAGE_KHR) {
469 return UNKNOWN_ERROR;
470 }
471
472 // Attach the current buffer to the GL texture.
473 glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
474
475 GLint error;
476 status_t err = OK;
477 while ((error = glGetError()) != GL_NO_ERROR) {
478 ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
479 "(slot %d): %#04x", image, mCurrentTexture, error);
480 err = UNKNOWN_ERROR;
481 }
482
483 // We destroy the EGLImageKHR here because the current buffer may no
484 // longer be associated with one of the buffer slots, so we have
485 // nowhere to to store it. If the buffer is still associated with a
486 // slot then another EGLImageKHR will be created next time that buffer
487 // gets acquired in updateTexImage.
488 eglDestroyImageKHR(dpy, image);
489
490 return err;
491}
492
493
Andy McFadden2adaf042012-12-18 09:49:45 -0800494status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
Jamie Gennis74bed552012-03-28 19:05:54 -0700495 ST_LOGV("syncForReleaseLocked");
496
Jamie Gennis01dbf552012-09-06 14:54:19 -0700497 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
Mathias Agopianca088332013-03-28 17:44:13 -0700498 if (SyncFeatures::getInstance().useNativeFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700499 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
500 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
501 if (sync == EGL_NO_SYNC_KHR) {
502 ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
503 eglGetError());
Jamie Gennis74bed552012-03-28 19:05:54 -0700504 return UNKNOWN_ERROR;
Jamie Gennis74bed552012-03-28 19:05:54 -0700505 }
Jamie Gennis01dbf552012-09-06 14:54:19 -0700506 glFlush();
507 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
Jamie Gennis98ff0592012-09-10 14:49:42 -0700508 eglDestroySyncKHR(dpy, sync);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700509 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
510 ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
511 "fd: %#x", eglGetError());
512 return UNKNOWN_ERROR;
513 }
514 sp<Fence> fence(new Fence(fenceFd));
Lajos Molnarc5d7b7d2013-05-03 14:50:50 -0700515 status_t err = addReleaseFenceLocked(mCurrentTexture,
516 mCurrentTextureBuf, fence);
Jamie Gennis01dbf552012-09-06 14:54:19 -0700517 if (err != OK) {
518 ST_LOGE("syncForReleaseLocked: error adding release fence: "
519 "%s (%d)", strerror(-err), err);
520 return err;
521 }
Mathias Agopianca088332013-03-28 17:44:13 -0700522 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
Jamie Gennis01dbf552012-09-06 14:54:19 -0700523 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
524 if (fence != EGL_NO_SYNC_KHR) {
525 // There is already a fence for the current slot. We need to
526 // wait on that before replacing it with another fence to
527 // ensure that all outstanding buffer accesses have completed
528 // before the producer accesses it.
529 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
530 if (result == EGL_FALSE) {
531 ST_LOGE("syncForReleaseLocked: error waiting for previous "
532 "fence: %#x", eglGetError());
533 return UNKNOWN_ERROR;
534 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
535 ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
536 "fence");
537 return TIMED_OUT;
538 }
539 eglDestroySyncKHR(dpy, fence);
540 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700541
Jamie Gennis01dbf552012-09-06 14:54:19 -0700542 // Create a fence for the outstanding accesses in the current
543 // OpenGL ES context.
544 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
545 if (fence == EGL_NO_SYNC_KHR) {
546 ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
547 eglGetError());
548 return UNKNOWN_ERROR;
549 }
550 glFlush();
551 mEglSlots[mCurrentTexture].mEglFence = fence;
Jamie Gennis74bed552012-03-28 19:05:54 -0700552 }
Jamie Gennis74bed552012-03-28 19:05:54 -0700553 }
554
555 return OK;
556}
557
Andy McFadden2adaf042012-12-18 09:49:45 -0800558bool GLConsumer::isExternalFormat(uint32_t format)
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700559{
560 switch (format) {
561 // supported YUV formats
562 case HAL_PIXEL_FORMAT_YV12:
563 // Legacy/deprecated YUV formats
564 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
565 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
566 case HAL_PIXEL_FORMAT_YCbCr_422_I:
567 return true;
568 }
569
570 // Any OEM format needs to be considered
571 if (format>=0x100 && format<=0x1FF)
572 return true;
573
574 return false;
575}
576
Andy McFadden2adaf042012-12-18 09:49:45 -0800577GLenum GLConsumer::getCurrentTextureTarget() const {
Jamie Gennisfb1b5a22011-09-28 12:13:31 -0700578 return mTexTarget;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700579}
580
Andy McFadden2adaf042012-12-18 09:49:45 -0800581void GLConsumer::getTransformMatrix(float mtx[16]) {
Jamie Gennisf238e282011-01-09 16:33:17 -0800582 Mutex::Autolock lock(mMutex);
Jamie Gennis736aa952011-06-12 17:03:06 -0700583 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
584}
585
Andy McFadden2adaf042012-12-18 09:49:45 -0800586void GLConsumer::setFilteringEnabled(bool enabled) {
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700587 Mutex::Autolock lock(mMutex);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700588 if (mAbandoned) {
Andy McFadden2adaf042012-12-18 09:49:45 -0800589 ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700590 return;
591 }
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700592 bool needsRecompute = mFilteringEnabled != enabled;
593 mFilteringEnabled = enabled;
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700594
595 if (needsRecompute && mCurrentTextureBuf==NULL) {
596 ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
597 }
598
599 if (needsRecompute && mCurrentTextureBuf != NULL) {
600 computeCurrentTransformMatrixLocked();
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700601 }
602}
603
Andy McFadden2adaf042012-12-18 09:49:45 -0800604void GLConsumer::computeCurrentTransformMatrixLocked() {
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700605 ST_LOGV("computeCurrentTransformMatrixLocked");
Jamie Gennisf238e282011-01-09 16:33:17 -0800606
Jamie Gennisa214c642011-01-14 13:53:31 -0800607 float xform[16];
608 for (int i = 0; i < 16; i++) {
609 xform[i] = mtxIdentity[i];
610 }
611 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
612 float result[16];
613 mtxMul(result, xform, mtxFlipH);
614 for (int i = 0; i < 16; i++) {
615 xform[i] = result[i];
616 }
617 }
618 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
619 float result[16];
620 mtxMul(result, xform, mtxFlipV);
621 for (int i = 0; i < 16; i++) {
622 xform[i] = result[i];
623 }
624 }
625 if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
626 float result[16];
627 mtxMul(result, xform, mtxRot90);
628 for (int i = 0; i < 16; i++) {
629 xform[i] = result[i];
630 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800631 }
632
Daniel Lameae59d22012-01-22 15:26:27 -0800633 sp<GraphicBuffer>& buf(mCurrentTextureBuf);
Mathias Agopiane96e9e12012-09-24 19:26:11 -0700634
635 if (buf == NULL) {
636 ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
637 }
638
Jamie Gennisd72f2332012-05-07 13:50:11 -0700639 Rect cropRect = mCurrentCrop;
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700640 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
641 float bufferWidth = buf->getWidth();
642 float bufferHeight = buf->getHeight();
Jamie Gennisd72f2332012-05-07 13:50:11 -0700643 if (!cropRect.isEmpty()) {
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700644 float shrinkAmount = 0.0f;
645 if (mFilteringEnabled) {
646 // In order to prevent bilinear sampling beyond the edge of the
647 // crop rectangle we may need to shrink it by 2 texels in each
648 // dimension. Normally this would just need to take 1/2 a texel
649 // off each end, but because the chroma channels of YUV420 images
650 // are subsampled we may need to shrink the crop region by a whole
651 // texel on each side.
652 switch (buf->getPixelFormat()) {
653 case PIXEL_FORMAT_RGBA_8888:
654 case PIXEL_FORMAT_RGBX_8888:
655 case PIXEL_FORMAT_RGB_888:
656 case PIXEL_FORMAT_RGB_565:
657 case PIXEL_FORMAT_BGRA_8888:
658 case PIXEL_FORMAT_RGBA_5551:
659 case PIXEL_FORMAT_RGBA_4444:
660 // We know there's no subsampling of any channels, so we
661 // only need to shrink by a half a pixel.
662 shrinkAmount = 0.5;
Romain Guy4f9c2842012-08-01 19:16:59 -0700663 break;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700664
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700665 default:
666 // If we don't recognize the format, we must assume the
667 // worst case (that we care about), which is YUV420.
668 shrinkAmount = 1.0;
Jamie Gennis9fea3422012-08-07 18:03:04 -0700669 break;
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700670 }
671 }
Jamie Gennisd72f2332012-05-07 13:50:11 -0700672
Jamie Gennis5c1139f2012-05-08 16:56:34 -0700673 // Only shrink the dimensions that are not the size of the buffer.
674 if (cropRect.width() < bufferWidth) {
675 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
676 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
677 bufferWidth;
678 }
679 if (cropRect.height() < bufferHeight) {
680 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
681 bufferHeight;
682 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
683 bufferHeight;
684 }
Jamie Gennisa214c642011-01-14 13:53:31 -0800685 }
Jamie Gennisf238e282011-01-09 16:33:17 -0800686 float crop[16] = {
Jamie Gennisa214c642011-01-14 13:53:31 -0800687 sx, 0, 0, 0,
688 0, sy, 0, 0,
Jamie Gennisf238e282011-01-09 16:33:17 -0800689 0, 0, 1, 0,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800690 tx, ty, 0, 1,
Jamie Gennisf238e282011-01-09 16:33:17 -0800691 };
692
Jamie Gennisa214c642011-01-14 13:53:31 -0800693 float mtxBeforeFlipV[16];
694 mtxMul(mtxBeforeFlipV, crop, xform);
695
696 // SurfaceFlinger expects the top of its window textures to be at a Y
Andy McFadden2adaf042012-12-18 09:49:45 -0800697 // coordinate of 0, so GLConsumer must behave the same way. We don't
Jamie Gennisa214c642011-01-14 13:53:31 -0800698 // want to expose this to applications, however, so we must add an
699 // additional vertical flip to the transform after all the other transforms.
Jamie Gennis736aa952011-06-12 17:03:06 -0700700 mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
Jamie Gennisf238e282011-01-09 16:33:17 -0800701}
702
Andy McFadden2adaf042012-12-18 09:49:45 -0800703nsecs_t GLConsumer::getTimestamp() {
Jamie Gennis6ee96ad2011-10-19 13:36:31 -0700704 ST_LOGV("getTimestamp");
Eino-Ville Talvala1d01a122011-02-18 11:02:42 -0800705 Mutex::Autolock lock(mMutex);
706 return mCurrentTimestamp;
707}
708
Andy McFadden2adaf042012-12-18 09:49:45 -0800709EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800710 const sp<GraphicBuffer>& graphicBuffer) {
711 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
712 EGLint attrs[] = {
713 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
714 EGL_NONE,
715 };
716 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
717 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
Mathias Agopian3cd5a112011-04-26 14:57:40 -0700718 if (image == EGL_NO_IMAGE_KHR) {
719 EGLint error = eglGetError();
Jamie Gennisfa28c352011-09-16 17:30:26 -0700720 ST_LOGE("error creating EGLImage: %#x", error);
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800721 }
722 return image;
723}
724
Andy McFadden2adaf042012-12-18 09:49:45 -0800725sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700726 Mutex::Autolock lock(mMutex);
727 return mCurrentTextureBuf;
728}
729
Andy McFadden2adaf042012-12-18 09:49:45 -0800730Rect GLConsumer::getCurrentCrop() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700731 Mutex::Autolock lock(mMutex);
Daniel Lam016c8cb2012-04-03 15:54:58 -0700732
733 Rect outCrop = mCurrentCrop;
734 if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
735 int32_t newWidth = mCurrentCrop.width();
736 int32_t newHeight = mCurrentCrop.height();
737
738 if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
739 newWidth = newHeight * mDefaultWidth / mDefaultHeight;
740 ST_LOGV("too wide: newWidth = %d", newWidth);
741 } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
742 newHeight = newWidth * mDefaultHeight / mDefaultWidth;
743 ST_LOGV("too tall: newHeight = %d", newHeight);
744 }
745
746 // The crop is too wide
747 if (newWidth < mCurrentCrop.width()) {
748 int32_t dw = (newWidth - mCurrentCrop.width())/2;
749 outCrop.left -=dw;
750 outCrop.right += dw;
751 // The crop is too tall
752 } else if (newHeight < mCurrentCrop.height()) {
753 int32_t dh = (newHeight - mCurrentCrop.height())/2;
754 outCrop.top -= dh;
755 outCrop.bottom += dh;
756 }
757
758 ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
759 outCrop.left, outCrop.top,
760 outCrop.right,outCrop.bottom);
761 }
762
Daniel Lam016c8cb2012-04-03 15:54:58 -0700763 return outCrop;
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700764}
765
Andy McFadden2adaf042012-12-18 09:49:45 -0800766uint32_t GLConsumer::getCurrentTransform() const {
Mathias Agopian7a042bf2011-04-11 21:19:55 -0700767 Mutex::Autolock lock(mMutex);
768 return mCurrentTransform;
769}
770
Andy McFadden2adaf042012-12-18 09:49:45 -0800771uint32_t GLConsumer::getCurrentScalingMode() const {
Mathias Agopian7734ebf2011-07-13 15:24:42 -0700772 Mutex::Autolock lock(mMutex);
773 return mCurrentScalingMode;
774}
775
Andy McFadden2adaf042012-12-18 09:49:45 -0800776sp<Fence> GLConsumer::getCurrentFence() const {
Jesse Halldc5b4852012-06-29 15:21:18 -0700777 Mutex::Autolock lock(mMutex);
778 return mCurrentFence;
779}
780
Andy McFadden2adaf042012-12-18 09:49:45 -0800781status_t GLConsumer::doGLFenceWait() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700782 Mutex::Autolock lock(mMutex);
Jamie Gennis3941cb22012-09-17 16:58:17 -0700783 return doGLFenceWaitLocked();
784}
785
Andy McFadden2adaf042012-12-18 09:49:45 -0800786status_t GLConsumer::doGLFenceWaitLocked() const {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700787
788 EGLDisplay dpy = eglGetCurrentDisplay();
789 EGLContext ctx = eglGetCurrentContext();
790
791 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
792 ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
793 return INVALID_OPERATION;
794 }
795
796 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
797 ST_LOGE("doGLFenceWait: invalid current EGLContext");
798 return INVALID_OPERATION;
799 }
800
Jamie Gennis1df8c342012-12-20 14:05:45 -0800801 if (mCurrentFence->isValid()) {
Mathias Agopianca088332013-03-28 17:44:13 -0700802 if (SyncFeatures::getInstance().useWaitSync()) {
Jamie Gennis61e04b92012-09-09 17:48:42 -0700803 // Create an EGLSyncKHR from the current fence.
804 int fenceFd = mCurrentFence->dup();
805 if (fenceFd == -1) {
806 ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
807 return -errno;
808 }
809 EGLint attribs[] = {
810 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
811 EGL_NONE
812 };
813 EGLSyncKHR sync = eglCreateSyncKHR(dpy,
814 EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
815 if (sync == EGL_NO_SYNC_KHR) {
816 close(fenceFd);
817 ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
818 eglGetError());
819 return UNKNOWN_ERROR;
820 }
821
822 // XXX: The spec draft is inconsistent as to whether this should
823 // return an EGLint or void. Ignore the return value for now, as
824 // it's not strictly needed.
Mathias Agopian2bb71682013-03-27 17:32:41 -0700825 eglWaitSyncKHR(dpy, sync, 0);
Jamie Gennis61e04b92012-09-09 17:48:42 -0700826 EGLint eglErr = eglGetError();
827 eglDestroySyncKHR(dpy, sync);
828 if (eglErr != EGL_SUCCESS) {
829 ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
830 eglErr);
831 return UNKNOWN_ERROR;
832 }
833 } else {
Mathias Agopianea74d3b2013-05-16 18:03:22 -0700834 status_t err = mCurrentFence->waitForever(
Andy McFadden2adaf042012-12-18 09:49:45 -0800835 "GLConsumer::doGLFenceWaitLocked");
Jamie Gennis61e04b92012-09-09 17:48:42 -0700836 if (err != NO_ERROR) {
837 ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
838 return err;
839 }
840 }
841 }
842
843 return NO_ERROR;
844}
845
Andy McFadden2adaf042012-12-18 09:49:45 -0800846bool GLConsumer::isSynchronousMode() const {
Jamie Gennis59769462011-11-19 18:04:43 -0800847 Mutex::Autolock lock(mMutex);
Daniel Lamb2675792012-02-23 14:35:13 -0800848 return mBufferQueue->isSynchronousMode();
Jamie Gennis59769462011-11-19 18:04:43 -0800849}
850
Andy McFadden2adaf042012-12-18 09:49:45 -0800851void GLConsumer::freeBufferLocked(int slotIndex) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700852 ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700853 if (slotIndex == mCurrentTexture) {
854 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
855 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700856 EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
Jamie Gennis9aa74db2012-04-17 13:07:45 -0700857 if (img != EGL_NO_IMAGE_KHR) {
858 ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
859 eglDestroyImageKHR(mEglDisplay, img);
Daniel Lameae59d22012-01-22 15:26:27 -0800860 }
Jamie Gennis9fea3422012-08-07 18:03:04 -0700861 mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
862 ConsumerBase::freeBufferLocked(slotIndex);
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700863}
Daniel Lameae59d22012-01-22 15:26:27 -0800864
Andy McFadden2adaf042012-12-18 09:49:45 -0800865void GLConsumer::abandonLocked() {
Jamie Gennis9fea3422012-08-07 18:03:04 -0700866 ST_LOGV("abandonLocked");
867 mCurrentTextureBuf.clear();
868 ConsumerBase::abandonLocked();
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700869}
870
Andy McFadden2adaf042012-12-18 09:49:45 -0800871void GLConsumer::setName(const String8& name) {
Daniel Lameae59d22012-01-22 15:26:27 -0800872 Mutex::Autolock _l(mMutex);
Jamie Gennisfa28c352011-09-16 17:30:26 -0700873 mName = name;
Daniel Lamb2675792012-02-23 14:35:13 -0800874 mBufferQueue->setConsumerName(name);
875}
876
Andy McFadden2adaf042012-12-18 09:49:45 -0800877status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
Daniel Lamb2675792012-02-23 14:35:13 -0800878 Mutex::Autolock lock(mMutex);
879 return mBufferQueue->setDefaultBufferFormat(defaultFormat);
880}
881
Andy McFadden2adaf042012-12-18 09:49:45 -0800882status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
Daniel Lamb2675792012-02-23 14:35:13 -0800883 Mutex::Autolock lock(mMutex);
Eino-Ville Talvala85b21762012-04-13 15:16:31 -0700884 usage |= DEFAULT_USAGE_FLAGS;
Daniel Lamb2675792012-02-23 14:35:13 -0800885 return mBufferQueue->setConsumerUsageBits(usage);
886}
887
Andy McFadden2adaf042012-12-18 09:49:45 -0800888status_t GLConsumer::setTransformHint(uint32_t hint) {
Daniel Lamb2675792012-02-23 14:35:13 -0800889 Mutex::Autolock lock(mMutex);
890 return mBufferQueue->setTransformHint(hint);
891}
892
Andy McFadden2adaf042012-12-18 09:49:45 -0800893// Used for refactoring BufferQueue from GLConsumer
894// Should not be in final interface once users of GLConsumer are clean up.
895status_t GLConsumer::setSynchronousMode(bool enabled) {
Daniel Lamb2675792012-02-23 14:35:13 -0800896 Mutex::Autolock lock(mMutex);
897 return mBufferQueue->setSynchronousMode(enabled);
898}
899
Mathias Agopian74d211a2013-04-22 16:55:35 +0200900void GLConsumer::dumpLocked(String8& result, const char* prefix) const
Mathias Agopian68c77942011-05-09 19:08:33 -0700901{
Mathias Agopian74d211a2013-04-22 16:55:35 +0200902 result.appendFormat(
Jamie Gennis9fea3422012-08-07 18:03:04 -0700903 "%smTexName=%d mCurrentTexture=%d\n"
904 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
905 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
906 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
907 mCurrentTransform);
Mathias Agopian68c77942011-05-09 19:08:33 -0700908
Mathias Agopian74d211a2013-04-22 16:55:35 +0200909 ConsumerBase::dumpLocked(result, prefix);
Mathias Agopian68c77942011-05-09 19:08:33 -0700910}
911
Jamie Gennisf238e282011-01-09 16:33:17 -0800912static void mtxMul(float out[16], const float a[16], const float b[16]) {
913 out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
914 out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
915 out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
916 out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
917
918 out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
919 out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
920 out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
921 out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
922
923 out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
924 out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
925 out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
926 out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
927
928 out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
929 out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
930 out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
931 out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
932}
933
Jamie Gennis8ba32fa2010-12-20 11:27:26 -0800934}; // namespace android