blob: 9ade402139cd1f8ef461098abe3d0b0b2942a134 [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 }
419 computeTransformMatrix(mCurrentTransformMatrix, buf,
420 isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
421 mCurrentTransform, mFilteringEnabled);
422}
423
424void BufferLayerConsumer::computeTransformMatrix(float outTransform[16],
425 const sp<GraphicBuffer>& buf, const Rect& cropRect,
426 uint32_t transform, bool filtering) {
427 // Transform matrices
428 static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
429 static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
430 static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
431
432 mat4 xform;
433 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
434 xform *= mtxFlipH;
435 }
436 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
437 xform *= mtxFlipV;
438 }
439 if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
440 xform *= mtxRot90;
441 }
442
443 if (!cropRect.isEmpty()) {
444 float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
445 float bufferWidth = buf->getWidth();
446 float bufferHeight = buf->getHeight();
447 float shrinkAmount = 0.0f;
448 if (filtering) {
449 // In order to prevent bilinear sampling beyond the edge of the
450 // crop rectangle we may need to shrink it by 2 texels in each
451 // dimension. Normally this would just need to take 1/2 a texel
452 // off each end, but because the chroma channels of YUV420 images
453 // are subsampled we may need to shrink the crop region by a whole
454 // texel on each side.
455 switch (buf->getPixelFormat()) {
456 case PIXEL_FORMAT_RGBA_8888:
457 case PIXEL_FORMAT_RGBX_8888:
458 case PIXEL_FORMAT_RGBA_FP16:
459 case PIXEL_FORMAT_RGBA_1010102:
460 case PIXEL_FORMAT_RGB_888:
461 case PIXEL_FORMAT_RGB_565:
462 case PIXEL_FORMAT_BGRA_8888:
463 // We know there's no subsampling of any channels, so we
464 // only need to shrink by a half a pixel.
465 shrinkAmount = 0.5;
466 break;
467
468 default:
469 // If we don't recognize the format, we must assume the
470 // worst case (that we care about), which is YUV420.
471 shrinkAmount = 1.0;
472 break;
473 }
474 }
475
476 // Only shrink the dimensions that are not the size of the buffer.
477 if (cropRect.width() < bufferWidth) {
478 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
479 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
480 }
481 if (cropRect.height() < bufferHeight) {
482 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
483 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
484 }
485
486 mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
487 xform = crop * xform;
488 }
489
490 // SurfaceFlinger expects the top of its window textures to be at a Y
491 // coordinate of 0, so BufferLayerConsumer must behave the same way. We don't
492 // want to expose this to applications, however, so we must add an
493 // additional vertical flip to the transform after all the other transforms.
494 xform = mtxFlipV * xform;
495
496 memcpy(outTransform, xform.asArray(), sizeof(xform));
497}
498
499Rect BufferLayerConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
500 uint32_t bufferHeight) {
501 Rect outCrop = crop;
502
503 uint32_t newWidth = static_cast<uint32_t>(crop.width());
504 uint32_t newHeight = static_cast<uint32_t>(crop.height());
505
506 if (newWidth * bufferHeight > newHeight * bufferWidth) {
507 newWidth = newHeight * bufferWidth / bufferHeight;
508 ALOGV("too wide: newWidth = %d", newWidth);
509 } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
510 newHeight = newWidth * bufferHeight / bufferWidth;
511 ALOGV("too tall: newHeight = %d", newHeight);
512 }
513
514 uint32_t currentWidth = static_cast<uint32_t>(crop.width());
515 uint32_t currentHeight = static_cast<uint32_t>(crop.height());
516
517 // The crop is too wide
518 if (newWidth < currentWidth) {
519 uint32_t dw = currentWidth - newWidth;
520 auto halfdw = dw / 2;
521 outCrop.left += halfdw;
522 // Not halfdw because it would subtract 1 too few when dw is odd
523 outCrop.right -= (dw - halfdw);
524 // The crop is too tall
525 } else if (newHeight < currentHeight) {
526 uint32_t dh = currentHeight - newHeight;
527 auto halfdh = dh / 2;
528 outCrop.top += halfdh;
529 // Not halfdh because it would subtract 1 too few when dh is odd
530 outCrop.bottom -= (dh - halfdh);
531 }
532
533 ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
534 outCrop.bottom);
535
536 return outCrop;
537}
538
539nsecs_t BufferLayerConsumer::getTimestamp() {
540 BLC_LOGV("getTimestamp");
541 Mutex::Autolock lock(mMutex);
542 return mCurrentTimestamp;
543}
544
545android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
546 BLC_LOGV("getCurrentDataSpace");
547 Mutex::Autolock lock(mMutex);
548 return mCurrentDataSpace;
549}
550
551uint64_t BufferLayerConsumer::getFrameNumber() {
552 BLC_LOGV("getFrameNumber");
553 Mutex::Autolock lock(mMutex);
554 return mCurrentFrameNumber;
555}
556
557sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
558 Mutex::Autolock lock(mMutex);
559
560 if (outSlot != nullptr) {
561 *outSlot = mCurrentTexture;
562 }
563
564 return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
565}
566
567Rect BufferLayerConsumer::getCurrentCrop() const {
568 Mutex::Autolock lock(mMutex);
569 return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
570 ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
571 : mCurrentCrop;
572}
573
574uint32_t BufferLayerConsumer::getCurrentTransform() const {
575 Mutex::Autolock lock(mMutex);
576 return mCurrentTransform;
577}
578
579uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
580 Mutex::Autolock lock(mMutex);
581 return mCurrentScalingMode;
582}
583
584sp<Fence> BufferLayerConsumer::getCurrentFence() const {
585 Mutex::Autolock lock(mMutex);
586 return mCurrentFence;
587}
588
589std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
590 Mutex::Autolock lock(mMutex);
591 return mCurrentFenceTime;
592}
593
594status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
595 EGLDisplay dpy = eglGetCurrentDisplay();
596 EGLContext ctx = eglGetCurrentContext();
597
598 if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
599 BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
600 return INVALID_OPERATION;
601 }
602
603 if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
604 BLC_LOGE("doGLFenceWait: invalid current EGLContext");
605 return INVALID_OPERATION;
606 }
607
608 if (mCurrentFence->isValid()) {
609 if (SyncFeatures::getInstance().useWaitSync()) {
610 // Create an EGLSyncKHR from the current fence.
611 int fenceFd = mCurrentFence->dup();
612 if (fenceFd == -1) {
613 BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
614 return -errno;
615 }
616 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
617 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
618 if (sync == EGL_NO_SYNC_KHR) {
619 close(fenceFd);
620 BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
621 return UNKNOWN_ERROR;
622 }
623
624 // XXX: The spec draft is inconsistent as to whether this should
625 // return an EGLint or void. Ignore the return value for now, as
626 // it's not strictly needed.
627 eglWaitSyncKHR(dpy, sync, 0);
628 EGLint eglErr = eglGetError();
629 eglDestroySyncKHR(dpy, sync);
630 if (eglErr != EGL_SUCCESS) {
631 BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
632 return UNKNOWN_ERROR;
633 }
634 } else {
635 status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
636 if (err != NO_ERROR) {
637 BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
638 return err;
639 }
640 }
641 }
642
643 return NO_ERROR;
644}
645
646void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
647 BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
648 if (slotIndex == mCurrentTexture) {
649 mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
650 }
651 mEglSlots[slotIndex].mEglImage.clear();
652 ConsumerBase::freeBufferLocked(slotIndex);
653}
654
655void BufferLayerConsumer::abandonLocked() {
656 BLC_LOGV("abandonLocked");
657 mCurrentTextureImage.clear();
658 ConsumerBase::abandonLocked();
659}
660
661status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
662 return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
663}
664
665void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
666 result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
667 "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
668 prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
669 mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
670 mCurrentTransform);
671
672 ConsumerBase::dumpLocked(result, prefix);
673}
674
675BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
676 : mGraphicBuffer(graphicBuffer),
677 mEglImage(EGL_NO_IMAGE_KHR),
678 mEglDisplay(EGL_NO_DISPLAY),
679 mCropRect(Rect::EMPTY_RECT) {}
680
681BufferLayerConsumer::EglImage::~EglImage() {
682 if (mEglImage != EGL_NO_IMAGE_KHR) {
683 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
684 ALOGE("~EglImage: eglDestroyImageKHR failed");
685 }
686 eglTerminate(mEglDisplay);
687 }
688}
689
Chia-I Wuc91077c2017-11-27 13:32:04 -0800690status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
691 const Rect& cropRect) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800692 // If there's an image and it's no longer valid, destroy it.
693 bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
694 bool displayInvalid = mEglDisplay != eglDisplay;
695 bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
Chia-I Wuc91077c2017-11-27 13:32:04 -0800696 if (haveImage && (displayInvalid || cropInvalid)) {
Chia-I Wuf1405182017-11-27 11:29:21 -0800697 if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
698 ALOGE("createIfNeeded: eglDestroyImageKHR failed");
699 }
700 eglTerminate(mEglDisplay);
701 mEglImage = EGL_NO_IMAGE_KHR;
702 mEglDisplay = EGL_NO_DISPLAY;
703 }
704
705 // If there's no image, create one.
706 if (mEglImage == EGL_NO_IMAGE_KHR) {
707 mEglDisplay = eglDisplay;
708 mCropRect = cropRect;
709 mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
710 }
711
712 // Fail if we can't create a valid image.
713 if (mEglImage == EGL_NO_IMAGE_KHR) {
714 mEglDisplay = EGL_NO_DISPLAY;
715 mCropRect.makeInvalid();
716 const sp<GraphicBuffer>& buffer = mGraphicBuffer;
717 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
718 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
719 buffer->getPixelFormat());
720 return UNKNOWN_ERROR;
721 }
722
723 return OK;
724}
725
726void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
727 glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
728}
729
730EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
731 const sp<GraphicBuffer>& graphicBuffer,
732 const Rect& crop) {
733 EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
734 const bool createProtectedImage =
735 (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
736 EGLint attrs[] = {
737 EGL_IMAGE_PRESERVED_KHR,
738 EGL_TRUE,
739 EGL_IMAGE_CROP_LEFT_ANDROID,
740 crop.left,
741 EGL_IMAGE_CROP_TOP_ANDROID,
742 crop.top,
743 EGL_IMAGE_CROP_RIGHT_ANDROID,
744 crop.right,
745 EGL_IMAGE_CROP_BOTTOM_ANDROID,
746 crop.bottom,
747 createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
748 createProtectedImage ? EGL_TRUE : EGL_NONE,
749 EGL_NONE,
750 };
751 if (!crop.isValid()) {
752 // No crop rect to set, so leave the crop out of the attrib array. Make
753 // sure to propagate the protected content attrs if they are set.
754 attrs[2] = attrs[10];
755 attrs[3] = attrs[11];
756 attrs[4] = EGL_NONE;
757 } else if (!isEglImageCroppable(crop)) {
758 // The crop rect is not at the origin, so we can't set the crop on the
759 // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
760 // extension. In the future we can add a layered extension that
761 // removes this restriction if there is hardware that can support it.
762 attrs[2] = attrs[10];
763 attrs[3] = attrs[11];
764 attrs[4] = EGL_NONE;
765 }
766 eglInitialize(dpy, 0, 0);
767 EGLImageKHR image =
768 eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
769 if (image == EGL_NO_IMAGE_KHR) {
770 EGLint error = eglGetError();
771 ALOGE("error creating EGLImage: %#x", error);
772 eglTerminate(dpy);
773 }
774 return image;
775}
776
777}; // namespace android