1 /*
2 * Copyright 2019 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 #define EGL_EGLEXT_PROTOTYPES
18 #include <EGL/egl.h>
19 #include <EGL/eglext.h>
20
21 #include <gui/BufferQueue.h>
22 #include <surfacetexture/ImageConsumer.h>
23 #include <surfacetexture/SurfaceTexture.h>
24
25 // Macro for including the SurfaceTexture name in log messages
26 #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
27
28 namespace android {
29
onReleaseBufferLocked(int buf)30 void ImageConsumer::onReleaseBufferLocked(int buf) {
31 mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
32 }
33
dequeueBuffer(int * outSlotid,android_dataspace * outDataspace,HdrMetadata * outHdrMetadata,bool * outQueueEmpty,SurfaceTexture & st,SurfaceTexture_createReleaseFence createFence,SurfaceTexture_fenceWait fenceWait,void * fencePassThroughHandle)34 sp<GraphicBuffer> ImageConsumer::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
35 HdrMetadata* outHdrMetadata, bool* outQueueEmpty,
36 SurfaceTexture& st,
37 SurfaceTexture_createReleaseFence createFence,
38 SurfaceTexture_fenceWait fenceWait,
39 void* fencePassThroughHandle) {
40 BufferItem item;
41 status_t err;
42 err = st.acquireBufferLocked(&item, 0);
43 if (err != OK) {
44 if (err != BufferQueue::NO_BUFFER_AVAILABLE) {
45 IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
46 } else {
47 int slot = st.mCurrentTexture;
48 if (slot != BufferItem::INVALID_BUFFER_SLOT) {
49 *outQueueEmpty = true;
50 *outDataspace = st.mCurrentDataSpace;
51 *outSlotid = slot;
52 return st.mSlots[slot].mGraphicBuffer;
53 }
54 }
55 return nullptr;
56 }
57
58 int slot = item.mSlot;
59 *outQueueEmpty = false;
60 if (item.mFence->isValid()) {
61 // If fence is not signaled, that means frame is not ready and
62 // outQueueEmpty is set to true. By the time the fence is signaled,
63 // there may be a new buffer queued. This is a proper detection for an
64 // empty queue and it is needed to avoid infinite loop in
65 // ASurfaceTexture_dequeueBuffer (see b/159921224).
66 *outQueueEmpty = item.mFence->getStatus() == Fence::Status::Unsignaled;
67
68 // Wait on the producer fence for the buffer to be ready.
69 err = fenceWait(item.mFence->get(), fencePassThroughHandle);
70 if (err != OK) {
71 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
72 return nullptr;
73 }
74 }
75
76 // Release old buffer.
77 if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) {
78 // If needed, set the released slot's fence to guard against a producer
79 // accessing the buffer before the outstanding accesses have completed.
80 int releaseFenceId = -1;
81 EGLDisplay display = EGL_NO_DISPLAY;
82 err = createFence(st.mUseFenceSync, &mImageSlots[slot].eglFence(), &display,
83 &releaseFenceId, fencePassThroughHandle);
84 if (OK != err) {
85 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
86 return nullptr;
87 }
88
89 if (releaseFenceId != -1) {
90 sp<Fence> releaseFence(new Fence(releaseFenceId));
91 status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
92 st.mSlots[st.mCurrentTexture].mGraphicBuffer,
93 releaseFence);
94 if (err != OK) {
95 IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err);
96 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
97 return nullptr;
98 }
99 }
100
101 // Finally release the old buffer.
102 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
103 EGLSyncKHR previousFence = mImageSlots[st.mCurrentTexture].eglFence();
104 if (previousFence != EGL_NO_SYNC_KHR) {
105 // Most platforms will be using native fences, so it's unlikely that we'll ever have to
106 // process an eglFence. Ideally we can remove this code eventually. In the mean time, do
107 // our best to wait for it so the buffer stays valid, otherwise return an error to the
108 // caller.
109 //
110 // EGL_SYNC_FLUSH_COMMANDS_BIT_KHR so that we don't wait forever on a fence that hasn't
111 // shown up on the GPU yet.
112 EGLint result = eglClientWaitSyncKHR(display, previousFence,
113 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 1000000000);
114 if (result == EGL_FALSE) {
115 IMG_LOGE("dequeueBuffer: error %#x waiting for fence", eglGetError());
116 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
117 IMG_LOGE("dequeueBuffer: timeout waiting for fence");
118 }
119 eglDestroySyncKHR(display, previousFence);
120 }
121
122 status_t status = st.releaseBufferLocked(st.mCurrentTexture,
123 st.mSlots[st.mCurrentTexture].mGraphicBuffer);
124 #else
125 status_t status =
126 st.releaseBufferLocked(st.mCurrentTexture,
127 st.mSlots[st.mCurrentTexture].mGraphicBuffer, display,
128 mImageSlots[st.mCurrentTexture].eglFence());
129 #endif
130 if (status < NO_ERROR) {
131 IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status);
132 err = status;
133 // Keep going, with error raised.
134 }
135 }
136
137 // Update the state.
138 st.mCurrentTexture = slot;
139 st.mCurrentCrop = item.mCrop;
140 st.mCurrentTransform = item.mTransform;
141 st.mCurrentScalingMode = item.mScalingMode;
142 st.mCurrentTimestamp = item.mTimestamp;
143 st.mCurrentDataSpace = item.mDataSpace;
144 st.mCurrentFence = item.mFence;
145 st.mCurrentFenceTime = item.mFenceTime;
146 st.mCurrentFrameNumber = item.mFrameNumber;
147 st.computeCurrentTransformMatrixLocked();
148
149 *outDataspace = item.mDataSpace;
150 *outHdrMetadata = item.mHdrMetadata;
151 *outSlotid = slot;
152 return st.mSlots[slot].mGraphicBuffer;
153 }
154
155 } /* namespace android */
156