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