blob: 8519a70cc46ebc28ed4aed99411dc5e77419ec8a [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),
Chia-I Wuc91077c2017-11-27 13:32:04 -0800127 mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800128 BLC_LOGV("BufferLayerConsumer");
129
130 memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
131
132 mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
133}
134
135status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
136 Mutex::Autolock lock(mMutex);
137 if (mAbandoned) {
138 BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
139 return NO_INIT;
140 }
141 mDefaultWidth = w;
142 mDefaultHeight = h;
143 return mConsumer->setDefaultBufferSize(w, h);
144}
145
146status_t BufferLayerConsumer::updateTexImage() {
147 ATRACE_CALL();
148 BLC_LOGV("updateTexImage");
149 Mutex::Autolock lock(mMutex);
150
151 if (mAbandoned) {
152 BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
153 return NO_INIT;
154 }
155
156 // Make sure the EGL state is the same as in previous calls.
157 status_t err = checkAndUpdateEglStateLocked();
158 if (err != NO_ERROR) {
159 return err;
160 }
161
162 BufferItem item;
163
164 // Acquire the next buffer.
165 // In asynchronous mode the list is guaranteed to be one buffer
166 // deep, while in synchronous mode we use the oldest buffer.
167 err = acquireBufferLocked(&item, 0);
168 if (err != NO_ERROR) {
169 if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
170 // We always bind the texture even if we don't update its contents.
171 BLC_LOGV("updateTexImage: no buffers were available");
172 glBindTexture(mTexTarget, mTexName);
173 err = NO_ERROR;
174 } else {
175 BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
176 }
177 return err;
178 }
179
180 // Release the previous buffer.
181 err = updateAndReleaseLocked(item);
182 if (err != NO_ERROR) {
183 // We always bind the texture.
184 glBindTexture(mTexTarget, mTexName);
185 return err;
186 }
187
188 // Bind the new buffer to the GL texture, and wait until it's ready.
189 return bindTextureImageLocked();
190}
191
Chia-I Wuf1405182017-11-27 11:29:21 -0800192status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
193 uint64_t maxFrameNumber) {
194 status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
195 if (err != NO_ERROR) {
196 return err;
197 }
198
199 // If item->mGraphicBuffer is not null, this buffer has not been acquired
200 // before, so any prior EglImage created is using a stale buffer. This
201 // replaces any old EglImage with a new one (using the new buffer).
202 if (item->mGraphicBuffer != NULL) {
203 int slot = item->mSlot;
204 mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
205 }
206
207 return NO_ERROR;
208}
209
210status_t BufferLayerConsumer::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer,
211 EGLDisplay display, EGLSyncKHR eglFence) {
212 // release the buffer if it hasn't already been discarded by the
213 // BufferQueue. This can happen, for example, when the producer of this
214 // buffer has reallocated the original buffer slot after this buffer
215 // was acquired.
216 status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence);
217 mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
218 return err;
219}
220
221status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
222 PendingRelease* pendingRelease) {
223 status_t err = NO_ERROR;
224
225 int slot = item.mSlot;
226
Chia-I Wuf1405182017-11-27 11:29:21 -0800227 // Confirm state.
228 err = checkAndUpdateEglStateLocked();
229 if (err != NO_ERROR) {
230 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
231 return err;
232 }
233
234 // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
235 // if nessessary, for the gralloc buffer currently in the slot in
236 // ConsumerBase.
237 // We may have to do this even when item.mGraphicBuffer == NULL (which
238 // means the buffer was previously acquired).
239 err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
240 if (err != NO_ERROR) {
241 BLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
242 slot);
243 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
244 return UNKNOWN_ERROR;
245 }
246
247 // Do whatever sync ops we need to do before releasing the old slot.
248 if (slot != mCurrentTexture) {
249 err = syncForReleaseLocked(mEglDisplay);
250 if (err != NO_ERROR) {
251 // Release the buffer we just acquired. It's not safe to
252 // release the old buffer, so instead we just drop the new frame.
253 // As we are still under lock since acquireBuffer, it is safe to
254 // release by slot.
255 releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
256 return err;
257 }
258 }
259
260 BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
261 mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
262 mSlots[slot].mGraphicBuffer->handle);
263
264 // Hang onto the pointer so that it isn't freed in the call to
265 // releaseBufferLocked() if we're in shared buffer mode and both buffers are
266 // the same.
267 sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
268
269 // release old buffer
270 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
271 if (pendingRelease == nullptr) {
272 status_t status =
273 releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
274 mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
275 if (status < NO_ERROR) {
276 BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
277 status);
278 err = status;
279 // keep going, with error raised [?]
280 }
281 } else {
282 pendingRelease->currentTexture = mCurrentTexture;
283 pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
284 pendingRelease->display = mEglDisplay;
285 pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
286 pendingRelease->isPending = true;
287 }
288 }
289
290 // Update the BufferLayerConsumer state.
291 mCurrentTexture = slot;
292 mCurrentTextureImage = nextTextureImage;
293 mCurrentCrop = item.mCrop;
294 mCurrentTransform = item.mTransform;
295 mCurrentScalingMode = item.mScalingMode;
296 mCurrentTimestamp = item.mTimestamp;
297 mCurrentDataSpace = item.mDataSpace;
298 mCurrentFence = item.mFence;
299 mCurrentFenceTime = item.mFenceTime;
300 mCurrentFrameNumber = item.mFrameNumber;
301
302 computeCurrentTransformMatrixLocked();
303
304 return err;
305}
306
307status_t BufferLayerConsumer::bindTextureImageLocked() {
308 if (mEglDisplay == EGL_NO_DISPLAY) {
309 ALOGE("bindTextureImage: invalid display");
310 return INVALID_OPERATION;
311 }
312
313 GLenum error;
314 while ((error = glGetError()) != GL_NO_ERROR) {
315 BLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
316 }
317
318 glBindTexture(mTexTarget, mTexName);
319 if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
320 BLC_LOGE("bindTextureImage: no currently-bound texture");
321 return NO_INIT;
322 }
323
324 status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop);
325 if (err != NO_ERROR) {
326 BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
327 mCurrentTexture);
328 return UNKNOWN_ERROR;
329 }
330 mCurrentTextureImage->bindToTextureTarget(mTexTarget);
331
Chia-I Wuf1405182017-11-27 11:29:21 -0800332 // Wait for the new buffer to be ready.
333 return doGLFenceWaitLocked();
334}
335
Chia-I Wuc91077c2017-11-27 13:32:04 -0800336status_t BufferLayerConsumer::checkAndUpdateEglStateLocked() {
Chia-I Wuf1405182017-11-27 11:29:21 -0800337 EGLDisplay dpy = eglGetCurrentDisplay();
338 EGLContext ctx = eglGetCurrentContext();
339
Chia-I Wuc91077c2017-11-27 13:32:04 -0800340 // if this is the first time we're called, mEglDisplay/mEglContext have
341 // never been set, so don't error out (below).
342 if (mEglDisplay == EGL_NO_DISPLAY) {
343 mEglDisplay = dpy;
344 }
345 if (mEglContext == EGL_NO_CONTEXT) {
346 mEglContext = ctx;
Chia-I Wuf1405182017-11-27 11:29:21 -0800347 }
348
349 if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
350 BLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
351 return INVALID_OPERATION;
352 }
353
354 if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
355 BLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
356 return INVALID_OPERATION;
357 }
358
Chia-I Wuf1405182017-11-27 11:29:21 -0800359 return NO_ERROR;
360}
361
362void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
363 if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
364 status_t err =
365 addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence);
366 if (err != OK) {
367 BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
368 }
369 }
370}
371
Chia-I Wuf1405182017-11-27 11:29:21 -0800372status_t BufferLayerConsumer::syncForReleaseLocked(EGLDisplay dpy) {
373 BLC_LOGV("syncForReleaseLocked");
374
375 if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
376 if (SyncFeatures::getInstance().useNativeFenceSync()) {
377 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
378 if (sync == EGL_NO_SYNC_KHR) {
379 BLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
380 return UNKNOWN_ERROR;
381 }
382 glFlush();
383 int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
384 eglDestroySyncKHR(dpy, sync);
385 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
386 BLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
387 "fd: %#x",
388 eglGetError());
389 return UNKNOWN_ERROR;
390 }
391 sp<Fence> fence(new Fence(fenceFd));
392 status_t err = addReleaseFenceLocked(mCurrentTexture,
393 mCurrentTextureImage->graphicBuffer(), fence);
394 if (err != OK) {
395 BLC_LOGE("syncForReleaseLocked: error adding release fence: "
396 "%s (%d)",
397 strerror(-err), err);
398 return err;
399 }
400 } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
401 EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
402 if (fence != EGL_NO_SYNC_KHR) {
403 // There is already a fence for the current slot. We need to
404 // wait on that before replacing it with another fence to
405 // ensure that all outstanding buffer accesses have completed
406 // before the producer accesses it.
407 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
408 if (result == EGL_FALSE) {
409 BLC_LOGE("syncForReleaseLocked: error waiting for previous "
410 "fence: %#x",
411 eglGetError());
412 return UNKNOWN_ERROR;
413 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
414 BLC_LOGE("syncForReleaseLocked: timeout waiting for previous "
415 "fence");
416 return TIMED_OUT;
417 }
418 eglDestroySyncKHR(dpy, fence);
419 }
420
421 // Create a fence for the outstanding accesses in the current
422 // OpenGL ES context.
423 fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
424 if (fence == EGL_NO_SYNC_KHR) {
425 BLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
426 return UNKNOWN_ERROR;
427 }
428 glFlush();
429 mEglSlots[mCurrentTexture].mEglFence = fence;
430 }
431 }
432
433 return OK;
434}
435
436uint32_t BufferLayerConsumer::getCurrentTextureTarget() const {
437 return mTexTarget;
438}
439
440void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
441 Mutex::Autolock lock(mMutex);
442 memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
443}
444
445void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
446 Mutex::Autolock lock(mMutex);
447 if (mAbandoned) {
448 BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
449 return;
450 }
451 bool needsRecompute = mFilteringEnabled != enabled;
452 mFilteringEnabled = enabled;
453
454 if (needsRecompute && mCurrentTextureImage == NULL) {
455 BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
456 }
457
458 if (needsRecompute && mCurrentTextureImage != NULL) {
459 computeCurrentTransformMatrixLocked();
460 }
461}
462
463void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
464 BLC_LOGV("computeCurrentTransformMatrixLocked");
465 sp<GraphicBuffer> buf =
466 (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
467 if (buf == nullptr) {
468 BLC_LOGD("computeCurrentTransformMatrixLocked: "
469 "mCurrentTextureImage is NULL");
470 }
471 computeTransformMatrix(mCurrentTransformMatrix, buf,
472 isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
473 mCurrentTransform, mFilteringEnabled);
474}
475
476void BufferLayerConsumer::computeTransformMatrix(float outTransform[16],
477 const sp<GraphicBuffer>& buf, const Rect& cropRect,
478 uint32_t transform, bool filtering) {
479 // Transform matrices
480 static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
481 static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
482 static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
483
484 mat4 xform;
485 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
486 xform *= mtxFlipH;
487 }
488 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
489 xform *= mtxFlipV;
490 }
491 if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
492 xform *= mtxRot90;
493 }
494
495 if (!cropRect.isEmpty()) {
496 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
497 float bufferWidth = buf->getWidth();
498 float bufferHeight = buf->getHeight();
499 float shrinkAmount = 0.0f;
500 if (filtering) {
501 // In order to prevent bilinear sampling beyond the edge of the
502 // crop rectangle we may need to shrink it by 2 texels in each
503 // dimension. Normally this would just need to take 1/2 a texel
504 // off each end, but because the chroma channels of YUV420 images
505 // are subsampled we may need to shrink the crop region by a whole
506 // texel on each side.
507 switch (buf->getPixelFormat()) {
508 case PIXEL_FORMAT_RGBA_8888:
509 case PIXEL_FORMAT_RGBX_8888:
510 case PIXEL_FORMAT_RGBA_FP16:
511 case PIXEL_FORMAT_RGBA_1010102:
512 case PIXEL_FORMAT_RGB_888:
513 case PIXEL_FORMAT_RGB_565:
514 case PIXEL_FORMAT_BGRA_8888:
515 // We know there's no subsampling of any channels, so we
516 // only need to shrink by a half a pixel.
517 shrinkAmount = 0.5;
518 break;
519
520 default:
521 // If we don't recognize the format, we must assume the
522 // worst case (that we care about), which is YUV420.
523 shrinkAmount = 1.0;
524 break;
525 }
526 }
527
528 // Only shrink the dimensions that are not the size of the buffer.
529 if (cropRect.width() < bufferWidth) {
530 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
531 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
532 }
533 if (cropRect.height() < bufferHeight) {
534 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
535 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
536 }
537
538 mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
539 xform = crop * xform;
540 }
541
542 // SurfaceFlinger expects the top of its window textures to be at a Y
543 // coordinate of 0, so BufferLayerConsumer must behave the same way. We don't
544 // want to expose this to applications, however, so we must add an
545 // additional vertical flip to the transform after all the other transforms.
546 xform = mtxFlipV * xform;
547
548 memcpy(outTransform, xform.asArray(), sizeof(xform));
549}
550
551Rect BufferLayerConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
552 uint32_t bufferHeight) {
553 Rect outCrop = crop;
554
555 uint32_t newWidth = static_cast<uint32_t>(crop.width());
556 uint32_t newHeight = static_cast<uint32_t>(crop.height());
557
558 if (newWidth * bufferHeight > newHeight * bufferWidth) {
559 newWidth = newHeight * bufferWidth / bufferHeight;
560 ALOGV("too wide: newWidth = %d", newWidth);
561 } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
562 newHeight = newWidth * bufferHeight / bufferWidth;
563 ALOGV("too tall: newHeight = %d", newHeight);
564 }
565
566 uint32_t currentWidth = static_cast<uint32_t>(crop.width());
567 uint32_t currentHeight = static_cast<uint32_t>(crop.height());
568
569 // The crop is too wide
570 if (newWidth < currentWidth) {
571 uint32_t dw = currentWidth - newWidth;
572 auto halfdw = dw / 2;
573 outCrop.left += halfdw;
574 // Not halfdw because it would subtract 1 too few when dw is odd
575 outCrop.right -= (dw - halfdw);
576 // The crop is too tall
577 } else if (newHeight < currentHeight) {
578 uint32_t dh = currentHeight - newHeight;
579 auto halfdh = dh / 2;
580 outCrop.top += halfdh;
581 // Not halfdh because it would subtract 1 too few when dh is odd
582 outCrop.bottom -= (dh - halfdh);
583 }
584
585 ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
586 outCrop.bottom);
587
588 return outCrop;
589}
590
591nsecs_t BufferLayerConsumer::getTimestamp() {
592 BLC_LOGV("getTimestamp");
593 Mutex::Autolock lock(mMutex);
594 return mCurrentTimestamp;
595}
596
597android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
598 BLC_LOGV("getCurrentDataSpace");
599 Mutex::Autolock lock(mMutex);
600 return mCurrentDataSpace;
601}
602
603uint64_t BufferLayerConsumer::getFrameNumber() {
604 BLC_LOGV("getFrameNumber");
605 Mutex::Autolock lock(mMutex);
606 return mCurrentFrameNumber;
607}
608
609sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
610 Mutex::Autolock lock(mMutex);
611
612 if (outSlot != nullptr) {
613 *outSlot = mCurrentTexture;
614 }
615
616 return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
617}
618
619Rect BufferLayerConsumer::getCurrentCrop() const {
620 Mutex::Autolock lock(mMutex);
621 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
622 ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
623 : mCurrentCrop;
624}
625
626uint32_t BufferLayerConsumer::getCurrentTransform() const {
627 Mutex::Autolock lock(mMutex);
628 return mCurrentTransform;
629}
630
631uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
632 Mutex::Autolock lock(mMutex);
633 return mCurrentScalingMode;
634}
635
636sp<Fence> BufferLayerConsumer::getCurrentFence() const {
637 Mutex::Autolock lock(mMutex);
638 return mCurrentFence;
639}
640
641std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
642 Mutex::Autolock lock(mMutex);
643 return mCurrentFenceTime;
644}
645
646status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
647 EGLDisplay dpy = eglGetCurrentDisplay();
648 EGLContext ctx = eglGetCurrentContext();
649
650 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
651 BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
652 return INVALID_OPERATION;
653 }
654
655 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
656 BLC_LOGE("doGLFenceWait: invalid current EGLContext");
657 return INVALID_OPERATION;
658 }
659
660 if (mCurrentFence->isValid()) {
661 if (SyncFeatures::getInstance().useWaitSync()) {
662 // Create an EGLSyncKHR from the current fence.
663 int fenceFd = mCurrentFence->dup();
664 if (fenceFd == -1) {
665 BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
666 return -errno;
667 }
668 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
669 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
670 if (sync == EGL_NO_SYNC_KHR) {
671 close(fenceFd);
672 BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
673 return UNKNOWN_ERROR;
674 }
675
676 // XXX: The spec draft is inconsistent as to whether this should
677 // return an EGLint or void. Ignore the return value for now, as
678 // it's not strictly needed.
679 eglWaitSyncKHR(dpy, sync, 0);
680 EGLint eglErr = eglGetError();
681 eglDestroySyncKHR(dpy, sync);
682 if (eglErr != EGL_SUCCESS) {
683 BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
684 return UNKNOWN_ERROR;
685 }
686 } else {
687 status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
688 if (err != NO_ERROR) {
689 BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
690 return err;
691 }
692 }
693 }
694
695 return NO_ERROR;
696}
697
698void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
699 BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
700 if (slotIndex == mCurrentTexture) {
701 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
702 }
703 mEglSlots[slotIndex].mEglImage.clear();
704 ConsumerBase::freeBufferLocked(slotIndex);
705}
706
707void BufferLayerConsumer::abandonLocked() {
708 BLC_LOGV("abandonLocked");
709 mCurrentTextureImage.clear();
710 ConsumerBase::abandonLocked();
711}
712
713status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
714 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
715}
716
717void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
718 result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
719 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
720 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
721 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
722 mCurrentTransform);
723
724 ConsumerBase::dumpLocked(result, prefix);
725}
726
727BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
728 : mGraphicBuffer(graphicBuffer),
729 mEglImage(EGL_NO_IMAGE_KHR),
730 mEglDisplay(EGL_NO_DISPLAY),
731 mCropRect(Rect::EMPTY_RECT) {}
732
733BufferLayerConsumer::EglImage::~EglImage() {
734 if (mEglImage != EGL_NO_IMAGE_KHR) {
735 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
736 ALOGE("~EglImage: eglDestroyImageKHR failed");
737 }
738 eglTerminate(mEglDisplay);
739 }
740}
741
Chia-I Wuc91077c2017-11-27 13:32:04 -0800742status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
743 const Rect& cropRect) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800744 // If there's an image and it's no longer valid, destroy it.
745 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
746 bool displayInvalid = mEglDisplay != eglDisplay;
747 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
Chia-I Wuc91077c2017-11-27 13:32:04 -0800748 if (haveImage && (displayInvalid || cropInvalid)) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800749 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
750 ALOGE("createIfNeeded: eglDestroyImageKHR failed");
751 }
752 eglTerminate(mEglDisplay);
753 mEglImage = EGL_NO_IMAGE_KHR;
754 mEglDisplay = EGL_NO_DISPLAY;
755 }
756
757 // If there's no image, create one.
758 if (mEglImage == EGL_NO_IMAGE_KHR) {
759 mEglDisplay = eglDisplay;
760 mCropRect = cropRect;
761 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
762 }
763
764 // Fail if we can't create a valid image.
765 if (mEglImage == EGL_NO_IMAGE_KHR) {
766 mEglDisplay = EGL_NO_DISPLAY;
767 mCropRect.makeInvalid();
768 const sp<GraphicBuffer>& buffer = mGraphicBuffer;
769 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
770 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
771 buffer->getPixelFormat());
772 return UNKNOWN_ERROR;
773 }
774
775 return OK;
776}
777
778void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
779 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
780}
781
782EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
783 const sp<GraphicBuffer>& graphicBuffer,
784 const Rect& crop) {
785 EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
786 const bool createProtectedImage =
787 (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
788 EGLint attrs[] = {
789 EGL_IMAGE_PRESERVED_KHR,
790 EGL_TRUE,
791 EGL_IMAGE_CROP_LEFT_ANDROID,
792 crop.left,
793 EGL_IMAGE_CROP_TOP_ANDROID,
794 crop.top,
795 EGL_IMAGE_CROP_RIGHT_ANDROID,
796 crop.right,
797 EGL_IMAGE_CROP_BOTTOM_ANDROID,
798 crop.bottom,
799 createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
800 createProtectedImage ? EGL_TRUE : EGL_NONE,
801 EGL_NONE,
802 };
803 if (!crop.isValid()) {
804 // No crop rect to set, so leave the crop out of the attrib array. Make
805 // sure to propagate the protected content attrs if they are set.
806 attrs[2] = attrs[10];
807 attrs[3] = attrs[11];
808 attrs[4] = EGL_NONE;
809 } else if (!isEglImageCroppable(crop)) {
810 // The crop rect is not at the origin, so we can't set the crop on the
811 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
812 // extension. In the future we can add a layered extension that
813 // removes this restriction if there is hardware that can support it.
814 attrs[2] = attrs[10];
815 attrs[3] = attrs[11];
816 attrs[4] = EGL_NONE;
817 }
818 eglInitialize(dpy, 0, 0);
819 EGLImageKHR image =
820 eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
821 if (image == EGL_NO_IMAGE_KHR) {
822 EGLint error = eglGetError();
823 ALOGE("error creating EGLImage: %#x", error);
824 eglTerminate(dpy);
825 }
826 return image;
827}
828
829}; // namespace android