• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #pragma once
18 
19 #include <EGL/egl.h>
20 #include <EGL/eglext.h>
21 #include <gui/BufferQueueDefs.h>
22 #include <ui/FenceTime.h>
23 #include <ui/GraphicBuffer.h>
24 #include <utils/Mutex.h>
25 
26 namespace android {
27 
28 class SurfaceTexture;
29 
30 /*
31  * EGLConsumer implements the parts of SurfaceTexture that deal with
32  * textures attached to an GL context.
33  */
34 class EGLConsumer {
35 public:
36     EGLConsumer();
37 
38     /**
39      * updateTexImage acquires the most recently queued buffer, and sets the
40      * image contents of the target texture to it.
41      *
42      * This call may only be made while the OpenGL ES context to which the
43      * target texture belongs is bound to the calling thread.
44      *
45      * This calls doGLFenceWait to ensure proper synchronization.
46      */
47     status_t updateTexImage(SurfaceTexture& st);
48 
49     /*
50      * releaseTexImage releases the texture acquired in updateTexImage().
51      * This is intended to be used in single buffer mode.
52      *
53      * This call may only be made while the OpenGL ES context to which the
54      * target texture belongs is bound to the calling thread.
55      */
56     status_t releaseTexImage(SurfaceTexture& st);
57 
58     /**
59      * detachFromContext detaches the EGLConsumer from the calling thread's
60      * current OpenGL ES context.  This context must be the same as the context
61      * that was current for previous calls to updateTexImage.
62      *
63      * Detaching a EGLConsumer from an OpenGL ES context will result in the
64      * deletion of the OpenGL ES texture object into which the images were being
65      * streamed.  After a EGLConsumer has been detached from the OpenGL ES
66      * context calls to updateTexImage will fail returning INVALID_OPERATION
67      * until the EGLConsumer is attached to a new OpenGL ES context using the
68      * attachToContext method.
69      */
70     status_t detachFromContext(SurfaceTexture& st);
71 
72     /**
73      * attachToContext attaches a EGLConsumer that is currently in the
74      * 'detached' state to the current OpenGL ES context.  A EGLConsumer is
75      * in the 'detached' state iff detachFromContext has successfully been
76      * called and no calls to attachToContext have succeeded since the last
77      * detachFromContext call.  Calls to attachToContext made on a
78      * EGLConsumer that is not in the 'detached' state will result in an
79      * INVALID_OPERATION error.
80      *
81      * The tex argument specifies the OpenGL ES texture object name in the
82      * new context into which the image contents will be streamed.  A successful
83      * call to attachToContext will result in this texture object being bound to
84      * the texture target and populated with the image contents that were
85      * current at the time of the last call to detachFromContext.
86      */
87     status_t attachToContext(uint32_t tex, SurfaceTexture& st);
88 
89     /**
90      * onAcquireBufferLocked amends the ConsumerBase method to update the
91      * mEglSlots array in addition to the ConsumerBase behavior.
92      */
93     void onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st);
94 
95     /**
96      * onReleaseBufferLocked amends the ConsumerBase method to update the
97      * mEglSlots array in addition to the ConsumerBase.
98      */
99     void onReleaseBufferLocked(int slot);
100 
101     /**
102      * onFreeBufferLocked frees up the given buffer slot. If the slot has been
103      * initialized this will release the reference to the GraphicBuffer in that
104      * slot and destroy the EGLImage in that slot.  Otherwise it has no effect.
105      */
106     void onFreeBufferLocked(int slotIndex);
107 
108     /**
109      * onAbandonLocked amends the ConsumerBase method to clear
110      * mCurrentTextureImage in addition to the ConsumerBase behavior.
111      */
112     void onAbandonLocked();
113 
114 protected:
115     struct PendingRelease {
PendingReleasePendingRelease116         PendingRelease()
117               : isPending(false),
118                 currentTexture(-1),
119                 graphicBuffer(),
120                 display(nullptr),
121                 fence(nullptr) {}
122 
123         bool isPending;
124         int currentTexture;
125         sp<GraphicBuffer> graphicBuffer;
126         EGLDisplay display;
127         EGLSyncKHR fence;
128     };
129 
130     /**
131      * This releases the buffer in the slot referenced by mCurrentTexture,
132      * then updates state to refer to the BufferItem, which must be a
133      * newly-acquired buffer. If pendingRelease is not null, the parameters
134      * which would have been passed to releaseBufferLocked upon the successful
135      * completion of the method will instead be returned to the caller, so that
136      * it may call releaseBufferLocked itself later.
137      */
138     status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
139                                     SurfaceTexture& st);
140 
141     /**
142      * Binds mTexName and the current buffer to mTexTarget.  Uses
143      * mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
144      * bind succeeds, this calls doGLFenceWait.
145      */
146     status_t bindTextureImageLocked(SurfaceTexture& st);
147 
148     /**
149      * Gets the current EGLDisplay and EGLContext values, and compares them
150      * to mEglDisplay and mEglContext.  If the fields have been previously
151      * set, the values must match; if not, the fields are set to the current
152      * values.
153      * The contextCheck argument is used to ensure that a GL context is
154      * properly set; when set to false, the check is not performed.
155      */
156     status_t checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck = false);
157 
158     /**
159      * EglImage is a utility class for tracking and creating EGLImageKHRs. There
160      * is primarily just one image per slot, but there is also special cases:
161      *  - For releaseTexImage, we use a debug image (mReleasedTexImage)
162      *  - After freeBuffer, we must still keep the current image/buffer
163      * Reference counting EGLImages lets us handle all these cases easily while
164      * also only creating new EGLImages from buffers when required.
165      */
166     class EglImage : public LightRefBase<EglImage> {
167     public:
168         EglImage(sp<GraphicBuffer> graphicBuffer);
169 
170         /**
171          * createIfNeeded creates an EGLImage if required (we haven't created
172          * one yet, or the EGLDisplay or crop-rect has changed).
173          */
174         status_t createIfNeeded(EGLDisplay display, bool forceCreate = false);
175 
176         /**
177          * This calls glEGLImageTargetTexture2DOES to bind the image to the
178          * texture in the specified texture target.
179          */
180         void bindToTextureTarget(uint32_t texTarget);
181 
graphicBuffer()182         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
graphicBufferHandle()183         const native_handle* graphicBufferHandle() {
184             return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
185         }
186 
187     private:
188         // Only allow instantiation using ref counting.
189         friend class LightRefBase<EglImage>;
190         virtual ~EglImage();
191 
192         // createImage creates a new EGLImage from a GraphicBuffer.
193         EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer);
194 
195         // Disallow copying
196         EglImage(const EglImage& rhs);
197         void operator=(const EglImage& rhs);
198 
199         // mGraphicBuffer is the buffer that was used to create this image.
200         sp<GraphicBuffer> mGraphicBuffer;
201 
202         // mEglImage is the EGLImage created from mGraphicBuffer.
203         EGLImageKHR mEglImage;
204 
205         // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
206         EGLDisplay mEglDisplay;
207 
208         // mCropRect is the crop rectangle passed to EGL when mEglImage
209         // was created.
210         Rect mCropRect;
211     };
212 
213     /**
214      * doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
215      * stream to ensure that it is safe for future OpenGL ES commands to
216      * access the current texture buffer.
217      */
218     status_t doGLFenceWaitLocked(SurfaceTexture& st) const;
219 
220     /**
221      * syncForReleaseLocked performs the synchronization needed to release the
222      * current slot from an OpenGL ES context.  If needed it will set the
223      * current slot's fence to guard against a producer accessing the buffer
224      * before the outstanding accesses have completed.
225      */
226     status_t syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st);
227 
228     /**
229      * returns a graphic buffer used when the texture image has been released
230      */
231     static sp<GraphicBuffer> getDebugTexImageBuffer();
232 
233     /**
234      * The default consumer usage flags that EGLConsumer always sets on its
235      * BufferQueue instance; these will be OR:d with any additional flags passed
236      * from the EGLConsumer user. In particular, EGLConsumer will always
237      * consume buffers as hardware textures.
238      */
239     static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
240 
241     /**
242      * mCurrentTextureImage is the EglImage/buffer of the current texture. It's
243      * possible that this buffer is not associated with any buffer slot, so we
244      * must track it separately in order to support the getCurrentBuffer method.
245      */
246     sp<EglImage> mCurrentTextureImage;
247 
248     /**
249      * EGLSlot contains the information and object references that
250      * EGLConsumer maintains about a BufferQueue buffer slot.
251      */
252     struct EglSlot {
EglSlotEglSlot253         EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
254 
255         /**
256          * mEglImage is the EGLImage created from mGraphicBuffer.
257          */
258         sp<EglImage> mEglImage;
259 
260         /**
261          * mFence is the EGL sync object that must signal before the buffer
262          * associated with this buffer slot may be dequeued. It is initialized
263          * to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
264          * on a compile-time option) set to a new sync object in updateTexImage.
265          */
266         EGLSyncKHR mEglFence;
267     };
268 
269     /**
270      * mEglDisplay is the EGLDisplay with which this EGLConsumer is currently
271      * associated.  It is intialized to EGL_NO_DISPLAY and gets set to the
272      * current display when updateTexImage is called for the first time and when
273      * attachToContext is called.
274      */
275     EGLDisplay mEglDisplay;
276 
277     /**
278      * mEglContext is the OpenGL ES context with which this EGLConsumer is
279      * currently associated.  It is initialized to EGL_NO_CONTEXT and gets set
280      * to the current GL context when updateTexImage is called for the first
281      * time and when attachToContext is called.
282      */
283     EGLContext mEglContext;
284 
285     /**
286      * mEGLSlots stores the buffers that have been allocated by the BufferQueue
287      * for each buffer slot.  It is initialized to null pointers, and gets
288      * filled in with the result of BufferQueue::acquire when the
289      * client dequeues a buffer from a
290      * slot that has not yet been used. The buffer allocated to a slot will also
291      * be replaced if the requested buffer usage or geometry differs from that
292      * of the buffer allocated to a slot.
293      */
294     EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
295 
296     /**
297      * protects static initialization
298      */
299     static Mutex sStaticInitLock;
300 
301     /**
302      * mReleasedTexImageBuffer is a dummy buffer used when in single buffer
303      * mode and releaseTexImage() has been called
304      */
305     static sp<GraphicBuffer> sReleasedTexImageBuffer;
306     sp<EglImage> mReleasedTexImage;
307 };
308 
309 } // namespace android
310