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