• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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