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