blob: 938a330de799896a9c62722d1656dbaa1a443d32 [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
Chia-I Wubd854bf2017-11-27 13:41:26 -0800108BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex)
109 : ConsumerBase(bq, false),
Chia-I Wuf1405182017-11-27 11:29:21 -0800110 mCurrentCrop(Rect::EMPTY_RECT),
111 mCurrentTransform(0),
112 mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
113 mCurrentFence(Fence::NO_FENCE),
114 mCurrentTimestamp(0),
115 mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
116 mCurrentFrameNumber(0),
117 mDefaultWidth(1),
118 mDefaultHeight(1),
119 mFilteringEnabled(true),
120 mTexName(tex),
Chia-I Wuf1405182017-11-27 11:29:21 -0800121 mEglDisplay(EGL_NO_DISPLAY),
122 mEglContext(EGL_NO_CONTEXT),
Chia-I Wuc91077c2017-11-27 13:32:04 -0800123 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800124 BLC_LOGV("BufferLayerConsumer");
125
126 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
127
128 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
129}
130
131status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
132 Mutex::Autolock lock(mMutex);
133 if (mAbandoned) {
134 BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
135 return NO_INIT;
136 }
137 mDefaultWidth = w;
138 mDefaultHeight = h;
139 return mConsumer->setDefaultBufferSize(w, h);
140}
141
142status_t BufferLayerConsumer::updateTexImage() {
143 ATRACE_CALL();
144 BLC_LOGV("updateTexImage");
145 Mutex::Autolock lock(mMutex);
146
147 if (mAbandoned) {
148 BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
149 return NO_INIT;
150 }
151
152 // Make sure the EGL state is the same as in previous calls.
153 status_t err = checkAndUpdateEglStateLocked();
154 if (err != NO_ERROR) {
155 return err;
156 }
157
158 BufferItem item;
159
160 // Acquire the next buffer.
161 // In asynchronous mode the list is guaranteed to be one buffer
162 // deep, while in synchronous mode we use the oldest buffer.
163 err = acquireBufferLocked(&item, 0);
164 if (err != NO_ERROR) {
165 if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
166 // We always bind the texture even if we don't update its contents.
167 BLC_LOGV("updateTexImage: no buffers were available");
Chia-I Wubd854bf2017-11-27 13:41:26 -0800168 glBindTexture(sTexTarget, mTexName);
Chia-I Wuf1405182017-11-27 11:29:21 -0800169 err = NO_ERROR;
170 } else {
171 BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
172 }
173 return err;
174 }
175
176 // Release the previous buffer.
177 err = updateAndReleaseLocked(item);
178 if (err != NO_ERROR) {
179 // We always bind the texture.
Chia-I Wubd854bf2017-11-27 13:41:26 -0800180 glBindTexture(sTexTarget, mTexName);
Chia-I Wuf1405182017-11-27 11:29:21 -0800181 return err;
182 }
183
184 // Bind the new buffer to the GL texture, and wait until it's ready.
185 return bindTextureImageLocked();
186}
187
Chia-I Wuf1405182017-11-27 11:29:21 -0800188status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
189 uint64_t maxFrameNumber) {
190 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
191 if (err != NO_ERROR) {
192 return err;
193 }
194
195 // If item->mGraphicBuffer is not null, this buffer has not been acquired
196 // before, so any prior EglImage created is using a stale buffer. This
197 // replaces any old EglImage with a new one (using the new buffer).
198 if (item->mGraphicBuffer != NULL) {
199 int slot = item->mSlot;
200 mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
201 }
202
203 return NO_ERROR;
204}
205
Chia-I Wuf1405182017-11-27 11:29:21 -0800206status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
207 PendingRelease* pendingRelease) {
208 status_t err = NO_ERROR;
209
210 int slot = item.mSlot;
211
Chia-I Wuf1405182017-11-27 11:29:21 -0800212 // Confirm state.
213 err = checkAndUpdateEglStateLocked();
214 if (err != NO_ERROR) {
Chia-I Wu6aff69b2017-11-27 14:08:48 -0800215 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
Chia-I Wuf1405182017-11-27 11:29:21 -0800216 return err;
217 }
218
219 // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
220 // if nessessary, for the gralloc buffer currently in the slot in
221 // ConsumerBase.
222 // We may have to do this even when item.mGraphicBuffer == NULL (which
223 // means the buffer was previously acquired).
224 err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
225 if (err != NO_ERROR) {
226 BLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
227 slot);
Chia-I Wu6aff69b2017-11-27 14:08:48 -0800228 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
Chia-I Wuf1405182017-11-27 11:29:21 -0800229 return UNKNOWN_ERROR;
230 }
231
232 // Do whatever sync ops we need to do before releasing the old slot.
233 if (slot != mCurrentTexture) {
234 err = syncForReleaseLocked(mEglDisplay);
235 if (err != NO_ERROR) {
236 // Release the buffer we just acquired. It's not safe to
237 // release the old buffer, so instead we just drop the new frame.
238 // As we are still under lock since acquireBuffer, it is safe to
239 // release by slot.
Chia-I Wu6aff69b2017-11-27 14:08:48 -0800240 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
Chia-I Wuf1405182017-11-27 11:29:21 -0800241 return err;
242 }
243 }
244
245 BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
246 mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
247 mSlots[slot].mGraphicBuffer->handle);
248
249 // Hang onto the pointer so that it isn't freed in the call to
250 // releaseBufferLocked() if we're in shared buffer mode and both buffers are
251 // the same.
252 sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
253
254 // release old buffer
255 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
256 if (pendingRelease == nullptr) {
257 status_t status =
Chia-I Wu6aff69b2017-11-27 14:08:48 -0800258 releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
Chia-I Wuf1405182017-11-27 11:29:21 -0800259 if (status < NO_ERROR) {
260 BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
261 status);
262 err = status;
263 // keep going, with error raised [?]
264 }
265 } else {
266 pendingRelease->currentTexture = mCurrentTexture;
267 pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
Chia-I Wuf1405182017-11-27 11:29:21 -0800268 pendingRelease->isPending = true;
269 }
270 }
271
272 // Update the BufferLayerConsumer state.
273 mCurrentTexture = slot;
274 mCurrentTextureImage = nextTextureImage;
275 mCurrentCrop = item.mCrop;
276 mCurrentTransform = item.mTransform;
277 mCurrentScalingMode = item.mScalingMode;
278 mCurrentTimestamp = item.mTimestamp;
279 mCurrentDataSpace = item.mDataSpace;
280 mCurrentFence = item.mFence;
281 mCurrentFenceTime = item.mFenceTime;
282 mCurrentFrameNumber = item.mFrameNumber;
283
284 computeCurrentTransformMatrixLocked();
285
286 return err;
287}
288
289status_t BufferLayerConsumer::bindTextureImageLocked() {
290 if (mEglDisplay == EGL_NO_DISPLAY) {
291 ALOGE("bindTextureImage: invalid display");
292 return INVALID_OPERATION;
293 }
294
295 GLenum error;
296 while ((error = glGetError()) != GL_NO_ERROR) {
297 BLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
298 }
299
Chia-I Wubd854bf2017-11-27 13:41:26 -0800300 glBindTexture(sTexTarget, mTexName);
Chia-I Wuf1405182017-11-27 11:29:21 -0800301 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
302 BLC_LOGE("bindTextureImage: no currently-bound texture");
303 return NO_INIT;
304 }
305
306 status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop);
307 if (err != NO_ERROR) {
308 BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
309 mCurrentTexture);
310 return UNKNOWN_ERROR;
311 }
Chia-I Wubd854bf2017-11-27 13:41:26 -0800312 mCurrentTextureImage->bindToTextureTarget(sTexTarget);
Chia-I Wuf1405182017-11-27 11:29:21 -0800313
Chia-I Wuf1405182017-11-27 11:29:21 -0800314 // Wait for the new buffer to be ready.
315 return doGLFenceWaitLocked();
316}
317
Chia-I Wuc91077c2017-11-27 13:32:04 -0800318status_t BufferLayerConsumer::checkAndUpdateEglStateLocked() {
Chia-I Wuf1405182017-11-27 11:29:21 -0800319 EGLDisplay dpy = eglGetCurrentDisplay();
320 EGLContext ctx = eglGetCurrentContext();
321
Chia-I Wuc91077c2017-11-27 13:32:04 -0800322 // if this is the first time we're called, mEglDisplay/mEglContext have
323 // never been set, so don't error out (below).
324 if (mEglDisplay == EGL_NO_DISPLAY) {
325 mEglDisplay = dpy;
326 }
327 if (mEglContext == EGL_NO_CONTEXT) {
328 mEglContext = ctx;
Chia-I Wuf1405182017-11-27 11:29:21 -0800329 }
330
331 if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
332 BLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
333 return INVALID_OPERATION;
334 }
335
336 if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
337 BLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
338 return INVALID_OPERATION;
339 }
340
Chia-I Wuf1405182017-11-27 11:29:21 -0800341 return NO_ERROR;
342}
343
344void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
345 if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
346 status_t err =
347 addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence);
348 if (err != OK) {
349 BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
350 }
351 }
352}
353
Chia-I Wuf1405182017-11-27 11:29:21 -0800354status_t BufferLayerConsumer::syncForReleaseLocked(EGLDisplay dpy) {
355 BLC_LOGV("syncForReleaseLocked");
356
357 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
358 if (SyncFeatures::getInstance().useNativeFenceSync()) {
359 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
360 if (sync == EGL_NO_SYNC_KHR) {
361 BLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
362 return UNKNOWN_ERROR;
363 }
364 glFlush();
365 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
366 eglDestroySyncKHR(dpy, sync);
367 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
368 BLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
369 "fd: %#x",
370 eglGetError());
371 return UNKNOWN_ERROR;
372 }
373 sp<Fence> fence(new Fence(fenceFd));
374 status_t err = addReleaseFenceLocked(mCurrentTexture,
375 mCurrentTextureImage->graphicBuffer(), fence);
376 if (err != OK) {
377 BLC_LOGE("syncForReleaseLocked: error adding release fence: "
378 "%s (%d)",
379 strerror(-err), err);
380 return err;
381 }
Chia-I Wuf1405182017-11-27 11:29:21 -0800382 }
383 }
384
385 return OK;
386}
387
Chia-I Wuf1405182017-11-27 11:29:21 -0800388void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
389 Mutex::Autolock lock(mMutex);
390 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
391}
392
393void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
394 Mutex::Autolock lock(mMutex);
395 if (mAbandoned) {
396 BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
397 return;
398 }
399 bool needsRecompute = mFilteringEnabled != enabled;
400 mFilteringEnabled = enabled;
401
402 if (needsRecompute && mCurrentTextureImage == NULL) {
403 BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
404 }
405
406 if (needsRecompute && mCurrentTextureImage != NULL) {
407 computeCurrentTransformMatrixLocked();
408 }
409}
410
411void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
412 BLC_LOGV("computeCurrentTransformMatrixLocked");
413 sp<GraphicBuffer> buf =
414 (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
415 if (buf == nullptr) {
416 BLC_LOGD("computeCurrentTransformMatrixLocked: "
417 "mCurrentTextureImage is NULL");
418 }
Chia-I Wu243b74a2017-11-27 14:24:14 -0800419 GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf,
420 isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT
421 : mCurrentCrop,
422 mCurrentTransform, mFilteringEnabled);
Chia-I Wuf1405182017-11-27 11:29:21 -0800423}
424
Chia-I Wuf1405182017-11-27 11:29:21 -0800425nsecs_t BufferLayerConsumer::getTimestamp() {
426 BLC_LOGV("getTimestamp");
427 Mutex::Autolock lock(mMutex);
428 return mCurrentTimestamp;
429}
430
431android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
432 BLC_LOGV("getCurrentDataSpace");
433 Mutex::Autolock lock(mMutex);
434 return mCurrentDataSpace;
435}
436
437uint64_t BufferLayerConsumer::getFrameNumber() {
438 BLC_LOGV("getFrameNumber");
439 Mutex::Autolock lock(mMutex);
440 return mCurrentFrameNumber;
441}
442
443sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
444 Mutex::Autolock lock(mMutex);
445
446 if (outSlot != nullptr) {
447 *outSlot = mCurrentTexture;
448 }
449
450 return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
451}
452
453Rect BufferLayerConsumer::getCurrentCrop() const {
454 Mutex::Autolock lock(mMutex);
455 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
Chia-I Wue1e11872017-12-01 09:21:59 -0800456 ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
Chia-I Wuf1405182017-11-27 11:29:21 -0800457 : mCurrentCrop;
458}
459
460uint32_t BufferLayerConsumer::getCurrentTransform() const {
461 Mutex::Autolock lock(mMutex);
462 return mCurrentTransform;
463}
464
465uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
466 Mutex::Autolock lock(mMutex);
467 return mCurrentScalingMode;
468}
469
470sp<Fence> BufferLayerConsumer::getCurrentFence() const {
471 Mutex::Autolock lock(mMutex);
472 return mCurrentFence;
473}
474
475std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
476 Mutex::Autolock lock(mMutex);
477 return mCurrentFenceTime;
478}
479
480status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
481 EGLDisplay dpy = eglGetCurrentDisplay();
482 EGLContext ctx = eglGetCurrentContext();
483
484 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
485 BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
486 return INVALID_OPERATION;
487 }
488
489 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
490 BLC_LOGE("doGLFenceWait: invalid current EGLContext");
491 return INVALID_OPERATION;
492 }
493
494 if (mCurrentFence->isValid()) {
495 if (SyncFeatures::getInstance().useWaitSync()) {
496 // Create an EGLSyncKHR from the current fence.
497 int fenceFd = mCurrentFence->dup();
498 if (fenceFd == -1) {
499 BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
500 return -errno;
501 }
502 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
503 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
504 if (sync == EGL_NO_SYNC_KHR) {
505 close(fenceFd);
506 BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
507 return UNKNOWN_ERROR;
508 }
509
510 // XXX: The spec draft is inconsistent as to whether this should
511 // return an EGLint or void. Ignore the return value for now, as
512 // it's not strictly needed.
513 eglWaitSyncKHR(dpy, sync, 0);
514 EGLint eglErr = eglGetError();
515 eglDestroySyncKHR(dpy, sync);
516 if (eglErr != EGL_SUCCESS) {
517 BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
518 return UNKNOWN_ERROR;
519 }
520 } else {
521 status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
522 if (err != NO_ERROR) {
523 BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
524 return err;
525 }
526 }
527 }
528
529 return NO_ERROR;
530}
531
532void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
533 BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
534 if (slotIndex == mCurrentTexture) {
535 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
536 }
537 mEglSlots[slotIndex].mEglImage.clear();
538 ConsumerBase::freeBufferLocked(slotIndex);
539}
540
541void BufferLayerConsumer::abandonLocked() {
542 BLC_LOGV("abandonLocked");
543 mCurrentTextureImage.clear();
544 ConsumerBase::abandonLocked();
545}
546
547status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
548 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
549}
550
551void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
552 result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
553 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
554 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
555 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
556 mCurrentTransform);
557
558 ConsumerBase::dumpLocked(result, prefix);
559}
560
561BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
562 : mGraphicBuffer(graphicBuffer),
563 mEglImage(EGL_NO_IMAGE_KHR),
564 mEglDisplay(EGL_NO_DISPLAY),
565 mCropRect(Rect::EMPTY_RECT) {}
566
567BufferLayerConsumer::EglImage::~EglImage() {
568 if (mEglImage != EGL_NO_IMAGE_KHR) {
569 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
570 ALOGE("~EglImage: eglDestroyImageKHR failed");
571 }
572 eglTerminate(mEglDisplay);
573 }
574}
575
Chia-I Wuc91077c2017-11-27 13:32:04 -0800576status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
577 const Rect& cropRect) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800578 // If there's an image and it's no longer valid, destroy it.
579 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
580 bool displayInvalid = mEglDisplay != eglDisplay;
581 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
Chia-I Wuc91077c2017-11-27 13:32:04 -0800582 if (haveImage && (displayInvalid || cropInvalid)) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800583 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
584 ALOGE("createIfNeeded: eglDestroyImageKHR failed");
585 }
586 eglTerminate(mEglDisplay);
587 mEglImage = EGL_NO_IMAGE_KHR;
588 mEglDisplay = EGL_NO_DISPLAY;
589 }
590
591 // If there's no image, create one.
592 if (mEglImage == EGL_NO_IMAGE_KHR) {
593 mEglDisplay = eglDisplay;
594 mCropRect = cropRect;
595 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
596 }
597
598 // Fail if we can't create a valid image.
599 if (mEglImage == EGL_NO_IMAGE_KHR) {
600 mEglDisplay = EGL_NO_DISPLAY;
601 mCropRect.makeInvalid();
602 const sp<GraphicBuffer>& buffer = mGraphicBuffer;
603 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
604 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
605 buffer->getPixelFormat());
606 return UNKNOWN_ERROR;
607 }
608
609 return OK;
610}
611
612void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
613 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
614}
615
616EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
617 const sp<GraphicBuffer>& graphicBuffer,
618 const Rect& crop) {
619 EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
620 const bool createProtectedImage =
621 (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
622 EGLint attrs[] = {
623 EGL_IMAGE_PRESERVED_KHR,
624 EGL_TRUE,
625 EGL_IMAGE_CROP_LEFT_ANDROID,
626 crop.left,
627 EGL_IMAGE_CROP_TOP_ANDROID,
628 crop.top,
629 EGL_IMAGE_CROP_RIGHT_ANDROID,
630 crop.right,
631 EGL_IMAGE_CROP_BOTTOM_ANDROID,
632 crop.bottom,
633 createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
634 createProtectedImage ? EGL_TRUE : EGL_NONE,
635 EGL_NONE,
636 };
637 if (!crop.isValid()) {
638 // No crop rect to set, so leave the crop out of the attrib array. Make
639 // sure to propagate the protected content attrs if they are set.
640 attrs[2] = attrs[10];
641 attrs[3] = attrs[11];
642 attrs[4] = EGL_NONE;
643 } else if (!isEglImageCroppable(crop)) {
644 // The crop rect is not at the origin, so we can't set the crop on the
645 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
646 // extension. In the future we can add a layered extension that
647 // removes this restriction if there is hardware that can support it.
648 attrs[2] = attrs[10];
649 attrs[3] = attrs[11];
650 attrs[4] = EGL_NONE;
651 }
652 eglInitialize(dpy, 0, 0);
653 EGLImageKHR image =
654 eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
655 if (image == EGL_NO_IMAGE_KHR) {
656 EGLint error = eglGetError();
657 ALOGE("error creating EGLImage: %#x", error);
658 eglTerminate(dpy);
659 }
660 return image;
661}
662
663}; // namespace android