blob: 482de1665ff939c9f41266f6e80e71580b79789c [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
425Rect BufferLayerConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
426 uint32_t bufferHeight) {
427 Rect outCrop = crop;
428
429 uint32_t newWidth = static_cast<uint32_t>(crop.width());
430 uint32_t newHeight = static_cast<uint32_t>(crop.height());
431
432 if (newWidth * bufferHeight > newHeight * bufferWidth) {
433 newWidth = newHeight * bufferWidth / bufferHeight;
434 ALOGV("too wide: newWidth = %d", newWidth);
435 } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
436 newHeight = newWidth * bufferHeight / bufferWidth;
437 ALOGV("too tall: newHeight = %d", newHeight);
438 }
439
440 uint32_t currentWidth = static_cast<uint32_t>(crop.width());
441 uint32_t currentHeight = static_cast<uint32_t>(crop.height());
442
443 // The crop is too wide
444 if (newWidth < currentWidth) {
445 uint32_t dw = currentWidth - newWidth;
446 auto halfdw = dw / 2;
447 outCrop.left += halfdw;
448 // Not halfdw because it would subtract 1 too few when dw is odd
449 outCrop.right -= (dw - halfdw);
450 // The crop is too tall
451 } else if (newHeight < currentHeight) {
452 uint32_t dh = currentHeight - newHeight;
453 auto halfdh = dh / 2;
454 outCrop.top += halfdh;
455 // Not halfdh because it would subtract 1 too few when dh is odd
456 outCrop.bottom -= (dh - halfdh);
457 }
458
459 ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
460 outCrop.bottom);
461
462 return outCrop;
463}
464
465nsecs_t BufferLayerConsumer::getTimestamp() {
466 BLC_LOGV("getTimestamp");
467 Mutex::Autolock lock(mMutex);
468 return mCurrentTimestamp;
469}
470
471android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
472 BLC_LOGV("getCurrentDataSpace");
473 Mutex::Autolock lock(mMutex);
474 return mCurrentDataSpace;
475}
476
477uint64_t BufferLayerConsumer::getFrameNumber() {
478 BLC_LOGV("getFrameNumber");
479 Mutex::Autolock lock(mMutex);
480 return mCurrentFrameNumber;
481}
482
483sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
484 Mutex::Autolock lock(mMutex);
485
486 if (outSlot != nullptr) {
487 *outSlot = mCurrentTexture;
488 }
489
490 return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
491}
492
493Rect BufferLayerConsumer::getCurrentCrop() const {
494 Mutex::Autolock lock(mMutex);
495 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
496 ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
497 : mCurrentCrop;
498}
499
500uint32_t BufferLayerConsumer::getCurrentTransform() const {
501 Mutex::Autolock lock(mMutex);
502 return mCurrentTransform;
503}
504
505uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
506 Mutex::Autolock lock(mMutex);
507 return mCurrentScalingMode;
508}
509
510sp<Fence> BufferLayerConsumer::getCurrentFence() const {
511 Mutex::Autolock lock(mMutex);
512 return mCurrentFence;
513}
514
515std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
516 Mutex::Autolock lock(mMutex);
517 return mCurrentFenceTime;
518}
519
520status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
521 EGLDisplay dpy = eglGetCurrentDisplay();
522 EGLContext ctx = eglGetCurrentContext();
523
524 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
525 BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
526 return INVALID_OPERATION;
527 }
528
529 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
530 BLC_LOGE("doGLFenceWait: invalid current EGLContext");
531 return INVALID_OPERATION;
532 }
533
534 if (mCurrentFence->isValid()) {
535 if (SyncFeatures::getInstance().useWaitSync()) {
536 // Create an EGLSyncKHR from the current fence.
537 int fenceFd = mCurrentFence->dup();
538 if (fenceFd == -1) {
539 BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
540 return -errno;
541 }
542 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
543 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
544 if (sync == EGL_NO_SYNC_KHR) {
545 close(fenceFd);
546 BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
547 return UNKNOWN_ERROR;
548 }
549
550 // XXX: The spec draft is inconsistent as to whether this should
551 // return an EGLint or void. Ignore the return value for now, as
552 // it's not strictly needed.
553 eglWaitSyncKHR(dpy, sync, 0);
554 EGLint eglErr = eglGetError();
555 eglDestroySyncKHR(dpy, sync);
556 if (eglErr != EGL_SUCCESS) {
557 BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
558 return UNKNOWN_ERROR;
559 }
560 } else {
561 status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
562 if (err != NO_ERROR) {
563 BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
564 return err;
565 }
566 }
567 }
568
569 return NO_ERROR;
570}
571
572void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
573 BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
574 if (slotIndex == mCurrentTexture) {
575 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
576 }
577 mEglSlots[slotIndex].mEglImage.clear();
578 ConsumerBase::freeBufferLocked(slotIndex);
579}
580
581void BufferLayerConsumer::abandonLocked() {
582 BLC_LOGV("abandonLocked");
583 mCurrentTextureImage.clear();
584 ConsumerBase::abandonLocked();
585}
586
587status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
588 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
589}
590
591void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
592 result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
593 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
594 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
595 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
596 mCurrentTransform);
597
598 ConsumerBase::dumpLocked(result, prefix);
599}
600
601BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
602 : mGraphicBuffer(graphicBuffer),
603 mEglImage(EGL_NO_IMAGE_KHR),
604 mEglDisplay(EGL_NO_DISPLAY),
605 mCropRect(Rect::EMPTY_RECT) {}
606
607BufferLayerConsumer::EglImage::~EglImage() {
608 if (mEglImage != EGL_NO_IMAGE_KHR) {
609 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
610 ALOGE("~EglImage: eglDestroyImageKHR failed");
611 }
612 eglTerminate(mEglDisplay);
613 }
614}
615
Chia-I Wuc91077c2017-11-27 13:32:04 -0800616status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
617 const Rect& cropRect) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800618 // If there's an image and it's no longer valid, destroy it.
619 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
620 bool displayInvalid = mEglDisplay != eglDisplay;
621 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
Chia-I Wuc91077c2017-11-27 13:32:04 -0800622 if (haveImage && (displayInvalid || cropInvalid)) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800623 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
624 ALOGE("createIfNeeded: eglDestroyImageKHR failed");
625 }
626 eglTerminate(mEglDisplay);
627 mEglImage = EGL_NO_IMAGE_KHR;
628 mEglDisplay = EGL_NO_DISPLAY;
629 }
630
631 // If there's no image, create one.
632 if (mEglImage == EGL_NO_IMAGE_KHR) {
633 mEglDisplay = eglDisplay;
634 mCropRect = cropRect;
635 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
636 }
637
638 // Fail if we can't create a valid image.
639 if (mEglImage == EGL_NO_IMAGE_KHR) {
640 mEglDisplay = EGL_NO_DISPLAY;
641 mCropRect.makeInvalid();
642 const sp<GraphicBuffer>& buffer = mGraphicBuffer;
643 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
644 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
645 buffer->getPixelFormat());
646 return UNKNOWN_ERROR;
647 }
648
649 return OK;
650}
651
652void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
653 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
654}
655
656EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
657 const sp<GraphicBuffer>& graphicBuffer,
658 const Rect& crop) {
659 EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
660 const bool createProtectedImage =
661 (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
662 EGLint attrs[] = {
663 EGL_IMAGE_PRESERVED_KHR,
664 EGL_TRUE,
665 EGL_IMAGE_CROP_LEFT_ANDROID,
666 crop.left,
667 EGL_IMAGE_CROP_TOP_ANDROID,
668 crop.top,
669 EGL_IMAGE_CROP_RIGHT_ANDROID,
670 crop.right,
671 EGL_IMAGE_CROP_BOTTOM_ANDROID,
672 crop.bottom,
673 createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
674 createProtectedImage ? EGL_TRUE : EGL_NONE,
675 EGL_NONE,
676 };
677 if (!crop.isValid()) {
678 // No crop rect to set, so leave the crop out of the attrib array. Make
679 // sure to propagate the protected content attrs if they are set.
680 attrs[2] = attrs[10];
681 attrs[3] = attrs[11];
682 attrs[4] = EGL_NONE;
683 } else if (!isEglImageCroppable(crop)) {
684 // The crop rect is not at the origin, so we can't set the crop on the
685 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
686 // extension. In the future we can add a layered extension that
687 // removes this restriction if there is hardware that can support it.
688 attrs[2] = attrs[10];
689 attrs[3] = attrs[11];
690 attrs[4] = EGL_NONE;
691 }
692 eglInitialize(dpy, 0, 0);
693 EGLImageKHR image =
694 eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
695 if (image == EGL_NO_IMAGE_KHR) {
696 EGLint error = eglGetError();
697 ALOGE("error creating EGLImage: %#x", error);
698 eglTerminate(dpy);
699 }
700 return image;
701}
702
703}; // namespace android