blob: b9930d17832272bb17aa3e52a4e0c699ec6dece3 [file] [log] [blame]
Chia-I Wuf1405182017-11-27 11:29:21 -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
17#undef LOG_TAG
18#define LOG_TAG "BufferLayerConsumer"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20//#define LOG_NDEBUG 0
21
22#include "BufferLayerConsumer.h"
23
24#include <inttypes.h>
25
26#include <EGL/egl.h>
27#include <EGL/eglext.h>
28#include <GLES2/gl2.h>
29#include <GLES2/gl2ext.h>
30#include <cutils/compiler.h>
31
32#include <hardware/hardware.h>
33
34#include <math/mat4.h>
35
36#include <gui/BufferItem.h>
37#include <gui/GLConsumer.h>
38#include <gui/ISurfaceComposer.h>
39#include <gui/SurfaceComposerClient.h>
40
41#include <private/gui/ComposerService.h>
42#include <private/gui/SyncFeatures.h>
43
44#include <utils/Log.h>
45#include <utils/String8.h>
46#include <utils/Trace.h>
47
48extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
49#define CROP_EXT_STR "EGL_ANDROID_image_crop"
50#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
51#define EGL_PROTECTED_CONTENT_EXT 0x32C0
52
53namespace android {
54
55// Macros for including the BufferLayerConsumer name in log messages
56#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
57#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
58//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
59#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
60#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
61
Chia-I Wuf1405182017-11-27 11:29:21 -080062static const mat4 mtxIdentity;
63
Chia-I Wuf1405182017-11-27 11:29:21 -080064static bool hasEglAndroidImageCropImpl() {
65 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
66 const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
67 size_t cropExtLen = strlen(CROP_EXT_STR);
68 size_t extsLen = strlen(exts);
69 bool equal = !strcmp(CROP_EXT_STR, exts);
70 bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen + 1);
71 bool atEnd = (cropExtLen + 1) < extsLen &&
72 !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen + 1));
73 bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
74 return equal || atStart || atEnd || inMiddle;
75}
76
77static bool hasEglAndroidImageCrop() {
78 // Only compute whether the extension is present once the first time this
79 // function is called.
80 static bool hasIt = hasEglAndroidImageCropImpl();
81 return hasIt;
82}
83
84static bool hasEglProtectedContentImpl() {
85 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
86 const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
87 size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
88 size_t extsLen = strlen(exts);
89 bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
90 bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
91 bool atEnd = (cropExtLen + 1) < extsLen &&
92 !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
93 bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
94 return equal || atStart || atEnd || inMiddle;
95}
96
97static bool hasEglProtectedContent() {
98 // Only compute whether the extension is present once the first time this
99 // function is called.
100 static bool hasIt = hasEglProtectedContentImpl();
101 return hasIt;
102}
103
104static bool isEglImageCroppable(const Rect& crop) {
105 return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
106}
107
108BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
109 uint32_t texTarget, bool useFenceSync,
110 bool isControlledByApp)
111 : ConsumerBase(bq, isControlledByApp),
112 mCurrentCrop(Rect::EMPTY_RECT),
113 mCurrentTransform(0),
114 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
115 mCurrentFence(Fence::NO_FENCE),
116 mCurrentTimestamp(0),
117 mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
118 mCurrentFrameNumber(0),
119 mDefaultWidth(1),
120 mDefaultHeight(1),
121 mFilteringEnabled(true),
122 mTexName(tex),
123 mUseFenceSync(useFenceSync),
124 mTexTarget(texTarget),
125 mEglDisplay(EGL_NO_DISPLAY),
126 mEglContext(EGL_NO_CONTEXT),
127 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
128 mAttached(true) {
129 BLC_LOGV("BufferLayerConsumer");
130
131 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
132
133 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
134}
135
136BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
137 bool useFenceSync, bool isControlledByApp)
138 : ConsumerBase(bq, isControlledByApp),
139 mCurrentCrop(Rect::EMPTY_RECT),
140 mCurrentTransform(0),
141 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
142 mCurrentFence(Fence::NO_FENCE),
143 mCurrentTimestamp(0),
144 mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
145 mCurrentFrameNumber(0),
146 mDefaultWidth(1),
147 mDefaultHeight(1),
148 mFilteringEnabled(true),
149 mTexName(0),
150 mUseFenceSync(useFenceSync),
151 mTexTarget(texTarget),
152 mEglDisplay(EGL_NO_DISPLAY),
153 mEglContext(EGL_NO_CONTEXT),
154 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
155 mAttached(false) {
156 BLC_LOGV("BufferLayerConsumer");
157
158 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
159
160 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
161}
162
163status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
164 Mutex::Autolock lock(mMutex);
165 if (mAbandoned) {
166 BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
167 return NO_INIT;
168 }
169 mDefaultWidth = w;
170 mDefaultHeight = h;
171 return mConsumer->setDefaultBufferSize(w, h);
172}
173
174status_t BufferLayerConsumer::updateTexImage() {
175 ATRACE_CALL();
176 BLC_LOGV("updateTexImage");
177 Mutex::Autolock lock(mMutex);
178
179 if (mAbandoned) {
180 BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
181 return NO_INIT;
182 }
183
184 // Make sure the EGL state is the same as in previous calls.
185 status_t err = checkAndUpdateEglStateLocked();
186 if (err != NO_ERROR) {
187 return err;
188 }
189
190 BufferItem item;
191
192 // Acquire the next buffer.
193 // In asynchronous mode the list is guaranteed to be one buffer
194 // deep, while in synchronous mode we use the oldest buffer.
195 err = acquireBufferLocked(&item, 0);
196 if (err != NO_ERROR) {
197 if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
198 // We always bind the texture even if we don't update its contents.
199 BLC_LOGV("updateTexImage: no buffers were available");
200 glBindTexture(mTexTarget, mTexName);
201 err = NO_ERROR;
202 } else {
203 BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
204 }
205 return err;
206 }
207
208 // Release the previous buffer.
209 err = updateAndReleaseLocked(item);
210 if (err != NO_ERROR) {
211 // We always bind the texture.
212 glBindTexture(mTexTarget, mTexName);
213 return err;
214 }
215
216 // Bind the new buffer to the GL texture, and wait until it's ready.
217 return bindTextureImageLocked();
218}
219
Chia-I Wuf1405182017-11-27 11:29:21 -0800220status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
221 uint64_t maxFrameNumber) {
222 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
223 if (err != NO_ERROR) {
224 return err;
225 }
226
227 // If item->mGraphicBuffer is not null, this buffer has not been acquired
228 // before, so any prior EglImage created is using a stale buffer. This
229 // replaces any old EglImage with a new one (using the new buffer).
230 if (item->mGraphicBuffer != NULL) {
231 int slot = item->mSlot;
232 mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
233 }
234
235 return NO_ERROR;
236}
237
238status_t BufferLayerConsumer::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer,
239 EGLDisplay display, EGLSyncKHR eglFence) {
240 // release the buffer if it hasn't already been discarded by the
241 // BufferQueue. This can happen, for example, when the producer of this
242 // buffer has reallocated the original buffer slot after this buffer
243 // was acquired.
244 status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence);
245 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
246 return err;
247}
248
249status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
250 PendingRelease* pendingRelease) {
251 status_t err = NO_ERROR;
252
253 int slot = item.mSlot;
254
255 if (!mAttached) {
256 BLC_LOGE("updateAndRelease: BufferLayerConsumer is not attached to an OpenGL "
257 "ES context");
258 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
259 return INVALID_OPERATION;
260 }
261
262 // Confirm state.
263 err = checkAndUpdateEglStateLocked();
264 if (err != NO_ERROR) {
265 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
266 return err;
267 }
268
269 // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
270 // if nessessary, for the gralloc buffer currently in the slot in
271 // ConsumerBase.
272 // We may have to do this even when item.mGraphicBuffer == NULL (which
273 // means the buffer was previously acquired).
274 err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
275 if (err != NO_ERROR) {
276 BLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
277 slot);
278 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
279 return UNKNOWN_ERROR;
280 }
281
282 // Do whatever sync ops we need to do before releasing the old slot.
283 if (slot != mCurrentTexture) {
284 err = syncForReleaseLocked(mEglDisplay);
285 if (err != NO_ERROR) {
286 // Release the buffer we just acquired. It's not safe to
287 // release the old buffer, so instead we just drop the new frame.
288 // As we are still under lock since acquireBuffer, it is safe to
289 // release by slot.
290 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
291 return err;
292 }
293 }
294
295 BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
296 mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
297 mSlots[slot].mGraphicBuffer->handle);
298
299 // Hang onto the pointer so that it isn't freed in the call to
300 // releaseBufferLocked() if we're in shared buffer mode and both buffers are
301 // the same.
302 sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
303
304 // release old buffer
305 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
306 if (pendingRelease == nullptr) {
307 status_t status =
308 releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
309 mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
310 if (status < NO_ERROR) {
311 BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
312 status);
313 err = status;
314 // keep going, with error raised [?]
315 }
316 } else {
317 pendingRelease->currentTexture = mCurrentTexture;
318 pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
319 pendingRelease->display = mEglDisplay;
320 pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
321 pendingRelease->isPending = true;
322 }
323 }
324
325 // Update the BufferLayerConsumer state.
326 mCurrentTexture = slot;
327 mCurrentTextureImage = nextTextureImage;
328 mCurrentCrop = item.mCrop;
329 mCurrentTransform = item.mTransform;
330 mCurrentScalingMode = item.mScalingMode;
331 mCurrentTimestamp = item.mTimestamp;
332 mCurrentDataSpace = item.mDataSpace;
333 mCurrentFence = item.mFence;
334 mCurrentFenceTime = item.mFenceTime;
335 mCurrentFrameNumber = item.mFrameNumber;
336
337 computeCurrentTransformMatrixLocked();
338
339 return err;
340}
341
342status_t BufferLayerConsumer::bindTextureImageLocked() {
343 if (mEglDisplay == EGL_NO_DISPLAY) {
344 ALOGE("bindTextureImage: invalid display");
345 return INVALID_OPERATION;
346 }
347
348 GLenum error;
349 while ((error = glGetError()) != GL_NO_ERROR) {
350 BLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
351 }
352
353 glBindTexture(mTexTarget, mTexName);
354 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
355 BLC_LOGE("bindTextureImage: no currently-bound texture");
356 return NO_INIT;
357 }
358
359 status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop);
360 if (err != NO_ERROR) {
361 BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
362 mCurrentTexture);
363 return UNKNOWN_ERROR;
364 }
365 mCurrentTextureImage->bindToTextureTarget(mTexTarget);
366
367 // In the rare case that the display is terminated and then initialized
368 // again, we can't detect that the display changed (it didn't), but the
369 // image is invalid. In this case, repeat the exact same steps while
370 // forcing the creation of a new image.
371 if ((error = glGetError()) != GL_NO_ERROR) {
372 glBindTexture(mTexTarget, mTexName);
373 status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop, true);
374 if (result != NO_ERROR) {
375 BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
376 mCurrentTexture);
377 return UNKNOWN_ERROR;
378 }
379 mCurrentTextureImage->bindToTextureTarget(mTexTarget);
380 if ((error = glGetError()) != GL_NO_ERROR) {
381 BLC_LOGE("bindTextureImage: error binding external image: %#04x", error);
382 return UNKNOWN_ERROR;
383 }
384 }
385
386 // Wait for the new buffer to be ready.
387 return doGLFenceWaitLocked();
388}
389
390status_t BufferLayerConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
391 EGLDisplay dpy = eglGetCurrentDisplay();
392 EGLContext ctx = eglGetCurrentContext();
393
394 if (!contextCheck) {
395 // if this is the first time we're called, mEglDisplay/mEglContext have
396 // never been set, so don't error out (below).
397 if (mEglDisplay == EGL_NO_DISPLAY) {
398 mEglDisplay = dpy;
399 }
400 if (mEglContext == EGL_NO_CONTEXT) {
401 mEglContext = ctx;
402 }
403 }
404
405 if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
406 BLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
407 return INVALID_OPERATION;
408 }
409
410 if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
411 BLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
412 return INVALID_OPERATION;
413 }
414
415 mEglDisplay = dpy;
416 mEglContext = ctx;
417 return NO_ERROR;
418}
419
420void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
421 if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
422 status_t err =
423 addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence);
424 if (err != OK) {
425 BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
426 }
427 }
428}
429
430status_t BufferLayerConsumer::detachFromContext() {
431 ATRACE_CALL();
432 BLC_LOGV("detachFromContext");
433 Mutex::Autolock lock(mMutex);
434
435 if (mAbandoned) {
436 BLC_LOGE("detachFromContext: abandoned BufferLayerConsumer");
437 return NO_INIT;
438 }
439
440 if (!mAttached) {
441 BLC_LOGE("detachFromContext: BufferLayerConsumer is not attached to a "
442 "context");
443 return INVALID_OPERATION;
444 }
445
446 EGLDisplay dpy = eglGetCurrentDisplay();
447 EGLContext ctx = eglGetCurrentContext();
448
449 if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
450 BLC_LOGE("detachFromContext: invalid current EGLDisplay");
451 return INVALID_OPERATION;
452 }
453
454 if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
455 BLC_LOGE("detachFromContext: invalid current EGLContext");
456 return INVALID_OPERATION;
457 }
458
459 if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
460 status_t err = syncForReleaseLocked(dpy);
461 if (err != OK) {
462 return err;
463 }
464
465 glDeleteTextures(1, &mTexName);
466 }
467
468 mEglDisplay = EGL_NO_DISPLAY;
469 mEglContext = EGL_NO_CONTEXT;
470 mAttached = false;
471
472 return OK;
473}
474
475status_t BufferLayerConsumer::attachToContext(uint32_t tex) {
476 ATRACE_CALL();
477 BLC_LOGV("attachToContext");
478 Mutex::Autolock lock(mMutex);
479
480 if (mAbandoned) {
481 BLC_LOGE("attachToContext: abandoned BufferLayerConsumer");
482 return NO_INIT;
483 }
484
485 if (mAttached) {
486 BLC_LOGE("attachToContext: BufferLayerConsumer is already attached to a "
487 "context");
488 return INVALID_OPERATION;
489 }
490
491 EGLDisplay dpy = eglGetCurrentDisplay();
492 EGLContext ctx = eglGetCurrentContext();
493
494 if (dpy == EGL_NO_DISPLAY) {
495 BLC_LOGE("attachToContext: invalid current EGLDisplay");
496 return INVALID_OPERATION;
497 }
498
499 if (ctx == EGL_NO_CONTEXT) {
500 BLC_LOGE("attachToContext: invalid current EGLContext");
501 return INVALID_OPERATION;
502 }
503
504 // We need to bind the texture regardless of whether there's a current
505 // buffer.
506 glBindTexture(mTexTarget, GLuint(tex));
507
508 mEglDisplay = dpy;
509 mEglContext = ctx;
510 mTexName = tex;
511 mAttached = true;
512
513 if (mCurrentTextureImage != NULL) {
514 // This may wait for a buffer a second time. This is likely required if
515 // this is a different context, since otherwise the wait could be skipped
516 // by bouncing through another context. For the same context the extra
517 // wait is redundant.
518 status_t err = bindTextureImageLocked();
519 if (err != NO_ERROR) {
520 return err;
521 }
522 }
523
524 return OK;
525}
526
527status_t BufferLayerConsumer::syncForReleaseLocked(EGLDisplay dpy) {
528 BLC_LOGV("syncForReleaseLocked");
529
530 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
531 if (SyncFeatures::getInstance().useNativeFenceSync()) {
532 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
533 if (sync == EGL_NO_SYNC_KHR) {
534 BLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
535 return UNKNOWN_ERROR;
536 }
537 glFlush();
538 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
539 eglDestroySyncKHR(dpy, sync);
540 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
541 BLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
542 "fd: %#x",
543 eglGetError());
544 return UNKNOWN_ERROR;
545 }
546 sp<Fence> fence(new Fence(fenceFd));
547 status_t err = addReleaseFenceLocked(mCurrentTexture,
548 mCurrentTextureImage->graphicBuffer(), fence);
549 if (err != OK) {
550 BLC_LOGE("syncForReleaseLocked: error adding release fence: "
551 "%s (%d)",
552 strerror(-err), err);
553 return err;
554 }
555 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
556 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
557 if (fence != EGL_NO_SYNC_KHR) {
558 // There is already a fence for the current slot. We need to
559 // wait on that before replacing it with another fence to
560 // ensure that all outstanding buffer accesses have completed
561 // before the producer accesses it.
562 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
563 if (result == EGL_FALSE) {
564 BLC_LOGE("syncForReleaseLocked: error waiting for previous "
565 "fence: %#x",
566 eglGetError());
567 return UNKNOWN_ERROR;
568 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
569 BLC_LOGE("syncForReleaseLocked: timeout waiting for previous "
570 "fence");
571 return TIMED_OUT;
572 }
573 eglDestroySyncKHR(dpy, fence);
574 }
575
576 // Create a fence for the outstanding accesses in the current
577 // OpenGL ES context.
578 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
579 if (fence == EGL_NO_SYNC_KHR) {
580 BLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
581 return UNKNOWN_ERROR;
582 }
583 glFlush();
584 mEglSlots[mCurrentTexture].mEglFence = fence;
585 }
586 }
587
588 return OK;
589}
590
591uint32_t BufferLayerConsumer::getCurrentTextureTarget() const {
592 return mTexTarget;
593}
594
595void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
596 Mutex::Autolock lock(mMutex);
597 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
598}
599
600void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
601 Mutex::Autolock lock(mMutex);
602 if (mAbandoned) {
603 BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
604 return;
605 }
606 bool needsRecompute = mFilteringEnabled != enabled;
607 mFilteringEnabled = enabled;
608
609 if (needsRecompute && mCurrentTextureImage == NULL) {
610 BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
611 }
612
613 if (needsRecompute && mCurrentTextureImage != NULL) {
614 computeCurrentTransformMatrixLocked();
615 }
616}
617
618void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
619 BLC_LOGV("computeCurrentTransformMatrixLocked");
620 sp<GraphicBuffer> buf =
621 (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
622 if (buf == nullptr) {
623 BLC_LOGD("computeCurrentTransformMatrixLocked: "
624 "mCurrentTextureImage is NULL");
625 }
626 computeTransformMatrix(mCurrentTransformMatrix, buf,
627 isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
628 mCurrentTransform, mFilteringEnabled);
629}
630
631void BufferLayerConsumer::computeTransformMatrix(float outTransform[16],
632 const sp<GraphicBuffer>& buf, const Rect& cropRect,
633 uint32_t transform, bool filtering) {
634 // Transform matrices
635 static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
636 static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
637 static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
638
639 mat4 xform;
640 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
641 xform *= mtxFlipH;
642 }
643 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
644 xform *= mtxFlipV;
645 }
646 if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
647 xform *= mtxRot90;
648 }
649
650 if (!cropRect.isEmpty()) {
651 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
652 float bufferWidth = buf->getWidth();
653 float bufferHeight = buf->getHeight();
654 float shrinkAmount = 0.0f;
655 if (filtering) {
656 // In order to prevent bilinear sampling beyond the edge of the
657 // crop rectangle we may need to shrink it by 2 texels in each
658 // dimension. Normally this would just need to take 1/2 a texel
659 // off each end, but because the chroma channels of YUV420 images
660 // are subsampled we may need to shrink the crop region by a whole
661 // texel on each side.
662 switch (buf->getPixelFormat()) {
663 case PIXEL_FORMAT_RGBA_8888:
664 case PIXEL_FORMAT_RGBX_8888:
665 case PIXEL_FORMAT_RGBA_FP16:
666 case PIXEL_FORMAT_RGBA_1010102:
667 case PIXEL_FORMAT_RGB_888:
668 case PIXEL_FORMAT_RGB_565:
669 case PIXEL_FORMAT_BGRA_8888:
670 // We know there's no subsampling of any channels, so we
671 // only need to shrink by a half a pixel.
672 shrinkAmount = 0.5;
673 break;
674
675 default:
676 // If we don't recognize the format, we must assume the
677 // worst case (that we care about), which is YUV420.
678 shrinkAmount = 1.0;
679 break;
680 }
681 }
682
683 // Only shrink the dimensions that are not the size of the buffer.
684 if (cropRect.width() < bufferWidth) {
685 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
686 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
687 }
688 if (cropRect.height() < bufferHeight) {
689 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
690 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
691 }
692
693 mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
694 xform = crop * xform;
695 }
696
697 // SurfaceFlinger expects the top of its window textures to be at a Y
698 // coordinate of 0, so BufferLayerConsumer must behave the same way. We don't
699 // want to expose this to applications, however, so we must add an
700 // additional vertical flip to the transform after all the other transforms.
701 xform = mtxFlipV * xform;
702
703 memcpy(outTransform, xform.asArray(), sizeof(xform));
704}
705
706Rect BufferLayerConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
707 uint32_t bufferHeight) {
708 Rect outCrop = crop;
709
710 uint32_t newWidth = static_cast<uint32_t>(crop.width());
711 uint32_t newHeight = static_cast<uint32_t>(crop.height());
712
713 if (newWidth * bufferHeight > newHeight * bufferWidth) {
714 newWidth = newHeight * bufferWidth / bufferHeight;
715 ALOGV("too wide: newWidth = %d", newWidth);
716 } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
717 newHeight = newWidth * bufferHeight / bufferWidth;
718 ALOGV("too tall: newHeight = %d", newHeight);
719 }
720
721 uint32_t currentWidth = static_cast<uint32_t>(crop.width());
722 uint32_t currentHeight = static_cast<uint32_t>(crop.height());
723
724 // The crop is too wide
725 if (newWidth < currentWidth) {
726 uint32_t dw = currentWidth - newWidth;
727 auto halfdw = dw / 2;
728 outCrop.left += halfdw;
729 // Not halfdw because it would subtract 1 too few when dw is odd
730 outCrop.right -= (dw - halfdw);
731 // The crop is too tall
732 } else if (newHeight < currentHeight) {
733 uint32_t dh = currentHeight - newHeight;
734 auto halfdh = dh / 2;
735 outCrop.top += halfdh;
736 // Not halfdh because it would subtract 1 too few when dh is odd
737 outCrop.bottom -= (dh - halfdh);
738 }
739
740 ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
741 outCrop.bottom);
742
743 return outCrop;
744}
745
746nsecs_t BufferLayerConsumer::getTimestamp() {
747 BLC_LOGV("getTimestamp");
748 Mutex::Autolock lock(mMutex);
749 return mCurrentTimestamp;
750}
751
752android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
753 BLC_LOGV("getCurrentDataSpace");
754 Mutex::Autolock lock(mMutex);
755 return mCurrentDataSpace;
756}
757
758uint64_t BufferLayerConsumer::getFrameNumber() {
759 BLC_LOGV("getFrameNumber");
760 Mutex::Autolock lock(mMutex);
761 return mCurrentFrameNumber;
762}
763
764sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
765 Mutex::Autolock lock(mMutex);
766
767 if (outSlot != nullptr) {
768 *outSlot = mCurrentTexture;
769 }
770
771 return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
772}
773
774Rect BufferLayerConsumer::getCurrentCrop() const {
775 Mutex::Autolock lock(mMutex);
776 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
777 ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
778 : mCurrentCrop;
779}
780
781uint32_t BufferLayerConsumer::getCurrentTransform() const {
782 Mutex::Autolock lock(mMutex);
783 return mCurrentTransform;
784}
785
786uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
787 Mutex::Autolock lock(mMutex);
788 return mCurrentScalingMode;
789}
790
791sp<Fence> BufferLayerConsumer::getCurrentFence() const {
792 Mutex::Autolock lock(mMutex);
793 return mCurrentFence;
794}
795
796std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
797 Mutex::Autolock lock(mMutex);
798 return mCurrentFenceTime;
799}
800
801status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
802 EGLDisplay dpy = eglGetCurrentDisplay();
803 EGLContext ctx = eglGetCurrentContext();
804
805 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
806 BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
807 return INVALID_OPERATION;
808 }
809
810 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
811 BLC_LOGE("doGLFenceWait: invalid current EGLContext");
812 return INVALID_OPERATION;
813 }
814
815 if (mCurrentFence->isValid()) {
816 if (SyncFeatures::getInstance().useWaitSync()) {
817 // Create an EGLSyncKHR from the current fence.
818 int fenceFd = mCurrentFence->dup();
819 if (fenceFd == -1) {
820 BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
821 return -errno;
822 }
823 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
824 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
825 if (sync == EGL_NO_SYNC_KHR) {
826 close(fenceFd);
827 BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
828 return UNKNOWN_ERROR;
829 }
830
831 // XXX: The spec draft is inconsistent as to whether this should
832 // return an EGLint or void. Ignore the return value for now, as
833 // it's not strictly needed.
834 eglWaitSyncKHR(dpy, sync, 0);
835 EGLint eglErr = eglGetError();
836 eglDestroySyncKHR(dpy, sync);
837 if (eglErr != EGL_SUCCESS) {
838 BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
839 return UNKNOWN_ERROR;
840 }
841 } else {
842 status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
843 if (err != NO_ERROR) {
844 BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
845 return err;
846 }
847 }
848 }
849
850 return NO_ERROR;
851}
852
853void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
854 BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
855 if (slotIndex == mCurrentTexture) {
856 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
857 }
858 mEglSlots[slotIndex].mEglImage.clear();
859 ConsumerBase::freeBufferLocked(slotIndex);
860}
861
862void BufferLayerConsumer::abandonLocked() {
863 BLC_LOGV("abandonLocked");
864 mCurrentTextureImage.clear();
865 ConsumerBase::abandonLocked();
866}
867
868status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
869 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
870}
871
872void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
873 result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
874 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
875 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
876 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
877 mCurrentTransform);
878
879 ConsumerBase::dumpLocked(result, prefix);
880}
881
882BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
883 : mGraphicBuffer(graphicBuffer),
884 mEglImage(EGL_NO_IMAGE_KHR),
885 mEglDisplay(EGL_NO_DISPLAY),
886 mCropRect(Rect::EMPTY_RECT) {}
887
888BufferLayerConsumer::EglImage::~EglImage() {
889 if (mEglImage != EGL_NO_IMAGE_KHR) {
890 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
891 ALOGE("~EglImage: eglDestroyImageKHR failed");
892 }
893 eglTerminate(mEglDisplay);
894 }
895}
896
897status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, const Rect& cropRect,
898 bool forceCreation) {
899 // If there's an image and it's no longer valid, destroy it.
900 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
901 bool displayInvalid = mEglDisplay != eglDisplay;
902 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
903 if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
904 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
905 ALOGE("createIfNeeded: eglDestroyImageKHR failed");
906 }
907 eglTerminate(mEglDisplay);
908 mEglImage = EGL_NO_IMAGE_KHR;
909 mEglDisplay = EGL_NO_DISPLAY;
910 }
911
912 // If there's no image, create one.
913 if (mEglImage == EGL_NO_IMAGE_KHR) {
914 mEglDisplay = eglDisplay;
915 mCropRect = cropRect;
916 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
917 }
918
919 // Fail if we can't create a valid image.
920 if (mEglImage == EGL_NO_IMAGE_KHR) {
921 mEglDisplay = EGL_NO_DISPLAY;
922 mCropRect.makeInvalid();
923 const sp<GraphicBuffer>& buffer = mGraphicBuffer;
924 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
925 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
926 buffer->getPixelFormat());
927 return UNKNOWN_ERROR;
928 }
929
930 return OK;
931}
932
933void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
934 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
935}
936
937EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
938 const sp<GraphicBuffer>& graphicBuffer,
939 const Rect& crop) {
940 EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
941 const bool createProtectedImage =
942 (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
943 EGLint attrs[] = {
944 EGL_IMAGE_PRESERVED_KHR,
945 EGL_TRUE,
946 EGL_IMAGE_CROP_LEFT_ANDROID,
947 crop.left,
948 EGL_IMAGE_CROP_TOP_ANDROID,
949 crop.top,
950 EGL_IMAGE_CROP_RIGHT_ANDROID,
951 crop.right,
952 EGL_IMAGE_CROP_BOTTOM_ANDROID,
953 crop.bottom,
954 createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
955 createProtectedImage ? EGL_TRUE : EGL_NONE,
956 EGL_NONE,
957 };
958 if (!crop.isValid()) {
959 // No crop rect to set, so leave the crop out of the attrib array. Make
960 // sure to propagate the protected content attrs if they are set.
961 attrs[2] = attrs[10];
962 attrs[3] = attrs[11];
963 attrs[4] = EGL_NONE;
964 } else if (!isEglImageCroppable(crop)) {
965 // The crop rect is not at the origin, so we can't set the crop on the
966 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
967 // extension. In the future we can add a layered extension that
968 // removes this restriction if there is hardware that can support it.
969 attrs[2] = attrs[10];
970 attrs[3] = attrs[11];
971 attrs[4] = EGL_NONE;
972 }
973 eglInitialize(dpy, 0, 0);
974 EGLImageKHR image =
975 eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
976 if (image == EGL_NO_IMAGE_KHR) {
977 EGLint error = eglGetError();
978 ALOGE("error creating EGLImage: %#x", error);
979 eglTerminate(dpy);
980 }
981 return image;
982}
983
984}; // namespace android