xref: /aosp_15_r20/frameworks/native/libs/nativedisplay/surfacetexture/EGLConsumer.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define GL_GLEXT_PROTOTYPES
18*38e8c45fSAndroid Build Coastguard Worker #define EGL_EGLEXT_PROTOTYPES
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <EGL/egl.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <EGL/eglext.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <GLES2/gl2.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <GLES2/gl2ext.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <cutils/compiler.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <gui/BufferItem.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <gui/BufferQueue.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <surfacetexture/EGLConsumer.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <surfacetexture/SurfaceTexture.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <private/gui/SyncFeatures.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <utils/String8.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
36*38e8c45fSAndroid Build Coastguard Worker #define EGL_PROTECTED_CONTENT_EXT 0x32C0
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker namespace android {
39*38e8c45fSAndroid Build Coastguard Worker 
40*38e8c45fSAndroid Build Coastguard Worker // Macros for including the SurfaceTexture name in log messages
41*38e8c45fSAndroid Build Coastguard Worker #define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
42*38e8c45fSAndroid Build Coastguard Worker #define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
43*38e8c45fSAndroid Build Coastguard Worker #define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
44*38e8c45fSAndroid Build Coastguard Worker #define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__)
45*38e8c45fSAndroid Build Coastguard Worker 
46*38e8c45fSAndroid Build Coastguard Worker static const struct {
47*38e8c45fSAndroid Build Coastguard Worker     uint32_t width, height;
48*38e8c45fSAndroid Build Coastguard Worker     char const* bits;
49*38e8c45fSAndroid Build Coastguard Worker } kDebugData = {15, 12,
50*38e8c45fSAndroid Build Coastguard Worker                 "_______________"
51*38e8c45fSAndroid Build Coastguard Worker                 "_______________"
52*38e8c45fSAndroid Build Coastguard Worker                 "_____XX_XX_____"
53*38e8c45fSAndroid Build Coastguard Worker                 "__X_X_____X_X__"
54*38e8c45fSAndroid Build Coastguard Worker                 "__X_XXXXXXX_X__"
55*38e8c45fSAndroid Build Coastguard Worker                 "__XXXXXXXXXXX__"
56*38e8c45fSAndroid Build Coastguard Worker                 "___XX_XXX_XX___"
57*38e8c45fSAndroid Build Coastguard Worker                 "____XXXXXXX____"
58*38e8c45fSAndroid Build Coastguard Worker                 "_____X___X_____"
59*38e8c45fSAndroid Build Coastguard Worker                 "____X_____X____"
60*38e8c45fSAndroid Build Coastguard Worker                 "_______________"
61*38e8c45fSAndroid Build Coastguard Worker                 "_______________"};
62*38e8c45fSAndroid Build Coastguard Worker 
63*38e8c45fSAndroid Build Coastguard Worker Mutex EGLConsumer::sStaticInitLock;
64*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer;
65*38e8c45fSAndroid Build Coastguard Worker 
hasEglProtectedContentImpl()66*38e8c45fSAndroid Build Coastguard Worker static bool hasEglProtectedContentImpl() {
67*38e8c45fSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
68*38e8c45fSAndroid Build Coastguard Worker     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
69*38e8c45fSAndroid Build Coastguard Worker     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
70*38e8c45fSAndroid Build Coastguard Worker     size_t extsLen = strlen(exts);
71*38e8c45fSAndroid Build Coastguard Worker     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
72*38e8c45fSAndroid Build Coastguard Worker     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
73*38e8c45fSAndroid Build Coastguard Worker     bool atEnd = (cropExtLen + 1) < extsLen &&
74*38e8c45fSAndroid Build Coastguard Worker             !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
75*38e8c45fSAndroid Build Coastguard Worker     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
76*38e8c45fSAndroid Build Coastguard Worker     return equal || atStart || atEnd || inMiddle;
77*38e8c45fSAndroid Build Coastguard Worker }
78*38e8c45fSAndroid Build Coastguard Worker 
hasEglProtectedContent()79*38e8c45fSAndroid Build Coastguard Worker static bool hasEglProtectedContent() {
80*38e8c45fSAndroid Build Coastguard Worker     // Only compute whether the extension is present once the first time this
81*38e8c45fSAndroid Build Coastguard Worker     // function is called.
82*38e8c45fSAndroid Build Coastguard Worker     static bool hasIt = hasEglProtectedContentImpl();
83*38e8c45fSAndroid Build Coastguard Worker     return hasIt;
84*38e8c45fSAndroid Build Coastguard Worker }
85*38e8c45fSAndroid Build Coastguard Worker 
EGLConsumer()86*38e8c45fSAndroid Build Coastguard Worker EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {}
87*38e8c45fSAndroid Build Coastguard Worker 
updateTexImage(SurfaceTexture & st)88*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::updateTexImage(SurfaceTexture& st) {
89*38e8c45fSAndroid Build Coastguard Worker     // Make sure the EGL state is the same as in previous calls.
90*38e8c45fSAndroid Build Coastguard Worker     status_t err = checkAndUpdateEglStateLocked(st);
91*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
92*38e8c45fSAndroid Build Coastguard Worker         return err;
93*38e8c45fSAndroid Build Coastguard Worker     }
94*38e8c45fSAndroid Build Coastguard Worker 
95*38e8c45fSAndroid Build Coastguard Worker     BufferItem item;
96*38e8c45fSAndroid Build Coastguard Worker 
97*38e8c45fSAndroid Build Coastguard Worker     // Acquire the next buffer.
98*38e8c45fSAndroid Build Coastguard Worker     // In asynchronous mode the list is guaranteed to be one buffer
99*38e8c45fSAndroid Build Coastguard Worker     // deep, while in synchronous mode we use the oldest buffer.
100*38e8c45fSAndroid Build Coastguard Worker     err = st.acquireBufferLocked(&item, 0);
101*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
102*38e8c45fSAndroid Build Coastguard Worker         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
103*38e8c45fSAndroid Build Coastguard Worker             // We always bind the texture even if we don't update its contents.
104*38e8c45fSAndroid Build Coastguard Worker             EGC_LOGV("updateTexImage: no buffers were available");
105*38e8c45fSAndroid Build Coastguard Worker             glBindTexture(st.mTexTarget, st.mTexName);
106*38e8c45fSAndroid Build Coastguard Worker             err = NO_ERROR;
107*38e8c45fSAndroid Build Coastguard Worker         } else {
108*38e8c45fSAndroid Build Coastguard Worker             EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
109*38e8c45fSAndroid Build Coastguard Worker         }
110*38e8c45fSAndroid Build Coastguard Worker         return err;
111*38e8c45fSAndroid Build Coastguard Worker     }
112*38e8c45fSAndroid Build Coastguard Worker 
113*38e8c45fSAndroid Build Coastguard Worker     // Release the previous buffer.
114*38e8c45fSAndroid Build Coastguard Worker     err = updateAndReleaseLocked(item, nullptr, st);
115*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
116*38e8c45fSAndroid Build Coastguard Worker         // We always bind the texture.
117*38e8c45fSAndroid Build Coastguard Worker         glBindTexture(st.mTexTarget, st.mTexName);
118*38e8c45fSAndroid Build Coastguard Worker         return err;
119*38e8c45fSAndroid Build Coastguard Worker     }
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker     // Bind the new buffer to the GL texture, and wait until it's ready.
122*38e8c45fSAndroid Build Coastguard Worker     return bindTextureImageLocked(st);
123*38e8c45fSAndroid Build Coastguard Worker }
124*38e8c45fSAndroid Build Coastguard Worker 
releaseTexImage(SurfaceTexture & st)125*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) {
126*38e8c45fSAndroid Build Coastguard Worker     // Make sure the EGL state is the same as in previous calls.
127*38e8c45fSAndroid Build Coastguard Worker     status_t err = NO_ERROR;
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker     // if we're detached, no need to validate EGL's state -- we won't use it.
130*38e8c45fSAndroid Build Coastguard Worker     if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
131*38e8c45fSAndroid Build Coastguard Worker         err = checkAndUpdateEglStateLocked(st, true);
132*38e8c45fSAndroid Build Coastguard Worker         if (err != NO_ERROR) {
133*38e8c45fSAndroid Build Coastguard Worker             return err;
134*38e8c45fSAndroid Build Coastguard Worker         }
135*38e8c45fSAndroid Build Coastguard Worker     }
136*38e8c45fSAndroid Build Coastguard Worker 
137*38e8c45fSAndroid Build Coastguard Worker     // Update the EGLConsumer state.
138*38e8c45fSAndroid Build Coastguard Worker     int buf = st.mCurrentTexture;
139*38e8c45fSAndroid Build Coastguard Worker     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
140*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode);
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker         // if we're detached, we just use the fence that was created in
143*38e8c45fSAndroid Build Coastguard Worker         // detachFromContext() so... basically, nothing more to do here.
144*38e8c45fSAndroid Build Coastguard Worker         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
145*38e8c45fSAndroid Build Coastguard Worker             // Do whatever sync ops we need to do before releasing the slot.
146*38e8c45fSAndroid Build Coastguard Worker             err = syncForReleaseLocked(mEglDisplay, st);
147*38e8c45fSAndroid Build Coastguard Worker             if (err != NO_ERROR) {
148*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
149*38e8c45fSAndroid Build Coastguard Worker                 return err;
150*38e8c45fSAndroid Build Coastguard Worker             }
151*38e8c45fSAndroid Build Coastguard Worker         }
152*38e8c45fSAndroid Build Coastguard Worker 
153*38e8c45fSAndroid Build Coastguard Worker         err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer);
154*38e8c45fSAndroid Build Coastguard Worker         if (err < NO_ERROR) {
155*38e8c45fSAndroid Build Coastguard Worker             EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err);
156*38e8c45fSAndroid Build Coastguard Worker             return err;
157*38e8c45fSAndroid Build Coastguard Worker         }
158*38e8c45fSAndroid Build Coastguard Worker 
159*38e8c45fSAndroid Build Coastguard Worker         if (mReleasedTexImage == nullptr) {
160*38e8c45fSAndroid Build Coastguard Worker             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
161*38e8c45fSAndroid Build Coastguard Worker         }
162*38e8c45fSAndroid Build Coastguard Worker 
163*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
164*38e8c45fSAndroid Build Coastguard Worker         mCurrentTextureImage = mReleasedTexImage;
165*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentCrop.makeInvalid();
166*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentTransform = 0;
167*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentTimestamp = 0;
168*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
169*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentFence = Fence::NO_FENCE;
170*38e8c45fSAndroid Build Coastguard Worker         st.mCurrentFenceTime = FenceTime::NO_FENCE;
171*38e8c45fSAndroid Build Coastguard Worker 
172*38e8c45fSAndroid Build Coastguard Worker         // detached, don't touch the texture (and we may not even have an
173*38e8c45fSAndroid Build Coastguard Worker         // EGLDisplay here.
174*38e8c45fSAndroid Build Coastguard Worker         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
175*38e8c45fSAndroid Build Coastguard Worker             // This binds a dummy buffer (mReleasedTexImage).
176*38e8c45fSAndroid Build Coastguard Worker             status_t result = bindTextureImageLocked(st);
177*38e8c45fSAndroid Build Coastguard Worker             if (result != NO_ERROR) {
178*38e8c45fSAndroid Build Coastguard Worker                 return result;
179*38e8c45fSAndroid Build Coastguard Worker             }
180*38e8c45fSAndroid Build Coastguard Worker         }
181*38e8c45fSAndroid Build Coastguard Worker     }
182*38e8c45fSAndroid Build Coastguard Worker 
183*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
184*38e8c45fSAndroid Build Coastguard Worker }
185*38e8c45fSAndroid Build Coastguard Worker 
getDebugTexImageBuffer()186*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() {
187*38e8c45fSAndroid Build Coastguard Worker     Mutex::Autolock _l(sStaticInitLock);
188*38e8c45fSAndroid Build Coastguard Worker     if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
189*38e8c45fSAndroid Build Coastguard Worker         // The first time, create the debug texture in case the application
190*38e8c45fSAndroid Build Coastguard Worker         // continues to use it.
191*38e8c45fSAndroid Build Coastguard Worker         sp<GraphicBuffer> buffer =
192*38e8c45fSAndroid Build Coastguard Worker                 new GraphicBuffer(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
193*38e8c45fSAndroid Build Coastguard Worker                                   DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
194*38e8c45fSAndroid Build Coastguard Worker                                   "[EGLConsumer debug texture]");
195*38e8c45fSAndroid Build Coastguard Worker         uint32_t* bits;
196*38e8c45fSAndroid Build Coastguard Worker         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
197*38e8c45fSAndroid Build Coastguard Worker         uint32_t stride = buffer->getStride();
198*38e8c45fSAndroid Build Coastguard Worker         uint32_t height = buffer->getHeight();
199*38e8c45fSAndroid Build Coastguard Worker         memset(bits, 0, stride * height * 4);
200*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t y = 0; y < kDebugData.height; y++) {
201*38e8c45fSAndroid Build Coastguard Worker             for (uint32_t x = 0; x < kDebugData.width; x++) {
202*38e8c45fSAndroid Build Coastguard Worker                 bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000
203*38e8c45fSAndroid Build Coastguard Worker                                                                              : 0xFFFFFFFF;
204*38e8c45fSAndroid Build Coastguard Worker             }
205*38e8c45fSAndroid Build Coastguard Worker             bits += stride;
206*38e8c45fSAndroid Build Coastguard Worker         }
207*38e8c45fSAndroid Build Coastguard Worker         buffer->unlock();
208*38e8c45fSAndroid Build Coastguard Worker         sReleasedTexImageBuffer = buffer;
209*38e8c45fSAndroid Build Coastguard Worker     }
210*38e8c45fSAndroid Build Coastguard Worker     return sReleasedTexImageBuffer;
211*38e8c45fSAndroid Build Coastguard Worker }
212*38e8c45fSAndroid Build Coastguard Worker 
onAcquireBufferLocked(BufferItem * item,SurfaceTexture & st)213*38e8c45fSAndroid Build Coastguard Worker void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) {
214*38e8c45fSAndroid Build Coastguard Worker     // If item->mGraphicBuffer is not null, this buffer has not been acquired
215*38e8c45fSAndroid Build Coastguard Worker     // before, so any prior EglImage created is using a stale buffer. This
216*38e8c45fSAndroid Build Coastguard Worker     // replaces any old EglImage with a new one (using the new buffer).
217*38e8c45fSAndroid Build Coastguard Worker     int slot = item->mSlot;
218*38e8c45fSAndroid Build Coastguard Worker     if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) {
219*38e8c45fSAndroid Build Coastguard Worker         mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
220*38e8c45fSAndroid Build Coastguard Worker     }
221*38e8c45fSAndroid Build Coastguard Worker }
222*38e8c45fSAndroid Build Coastguard Worker 
onReleaseBufferLocked(int buf)223*38e8c45fSAndroid Build Coastguard Worker void EGLConsumer::onReleaseBufferLocked(int buf) {
224*38e8c45fSAndroid Build Coastguard Worker     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
225*38e8c45fSAndroid Build Coastguard Worker }
226*38e8c45fSAndroid Build Coastguard Worker 
updateAndReleaseLocked(const BufferItem & item,PendingRelease * pendingRelease,SurfaceTexture & st)227*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
228*38e8c45fSAndroid Build Coastguard Worker                                              SurfaceTexture& st) {
229*38e8c45fSAndroid Build Coastguard Worker     status_t err = NO_ERROR;
230*38e8c45fSAndroid Build Coastguard Worker 
231*38e8c45fSAndroid Build Coastguard Worker     int slot = item.mSlot;
232*38e8c45fSAndroid Build Coastguard Worker 
233*38e8c45fSAndroid Build Coastguard Worker     if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) {
234*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("updateAndRelease: EGLConsumer is not attached to an OpenGL "
235*38e8c45fSAndroid Build Coastguard Worker                  "ES context");
236*38e8c45fSAndroid Build Coastguard Worker         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
237*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
238*38e8c45fSAndroid Build Coastguard Worker     }
239*38e8c45fSAndroid Build Coastguard Worker 
240*38e8c45fSAndroid Build Coastguard Worker     // Confirm state.
241*38e8c45fSAndroid Build Coastguard Worker     err = checkAndUpdateEglStateLocked(st);
242*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
243*38e8c45fSAndroid Build Coastguard Worker         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
244*38e8c45fSAndroid Build Coastguard Worker         return err;
245*38e8c45fSAndroid Build Coastguard Worker     }
246*38e8c45fSAndroid Build Coastguard Worker 
247*38e8c45fSAndroid Build Coastguard Worker     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
248*38e8c45fSAndroid Build Coastguard Worker     // if nessessary, for the gralloc buffer currently in the slot in
249*38e8c45fSAndroid Build Coastguard Worker     // ConsumerBase.
250*38e8c45fSAndroid Build Coastguard Worker     // We may have to do this even when item.mGraphicBuffer == NULL (which
251*38e8c45fSAndroid Build Coastguard Worker     // means the buffer was previously acquired).
252*38e8c45fSAndroid Build Coastguard Worker     err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
253*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
254*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
255*38e8c45fSAndroid Build Coastguard Worker                  slot);
256*38e8c45fSAndroid Build Coastguard Worker         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
257*38e8c45fSAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
258*38e8c45fSAndroid Build Coastguard Worker     }
259*38e8c45fSAndroid Build Coastguard Worker 
260*38e8c45fSAndroid Build Coastguard Worker     // Do whatever sync ops we need to do before releasing the old slot.
261*38e8c45fSAndroid Build Coastguard Worker     if (slot != st.mCurrentTexture) {
262*38e8c45fSAndroid Build Coastguard Worker         err = syncForReleaseLocked(mEglDisplay, st);
263*38e8c45fSAndroid Build Coastguard Worker         if (err != NO_ERROR) {
264*38e8c45fSAndroid Build Coastguard Worker             // Release the buffer we just acquired.  It's not safe to
265*38e8c45fSAndroid Build Coastguard Worker             // release the old buffer, so instead we just drop the new frame.
266*38e8c45fSAndroid Build Coastguard Worker             // As we are still under lock since acquireBuffer, it is safe to
267*38e8c45fSAndroid Build Coastguard Worker             // release by slot.
268*38e8c45fSAndroid Build Coastguard Worker             st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer);
269*38e8c45fSAndroid Build Coastguard Worker             return err;
270*38e8c45fSAndroid Build Coastguard Worker         }
271*38e8c45fSAndroid Build Coastguard Worker     }
272*38e8c45fSAndroid Build Coastguard Worker 
273*38e8c45fSAndroid Build Coastguard Worker     EGC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture,
274*38e8c45fSAndroid Build Coastguard Worker              mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle()
275*38e8c45fSAndroid Build Coastguard Worker                                              : nullptr,
276*38e8c45fSAndroid Build Coastguard Worker              slot, st.mSlots[slot].mGraphicBuffer->handle);
277*38e8c45fSAndroid Build Coastguard Worker 
278*38e8c45fSAndroid Build Coastguard Worker     // Hang onto the pointer so that it isn't freed in the call to
279*38e8c45fSAndroid Build Coastguard Worker     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
280*38e8c45fSAndroid Build Coastguard Worker     // the same.
281*38e8c45fSAndroid Build Coastguard Worker     sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
282*38e8c45fSAndroid Build Coastguard Worker 
283*38e8c45fSAndroid Build Coastguard Worker     // release old buffer
284*38e8c45fSAndroid Build Coastguard Worker     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
285*38e8c45fSAndroid Build Coastguard Worker         if (pendingRelease == nullptr) {
286*38e8c45fSAndroid Build Coastguard Worker             status_t status =
287*38e8c45fSAndroid Build Coastguard Worker                     st.releaseBufferLocked(st.mCurrentTexture,
288*38e8c45fSAndroid Build Coastguard Worker                                            mCurrentTextureImage->graphicBuffer(), mEglDisplay,
289*38e8c45fSAndroid Build Coastguard Worker                                            mEglSlots[st.mCurrentTexture].mEglFence);
290*38e8c45fSAndroid Build Coastguard Worker             if (status < NO_ERROR) {
291*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
292*38e8c45fSAndroid Build Coastguard Worker                          status);
293*38e8c45fSAndroid Build Coastguard Worker                 err = status;
294*38e8c45fSAndroid Build Coastguard Worker                 // keep going, with error raised [?]
295*38e8c45fSAndroid Build Coastguard Worker             }
296*38e8c45fSAndroid Build Coastguard Worker         } else {
297*38e8c45fSAndroid Build Coastguard Worker             pendingRelease->currentTexture = st.mCurrentTexture;
298*38e8c45fSAndroid Build Coastguard Worker             pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
299*38e8c45fSAndroid Build Coastguard Worker             pendingRelease->display = mEglDisplay;
300*38e8c45fSAndroid Build Coastguard Worker             pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence;
301*38e8c45fSAndroid Build Coastguard Worker             pendingRelease->isPending = true;
302*38e8c45fSAndroid Build Coastguard Worker         }
303*38e8c45fSAndroid Build Coastguard Worker     }
304*38e8c45fSAndroid Build Coastguard Worker 
305*38e8c45fSAndroid Build Coastguard Worker     // Update the EGLConsumer state.
306*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentTexture = slot;
307*38e8c45fSAndroid Build Coastguard Worker     mCurrentTextureImage = nextTextureImage;
308*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentCrop = item.mCrop;
309*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentTransform = item.mTransform;
310*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentScalingMode = item.mScalingMode;
311*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentTimestamp = item.mTimestamp;
312*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentDataSpace = item.mDataSpace;
313*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentFence = item.mFence;
314*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentFenceTime = item.mFenceTime;
315*38e8c45fSAndroid Build Coastguard Worker     st.mCurrentFrameNumber = item.mFrameNumber;
316*38e8c45fSAndroid Build Coastguard Worker 
317*38e8c45fSAndroid Build Coastguard Worker     st.computeCurrentTransformMatrixLocked();
318*38e8c45fSAndroid Build Coastguard Worker 
319*38e8c45fSAndroid Build Coastguard Worker     return err;
320*38e8c45fSAndroid Build Coastguard Worker }
321*38e8c45fSAndroid Build Coastguard Worker 
bindTextureImageLocked(SurfaceTexture & st)322*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) {
323*38e8c45fSAndroid Build Coastguard Worker     if (mEglDisplay == EGL_NO_DISPLAY) {
324*38e8c45fSAndroid Build Coastguard Worker         ALOGE("bindTextureImage: invalid display");
325*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
326*38e8c45fSAndroid Build Coastguard Worker     }
327*38e8c45fSAndroid Build Coastguard Worker 
328*38e8c45fSAndroid Build Coastguard Worker     GLenum error;
329*38e8c45fSAndroid Build Coastguard Worker     while ((error = glGetError()) != GL_NO_ERROR) {
330*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
331*38e8c45fSAndroid Build Coastguard Worker     }
332*38e8c45fSAndroid Build Coastguard Worker 
333*38e8c45fSAndroid Build Coastguard Worker     glBindTexture(st.mTexTarget, st.mTexName);
334*38e8c45fSAndroid Build Coastguard Worker     if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
335*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("bindTextureImage: no currently-bound texture");
336*38e8c45fSAndroid Build Coastguard Worker         return NO_INIT;
337*38e8c45fSAndroid Build Coastguard Worker     }
338*38e8c45fSAndroid Build Coastguard Worker 
339*38e8c45fSAndroid Build Coastguard Worker     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
340*38e8c45fSAndroid Build Coastguard Worker     if (err != NO_ERROR) {
341*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
342*38e8c45fSAndroid Build Coastguard Worker                  st.mCurrentTexture);
343*38e8c45fSAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
344*38e8c45fSAndroid Build Coastguard Worker     }
345*38e8c45fSAndroid Build Coastguard Worker     mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
346*38e8c45fSAndroid Build Coastguard Worker 
347*38e8c45fSAndroid Build Coastguard Worker     // In the rare case that the display is terminated and then initialized
348*38e8c45fSAndroid Build Coastguard Worker     // again, we can't detect that the display changed (it didn't), but the
349*38e8c45fSAndroid Build Coastguard Worker     // image is invalid. In this case, repeat the exact same steps while
350*38e8c45fSAndroid Build Coastguard Worker     // forcing the creation of a new image.
351*38e8c45fSAndroid Build Coastguard Worker     if ((error = glGetError()) != GL_NO_ERROR) {
352*38e8c45fSAndroid Build Coastguard Worker         glBindTexture(st.mTexTarget, st.mTexName);
353*38e8c45fSAndroid Build Coastguard Worker         status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
354*38e8c45fSAndroid Build Coastguard Worker         if (result != NO_ERROR) {
355*38e8c45fSAndroid Build Coastguard Worker             EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
356*38e8c45fSAndroid Build Coastguard Worker                      st.mCurrentTexture);
357*38e8c45fSAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
358*38e8c45fSAndroid Build Coastguard Worker         }
359*38e8c45fSAndroid Build Coastguard Worker         mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
360*38e8c45fSAndroid Build Coastguard Worker         if ((error = glGetError()) != GL_NO_ERROR) {
361*38e8c45fSAndroid Build Coastguard Worker             EGC_LOGE("bindTextureImage: error binding external image: %#04x", error);
362*38e8c45fSAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
363*38e8c45fSAndroid Build Coastguard Worker         }
364*38e8c45fSAndroid Build Coastguard Worker     }
365*38e8c45fSAndroid Build Coastguard Worker 
366*38e8c45fSAndroid Build Coastguard Worker     // Wait for the new buffer to be ready.
367*38e8c45fSAndroid Build Coastguard Worker     return doGLFenceWaitLocked(st);
368*38e8c45fSAndroid Build Coastguard Worker }
369*38e8c45fSAndroid Build Coastguard Worker 
checkAndUpdateEglStateLocked(SurfaceTexture & st,bool contextCheck)370*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) {
371*38e8c45fSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetCurrentDisplay();
372*38e8c45fSAndroid Build Coastguard Worker     EGLContext ctx = eglGetCurrentContext();
373*38e8c45fSAndroid Build Coastguard Worker 
374*38e8c45fSAndroid Build Coastguard Worker     if (!contextCheck) {
375*38e8c45fSAndroid Build Coastguard Worker         // if this is the first time we're called, mEglDisplay/mEglContext have
376*38e8c45fSAndroid Build Coastguard Worker         // never been set, so don't error out (below).
377*38e8c45fSAndroid Build Coastguard Worker         if (mEglDisplay == EGL_NO_DISPLAY) {
378*38e8c45fSAndroid Build Coastguard Worker             mEglDisplay = dpy;
379*38e8c45fSAndroid Build Coastguard Worker         }
380*38e8c45fSAndroid Build Coastguard Worker         if (mEglContext == EGL_NO_CONTEXT) {
381*38e8c45fSAndroid Build Coastguard Worker             mEglContext = ctx;
382*38e8c45fSAndroid Build Coastguard Worker         }
383*38e8c45fSAndroid Build Coastguard Worker     }
384*38e8c45fSAndroid Build Coastguard Worker 
385*38e8c45fSAndroid Build Coastguard Worker     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
386*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
387*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
388*38e8c45fSAndroid Build Coastguard Worker     }
389*38e8c45fSAndroid Build Coastguard Worker 
390*38e8c45fSAndroid Build Coastguard Worker     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
391*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
392*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
393*38e8c45fSAndroid Build Coastguard Worker     }
394*38e8c45fSAndroid Build Coastguard Worker 
395*38e8c45fSAndroid Build Coastguard Worker     mEglDisplay = dpy;
396*38e8c45fSAndroid Build Coastguard Worker     mEglContext = ctx;
397*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
398*38e8c45fSAndroid Build Coastguard Worker }
399*38e8c45fSAndroid Build Coastguard Worker 
detachFromContext(SurfaceTexture & st)400*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::detachFromContext(SurfaceTexture& st) {
401*38e8c45fSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetCurrentDisplay();
402*38e8c45fSAndroid Build Coastguard Worker     EGLContext ctx = eglGetCurrentContext();
403*38e8c45fSAndroid Build Coastguard Worker 
404*38e8c45fSAndroid Build Coastguard Worker     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
405*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("detachFromContext: invalid current EGLDisplay");
406*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
407*38e8c45fSAndroid Build Coastguard Worker     }
408*38e8c45fSAndroid Build Coastguard Worker 
409*38e8c45fSAndroid Build Coastguard Worker     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
410*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("detachFromContext: invalid current EGLContext");
411*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
412*38e8c45fSAndroid Build Coastguard Worker     }
413*38e8c45fSAndroid Build Coastguard Worker 
414*38e8c45fSAndroid Build Coastguard Worker     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
415*38e8c45fSAndroid Build Coastguard Worker         status_t err = syncForReleaseLocked(dpy, st);
416*38e8c45fSAndroid Build Coastguard Worker         if (err != OK) {
417*38e8c45fSAndroid Build Coastguard Worker             return err;
418*38e8c45fSAndroid Build Coastguard Worker         }
419*38e8c45fSAndroid Build Coastguard Worker 
420*38e8c45fSAndroid Build Coastguard Worker         glDeleteTextures(1, &st.mTexName);
421*38e8c45fSAndroid Build Coastguard Worker     }
422*38e8c45fSAndroid Build Coastguard Worker 
423*38e8c45fSAndroid Build Coastguard Worker     mEglDisplay = EGL_NO_DISPLAY;
424*38e8c45fSAndroid Build Coastguard Worker     mEglContext = EGL_NO_CONTEXT;
425*38e8c45fSAndroid Build Coastguard Worker 
426*38e8c45fSAndroid Build Coastguard Worker     return OK;
427*38e8c45fSAndroid Build Coastguard Worker }
428*38e8c45fSAndroid Build Coastguard Worker 
attachToContext(uint32_t tex,SurfaceTexture & st)429*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) {
430*38e8c45fSAndroid Build Coastguard Worker     // Initialize mCurrentTextureImage if there is a current buffer from past
431*38e8c45fSAndroid Build Coastguard Worker     // attached state.
432*38e8c45fSAndroid Build Coastguard Worker     int slot = st.mCurrentTexture;
433*38e8c45fSAndroid Build Coastguard Worker     if (slot != BufferItem::INVALID_BUFFER_SLOT) {
434*38e8c45fSAndroid Build Coastguard Worker         if (!mEglSlots[slot].mEglImage.get()) {
435*38e8c45fSAndroid Build Coastguard Worker             mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
436*38e8c45fSAndroid Build Coastguard Worker         }
437*38e8c45fSAndroid Build Coastguard Worker         mCurrentTextureImage = mEglSlots[slot].mEglImage;
438*38e8c45fSAndroid Build Coastguard Worker     }
439*38e8c45fSAndroid Build Coastguard Worker 
440*38e8c45fSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetCurrentDisplay();
441*38e8c45fSAndroid Build Coastguard Worker     EGLContext ctx = eglGetCurrentContext();
442*38e8c45fSAndroid Build Coastguard Worker 
443*38e8c45fSAndroid Build Coastguard Worker     if (dpy == EGL_NO_DISPLAY) {
444*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("attachToContext: invalid current EGLDisplay");
445*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
446*38e8c45fSAndroid Build Coastguard Worker     }
447*38e8c45fSAndroid Build Coastguard Worker 
448*38e8c45fSAndroid Build Coastguard Worker     if (ctx == EGL_NO_CONTEXT) {
449*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("attachToContext: invalid current EGLContext");
450*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
451*38e8c45fSAndroid Build Coastguard Worker     }
452*38e8c45fSAndroid Build Coastguard Worker 
453*38e8c45fSAndroid Build Coastguard Worker     // We need to bind the texture regardless of whether there's a current
454*38e8c45fSAndroid Build Coastguard Worker     // buffer.
455*38e8c45fSAndroid Build Coastguard Worker     glBindTexture(st.mTexTarget, GLuint(tex));
456*38e8c45fSAndroid Build Coastguard Worker 
457*38e8c45fSAndroid Build Coastguard Worker     mEglDisplay = dpy;
458*38e8c45fSAndroid Build Coastguard Worker     mEglContext = ctx;
459*38e8c45fSAndroid Build Coastguard Worker     st.mTexName = tex;
460*38e8c45fSAndroid Build Coastguard Worker     st.mOpMode = SurfaceTexture::OpMode::attachedToGL;
461*38e8c45fSAndroid Build Coastguard Worker 
462*38e8c45fSAndroid Build Coastguard Worker     if (mCurrentTextureImage != nullptr) {
463*38e8c45fSAndroid Build Coastguard Worker         // This may wait for a buffer a second time. This is likely required if
464*38e8c45fSAndroid Build Coastguard Worker         // this is a different context, since otherwise the wait could be skipped
465*38e8c45fSAndroid Build Coastguard Worker         // by bouncing through another context. For the same context the extra
466*38e8c45fSAndroid Build Coastguard Worker         // wait is redundant.
467*38e8c45fSAndroid Build Coastguard Worker         status_t err = bindTextureImageLocked(st);
468*38e8c45fSAndroid Build Coastguard Worker         if (err != NO_ERROR) {
469*38e8c45fSAndroid Build Coastguard Worker             return err;
470*38e8c45fSAndroid Build Coastguard Worker         }
471*38e8c45fSAndroid Build Coastguard Worker     }
472*38e8c45fSAndroid Build Coastguard Worker 
473*38e8c45fSAndroid Build Coastguard Worker     return OK;
474*38e8c45fSAndroid Build Coastguard Worker }
475*38e8c45fSAndroid Build Coastguard Worker 
syncForReleaseLocked(EGLDisplay dpy,SurfaceTexture & st)476*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) {
477*38e8c45fSAndroid Build Coastguard Worker     EGC_LOGV("syncForReleaseLocked");
478*38e8c45fSAndroid Build Coastguard Worker 
479*38e8c45fSAndroid Build Coastguard Worker     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
480*38e8c45fSAndroid Build Coastguard Worker         if (SyncFeatures::getInstance().useNativeFenceSync()) {
481*38e8c45fSAndroid Build Coastguard Worker             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
482*38e8c45fSAndroid Build Coastguard Worker             if (sync == EGL_NO_SYNC_KHR) {
483*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
484*38e8c45fSAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
485*38e8c45fSAndroid Build Coastguard Worker             }
486*38e8c45fSAndroid Build Coastguard Worker             glFlush();
487*38e8c45fSAndroid Build Coastguard Worker             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
488*38e8c45fSAndroid Build Coastguard Worker             eglDestroySyncKHR(dpy, sync);
489*38e8c45fSAndroid Build Coastguard Worker             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
490*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("syncForReleaseLocked: error dup'ing native fence "
491*38e8c45fSAndroid Build Coastguard Worker                          "fd: %#x",
492*38e8c45fSAndroid Build Coastguard Worker                          eglGetError());
493*38e8c45fSAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
494*38e8c45fSAndroid Build Coastguard Worker             }
495*38e8c45fSAndroid Build Coastguard Worker             sp<Fence> fence(new Fence(fenceFd));
496*38e8c45fSAndroid Build Coastguard Worker             status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
497*38e8c45fSAndroid Build Coastguard Worker                                                     mCurrentTextureImage->graphicBuffer(), fence);
498*38e8c45fSAndroid Build Coastguard Worker             if (err != OK) {
499*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("syncForReleaseLocked: error adding release fence: "
500*38e8c45fSAndroid Build Coastguard Worker                          "%s (%d)",
501*38e8c45fSAndroid Build Coastguard Worker                          strerror(-err), err);
502*38e8c45fSAndroid Build Coastguard Worker                 return err;
503*38e8c45fSAndroid Build Coastguard Worker             }
504*38e8c45fSAndroid Build Coastguard Worker         } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
505*38e8c45fSAndroid Build Coastguard Worker             EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence;
506*38e8c45fSAndroid Build Coastguard Worker             if (fence != EGL_NO_SYNC_KHR) {
507*38e8c45fSAndroid Build Coastguard Worker                 // There is already a fence for the current slot.  We need to
508*38e8c45fSAndroid Build Coastguard Worker                 // wait on that before replacing it with another fence to
509*38e8c45fSAndroid Build Coastguard Worker                 // ensure that all outstanding buffer accesses have completed
510*38e8c45fSAndroid Build Coastguard Worker                 // before the producer accesses it.
511*38e8c45fSAndroid Build Coastguard Worker                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
512*38e8c45fSAndroid Build Coastguard Worker                 if (result == EGL_FALSE) {
513*38e8c45fSAndroid Build Coastguard Worker                     EGC_LOGE("syncForReleaseLocked: error waiting for previous "
514*38e8c45fSAndroid Build Coastguard Worker                              "fence: %#x",
515*38e8c45fSAndroid Build Coastguard Worker                              eglGetError());
516*38e8c45fSAndroid Build Coastguard Worker                     return UNKNOWN_ERROR;
517*38e8c45fSAndroid Build Coastguard Worker                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
518*38e8c45fSAndroid Build Coastguard Worker                     EGC_LOGE("syncForReleaseLocked: timeout waiting for previous "
519*38e8c45fSAndroid Build Coastguard Worker                              "fence");
520*38e8c45fSAndroid Build Coastguard Worker                     return TIMED_OUT;
521*38e8c45fSAndroid Build Coastguard Worker                 }
522*38e8c45fSAndroid Build Coastguard Worker                 eglDestroySyncKHR(dpy, fence);
523*38e8c45fSAndroid Build Coastguard Worker             }
524*38e8c45fSAndroid Build Coastguard Worker 
525*38e8c45fSAndroid Build Coastguard Worker             // Create a fence for the outstanding accesses in the current
526*38e8c45fSAndroid Build Coastguard Worker             // OpenGL ES context.
527*38e8c45fSAndroid Build Coastguard Worker             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
528*38e8c45fSAndroid Build Coastguard Worker             if (fence == EGL_NO_SYNC_KHR) {
529*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
530*38e8c45fSAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
531*38e8c45fSAndroid Build Coastguard Worker             }
532*38e8c45fSAndroid Build Coastguard Worker             glFlush();
533*38e8c45fSAndroid Build Coastguard Worker             mEglSlots[st.mCurrentTexture].mEglFence = fence;
534*38e8c45fSAndroid Build Coastguard Worker         }
535*38e8c45fSAndroid Build Coastguard Worker     }
536*38e8c45fSAndroid Build Coastguard Worker 
537*38e8c45fSAndroid Build Coastguard Worker     return OK;
538*38e8c45fSAndroid Build Coastguard Worker }
539*38e8c45fSAndroid Build Coastguard Worker 
doGLFenceWaitLocked(SurfaceTexture & st) const540*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const {
541*38e8c45fSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetCurrentDisplay();
542*38e8c45fSAndroid Build Coastguard Worker     EGLContext ctx = eglGetCurrentContext();
543*38e8c45fSAndroid Build Coastguard Worker 
544*38e8c45fSAndroid Build Coastguard Worker     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
545*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("doGLFenceWait: invalid current EGLDisplay");
546*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
547*38e8c45fSAndroid Build Coastguard Worker     }
548*38e8c45fSAndroid Build Coastguard Worker 
549*38e8c45fSAndroid Build Coastguard Worker     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
550*38e8c45fSAndroid Build Coastguard Worker         EGC_LOGE("doGLFenceWait: invalid current EGLContext");
551*38e8c45fSAndroid Build Coastguard Worker         return INVALID_OPERATION;
552*38e8c45fSAndroid Build Coastguard Worker     }
553*38e8c45fSAndroid Build Coastguard Worker 
554*38e8c45fSAndroid Build Coastguard Worker     if (st.mCurrentFence->isValid()) {
555*38e8c45fSAndroid Build Coastguard Worker         if (SyncFeatures::getInstance().useWaitSync() &&
556*38e8c45fSAndroid Build Coastguard Worker             SyncFeatures::getInstance().useNativeFenceSync()) {
557*38e8c45fSAndroid Build Coastguard Worker             // Create an EGLSyncKHR from the current fence.
558*38e8c45fSAndroid Build Coastguard Worker             int fenceFd = st.mCurrentFence->dup();
559*38e8c45fSAndroid Build Coastguard Worker             if (fenceFd == -1) {
560*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
561*38e8c45fSAndroid Build Coastguard Worker                 return -errno;
562*38e8c45fSAndroid Build Coastguard Worker             }
563*38e8c45fSAndroid Build Coastguard Worker             EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
564*38e8c45fSAndroid Build Coastguard Worker             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
565*38e8c45fSAndroid Build Coastguard Worker             if (sync == EGL_NO_SYNC_KHR) {
566*38e8c45fSAndroid Build Coastguard Worker                 close(fenceFd);
567*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
568*38e8c45fSAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
569*38e8c45fSAndroid Build Coastguard Worker             }
570*38e8c45fSAndroid Build Coastguard Worker 
571*38e8c45fSAndroid Build Coastguard Worker             // XXX: The spec draft is inconsistent as to whether this should
572*38e8c45fSAndroid Build Coastguard Worker             // return an EGLint or void.  Ignore the return value for now, as
573*38e8c45fSAndroid Build Coastguard Worker             // it's not strictly needed.
574*38e8c45fSAndroid Build Coastguard Worker             eglWaitSyncKHR(dpy, sync, 0);
575*38e8c45fSAndroid Build Coastguard Worker             EGLint eglErr = eglGetError();
576*38e8c45fSAndroid Build Coastguard Worker             eglDestroySyncKHR(dpy, sync);
577*38e8c45fSAndroid Build Coastguard Worker             if (eglErr != EGL_SUCCESS) {
578*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
579*38e8c45fSAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
580*38e8c45fSAndroid Build Coastguard Worker             }
581*38e8c45fSAndroid Build Coastguard Worker         } else {
582*38e8c45fSAndroid Build Coastguard Worker             status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked");
583*38e8c45fSAndroid Build Coastguard Worker             if (err != NO_ERROR) {
584*38e8c45fSAndroid Build Coastguard Worker                 EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
585*38e8c45fSAndroid Build Coastguard Worker                 return err;
586*38e8c45fSAndroid Build Coastguard Worker             }
587*38e8c45fSAndroid Build Coastguard Worker         }
588*38e8c45fSAndroid Build Coastguard Worker     }
589*38e8c45fSAndroid Build Coastguard Worker 
590*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
591*38e8c45fSAndroid Build Coastguard Worker }
592*38e8c45fSAndroid Build Coastguard Worker 
onFreeBufferLocked(int slotIndex)593*38e8c45fSAndroid Build Coastguard Worker void EGLConsumer::onFreeBufferLocked(int slotIndex) {
594*38e8c45fSAndroid Build Coastguard Worker     if (mEglSlots[slotIndex].mEglImage != nullptr &&
595*38e8c45fSAndroid Build Coastguard Worker         mEglSlots[slotIndex].mEglImage == mCurrentTextureImage) {
596*38e8c45fSAndroid Build Coastguard Worker         mCurrentTextureImage.clear();
597*38e8c45fSAndroid Build Coastguard Worker     }
598*38e8c45fSAndroid Build Coastguard Worker     mEglSlots[slotIndex].mEglImage.clear();
599*38e8c45fSAndroid Build Coastguard Worker }
600*38e8c45fSAndroid Build Coastguard Worker 
onAbandonLocked()601*38e8c45fSAndroid Build Coastguard Worker void EGLConsumer::onAbandonLocked() {
602*38e8c45fSAndroid Build Coastguard Worker     mCurrentTextureImage.clear();
603*38e8c45fSAndroid Build Coastguard Worker }
604*38e8c45fSAndroid Build Coastguard Worker 
EglImage(sp<GraphicBuffer> graphicBuffer)605*38e8c45fSAndroid Build Coastguard Worker EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
606*38e8c45fSAndroid Build Coastguard Worker       : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {}
607*38e8c45fSAndroid Build Coastguard Worker 
~EglImage()608*38e8c45fSAndroid Build Coastguard Worker EGLConsumer::EglImage::~EglImage() {
609*38e8c45fSAndroid Build Coastguard Worker     if (mEglImage != EGL_NO_IMAGE_KHR) {
610*38e8c45fSAndroid Build Coastguard Worker         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
611*38e8c45fSAndroid Build Coastguard Worker             ALOGE("~EglImage: eglDestroyImageKHR failed");
612*38e8c45fSAndroid Build Coastguard Worker         }
613*38e8c45fSAndroid Build Coastguard Worker         eglTerminate(mEglDisplay);
614*38e8c45fSAndroid Build Coastguard Worker     }
615*38e8c45fSAndroid Build Coastguard Worker }
616*38e8c45fSAndroid Build Coastguard Worker 
createIfNeeded(EGLDisplay eglDisplay,bool forceCreation)617*38e8c45fSAndroid Build Coastguard Worker status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) {
618*38e8c45fSAndroid Build Coastguard Worker     // If there's an image and it's no longer valid, destroy it.
619*38e8c45fSAndroid Build Coastguard Worker     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
620*38e8c45fSAndroid Build Coastguard Worker     bool displayInvalid = mEglDisplay != eglDisplay;
621*38e8c45fSAndroid Build Coastguard Worker     if (haveImage && (displayInvalid || forceCreation)) {
622*38e8c45fSAndroid Build Coastguard Worker         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
623*38e8c45fSAndroid Build Coastguard Worker             ALOGE("createIfNeeded: eglDestroyImageKHR failed");
624*38e8c45fSAndroid Build Coastguard Worker         }
625*38e8c45fSAndroid Build Coastguard Worker         eglTerminate(mEglDisplay);
626*38e8c45fSAndroid Build Coastguard Worker         mEglImage = EGL_NO_IMAGE_KHR;
627*38e8c45fSAndroid Build Coastguard Worker         mEglDisplay = EGL_NO_DISPLAY;
628*38e8c45fSAndroid Build Coastguard Worker     }
629*38e8c45fSAndroid Build Coastguard Worker 
630*38e8c45fSAndroid Build Coastguard Worker     // If there's no image, create one.
631*38e8c45fSAndroid Build Coastguard Worker     if (mEglImage == EGL_NO_IMAGE_KHR) {
632*38e8c45fSAndroid Build Coastguard Worker         mEglDisplay = eglDisplay;
633*38e8c45fSAndroid Build Coastguard Worker         mEglImage = createImage(mEglDisplay, mGraphicBuffer);
634*38e8c45fSAndroid Build Coastguard Worker     }
635*38e8c45fSAndroid Build Coastguard Worker 
636*38e8c45fSAndroid Build Coastguard Worker     // Fail if we can't create a valid image.
637*38e8c45fSAndroid Build Coastguard Worker     if (mEglImage == EGL_NO_IMAGE_KHR) {
638*38e8c45fSAndroid Build Coastguard Worker         mEglDisplay = EGL_NO_DISPLAY;
639*38e8c45fSAndroid Build Coastguard Worker         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
640*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
641*38e8c45fSAndroid Build Coastguard Worker               buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
642*38e8c45fSAndroid Build Coastguard Worker               buffer->getPixelFormat());
643*38e8c45fSAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
644*38e8c45fSAndroid Build Coastguard Worker     }
645*38e8c45fSAndroid Build Coastguard Worker 
646*38e8c45fSAndroid Build Coastguard Worker     return OK;
647*38e8c45fSAndroid Build Coastguard Worker }
648*38e8c45fSAndroid Build Coastguard Worker 
bindToTextureTarget(uint32_t texTarget)649*38e8c45fSAndroid Build Coastguard Worker void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
650*38e8c45fSAndroid Build Coastguard Worker     glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
651*38e8c45fSAndroid Build Coastguard Worker }
652*38e8c45fSAndroid Build Coastguard Worker 
createImage(EGLDisplay dpy,const sp<GraphicBuffer> & graphicBuffer)653*38e8c45fSAndroid Build Coastguard Worker EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy,
654*38e8c45fSAndroid Build Coastguard Worker                                                const sp<GraphicBuffer>& graphicBuffer) {
655*38e8c45fSAndroid Build Coastguard Worker     EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
656*38e8c45fSAndroid Build Coastguard Worker     const bool createProtectedImage =
657*38e8c45fSAndroid Build Coastguard Worker             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
658*38e8c45fSAndroid Build Coastguard Worker     EGLint attrs[] = {
659*38e8c45fSAndroid Build Coastguard Worker             EGL_IMAGE_PRESERVED_KHR,
660*38e8c45fSAndroid Build Coastguard Worker             EGL_TRUE,
661*38e8c45fSAndroid Build Coastguard Worker             createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
662*38e8c45fSAndroid Build Coastguard Worker             createProtectedImage ? EGL_TRUE : EGL_NONE,
663*38e8c45fSAndroid Build Coastguard Worker             EGL_NONE,
664*38e8c45fSAndroid Build Coastguard Worker     };
665*38e8c45fSAndroid Build Coastguard Worker     eglInitialize(dpy, nullptr, nullptr);
666*38e8c45fSAndroid Build Coastguard Worker     EGLImageKHR image =
667*38e8c45fSAndroid Build Coastguard Worker             eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
668*38e8c45fSAndroid Build Coastguard Worker     if (image == EGL_NO_IMAGE_KHR) {
669*38e8c45fSAndroid Build Coastguard Worker         EGLint error = eglGetError();
670*38e8c45fSAndroid Build Coastguard Worker         ALOGE("error creating EGLImage: %#x", error);
671*38e8c45fSAndroid Build Coastguard Worker         eglTerminate(dpy);
672*38e8c45fSAndroid Build Coastguard Worker     }
673*38e8c45fSAndroid Build Coastguard Worker     return image;
674*38e8c45fSAndroid Build Coastguard Worker }
675*38e8c45fSAndroid Build Coastguard Worker 
676*38e8c45fSAndroid Build Coastguard Worker } // namespace android
677