Stan Iliev | 564ca3e | 2018-09-04 22:00:00 +0000 | [diff] [blame] | 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 { |
| 118 | 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 | |
| 184 | const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } |
| 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 { |
| 255 | 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 |