1 /* 2 * Copyright (C) 2011 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 #ifndef _LIBRENDER_COLORBUFFER_H 17 #define _LIBRENDER_COLORBUFFER_H 18 19 #include <EGL/egl.h> 20 #include <EGL/eglext.h> 21 #include <GLES/gl.h> 22 #include <GLES3/gl3.h> 23 #include "base/Stream.h" 24 // #include "android/skin/rect.h" 25 #include <memory> 26 27 #include "DisplayVk.h" 28 #include "FrameworkFormats.h" 29 #include "Hwc2.h" 30 #include "RenderContext.h" 31 #include "snapshot/LazySnapshotObj.h" 32 33 // From ANGLE "src/common/angleutils.h" 34 #define GL_BGR10_A2_ANGLEX 0x6AF9 35 36 class TextureDraw; 37 class TextureResize; 38 class YUVConverter; 39 40 // A class used to model a guest color buffer, and used to implement several 41 // related things: 42 // 43 // - Every gralloc native buffer with HW read or write requirements will 44 // allocate a host ColorBuffer instance. When gralloc_lock() is called, 45 // the guest will use ColorBuffer::readPixels() to read the current content 46 // of the buffer. When gralloc_unlock() is later called, it will call 47 // ColorBuffer::subUpdate() to send the updated pixels. 48 // 49 // - Every guest window EGLSurface is implemented by a host PBuffer 50 // (see WindowSurface.h) that can have a ColorBuffer instance attached to 51 // it (through WindowSurface::attachColorBuffer()). When such an attachment 52 // exists, WindowSurface::flushColorBuffer() will copy the PBuffer's 53 // pixel data into the ColorBuffer. The latter can then be displayed 54 // in the client's UI sub-window with ColorBuffer::post(). 55 // 56 // - Guest EGLImages are implemented as native gralloc buffers too. 57 // The guest glEGLImageTargetTexture2DOES() implementations will end up 58 // calling ColorBuffer::bindToTexture() to bind the current context's 59 // GL_TEXTURE_2D to the buffer. Similarly, the guest versions of 60 // glEGLImageTargetRenderbufferStorageOES() will end up calling 61 // ColorBuffer::bindToRenderbuffer(). 62 // 63 // This forces the implementation to use a host EGLImage to implement each 64 // ColorBuffer. 65 // 66 // As an additional twist. 67 68 class ColorBuffer : 69 public android::snapshot::LazySnapshotObj<ColorBuffer> { 70 public: 71 // Helper interface class used during ColorBuffer operations. This is 72 // introduced to remove coupling from the FrameBuffer class implementation. 73 class Helper { 74 public: 75 Helper() = default; 76 virtual ~Helper(); 77 virtual bool setupContext() = 0; 78 virtual void teardownContext() = 0; 79 virtual TextureDraw* getTextureDraw() const = 0; 80 virtual bool isBound() const = 0; 81 }; 82 83 // Helper class to use a ColorBuffer::Helper context. 84 // Usage is pretty simple: 85 // 86 // { 87 // RecursiveScopedHelperContext context(m_helper); 88 // if (!context.isOk()) { 89 // return false; // something bad happened. 90 // } 91 // .... do something .... 92 // } // automatically calls m_helper->teardownContext(); 93 // 94 class RecursiveScopedHelperContext { 95 public: RecursiveScopedHelperContext(ColorBuffer::Helper * helper)96 RecursiveScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) { 97 if (helper->isBound()) return; 98 if (!helper->setupContext()) { 99 mHelper = NULL; 100 return; 101 } 102 mNeedUnbind = true; 103 } 104 isOk()105 bool isOk() const { return mHelper != NULL; } 106 ~RecursiveScopedHelperContext()107 ~RecursiveScopedHelperContext() { release(); } 108 release()109 void release() { 110 if (mNeedUnbind) { 111 mHelper->teardownContext(); 112 mNeedUnbind = false; 113 } 114 mHelper = NULL; 115 } 116 117 private: 118 ColorBuffer::Helper* mHelper; 119 bool mNeedUnbind = false; 120 }; 121 122 // Create a new ColorBuffer instance. 123 // |p_display| is the host EGLDisplay handle. 124 // |p_width| and |p_height| are the buffer's dimensions in pixels. 125 // |p_internalFormat| is the internal OpenGL pixel format to use, valid 126 // values 127 // are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES. 128 // Implementation is free to use something else though. 129 // |p_frameworkFormat| specifies the original format of the guest 130 // color buffer so that we know how to convert to |p_internalFormat|, 131 // if necessary (otherwise, p_frameworkFormat == 132 // FRAMEWORK_FORMAT_GL_COMPATIBLE). 133 // It is assumed underlying EGL has EGL_KHR_gl_texture_2D_image. 134 // Returns NULL on failure. 135 // |fastBlitSupported|: whether or not this ColorBuffer can be 136 // blitted and posted to swapchain without context switches. 137 static ColorBuffer* create(EGLDisplay p_display, 138 int p_width, 139 int p_height, 140 GLint p_internalFormat, 141 FrameworkFormat p_frameworkFormat, 142 HandleType hndl, 143 Helper* helper, 144 bool fastBlitSupported); 145 146 // Sometimes things happen and we need to reformat the GL texture 147 // used. This function replaces the format of the underlying texture 148 // with the internalformat specified. 149 void reformat(GLint internalformat, GLenum type); 150 151 // Destructor. 152 ~ColorBuffer(); 153 154 // Return ColorBuffer width and height in pixels getWidth()155 GLuint getWidth() const { return m_width; } getHeight()156 GLuint getHeight() const { return m_height; } getInternalFormat()157 GLint getInternalFormat() const { return m_internalFormat; } 158 159 // Read the ColorBuffer instance's pixel values into host memory. 160 void readPixels(int x, 161 int y, 162 int width, 163 int height, 164 GLenum p_format, 165 GLenum p_type, 166 void* pixels); 167 168 void readPixelsScaled(int width, 169 int height, 170 GLenum p_format, 171 GLenum p_type, 172 int skinRotation, 173 void* pixels); 174 175 // Read cached YUV pixel values into host memory. 176 void readPixelsYUVCached(int x, 177 int y, 178 int width, 179 int height, 180 void* pixels, 181 uint32_t pixels_size); 182 183 void swapYUVTextures(uint32_t texture_type, uint32_t* textures); 184 185 // Update the ColorBuffer instance's pixel values from host memory. 186 // |p_format / p_type| are the desired OpenGL color buffer format 187 // and data type. 188 // Otherwise, subUpdate() will explicitly convert |pixels| 189 // to be in |p_format|. 190 void subUpdate(int x, 191 int y, 192 int width, 193 int height, 194 GLenum p_format, 195 GLenum p_type, 196 void* pixels); 197 198 // Completely replaces contents, assuming that |pixels| is a buffer 199 // that is allocated and filled with the same format. 200 bool replaceContents(const void* pixels, size_t numBytes); 201 202 // Reads back entire contents, tightly packed rows. 203 // If the framework format is YUV, it will read back as raw YUV data. 204 bool readContents(size_t* numBytes, void* pixels); 205 206 // Draw a ColorBuffer instance, i.e. blit it to the current guest 207 // framebuffer object / window surface. This doesn't display anything. 208 bool draw(); 209 210 // Scale the underlying texture of this ColorBuffer to match viewport size. 211 // It returns the texture name after scaling. 212 GLuint scale(); 213 // Post this ColorBuffer to the host native sub-window. 214 // |rotation| is the rotation angle in degrees, clockwise in the GL 215 // coordinate space. 216 bool post(GLuint tex, float rotation, float dx, float dy); 217 // Post this ColorBuffer to the host native sub-window and apply 218 // the device screen overlay (if there is one). 219 // |rotation| is the rotation angle in degrees, clockwise in the GL 220 // coordinate space. 221 bool postWithOverlay(GLuint tex, float rotation, float dx, float dy); 222 223 // Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's 224 // EGLImage. This is intended to implement glEGLImageTargetTexture2DOES() 225 // for all GLES versions. 226 bool bindToTexture(); 227 bool bindToTexture2(); 228 229 // Bind the current context's EGL_RENDERBUFFER_OES render buffer to this 230 // ColorBuffer's EGLImage. This is intended to implement 231 // glEGLImageTargetRenderbufferStorageOES() for all GLES versions. 232 bool bindToRenderbuffer(); 233 234 // Copy the content of the current context's read surface to this 235 // ColorBuffer. This is used from WindowSurface::flushColorBuffer(). 236 // Return true on success, false on failure (e.g. no current context). 237 bool blitFromCurrentReadBuffer(); 238 239 // Read the content of the whole ColorBuffer as 32-bit RGBA pixels. 240 // |img| must be a buffer large enough (i.e. width * height * 4). 241 void readback(unsigned char* img, bool readbackBgra = false); 242 // readback() but async (to the specified |buffer|) 243 void readbackAsync(GLuint buffer, bool readbackBgra = false); 244 245 void onSave(android::base::Stream* stream); 246 static ColorBuffer* onLoad(android::base::Stream* stream, 247 EGLDisplay p_display, 248 Helper* helper, 249 bool fastBlitSupported); 250 251 HandleType getHndl() const; 252 isFastBlitSupported()253 bool isFastBlitSupported() const { return m_fastBlitSupported; } 254 void postLayer(ComposeLayer* l, int frameWidth, int frameHeight); 255 GLuint getTexture(); 256 getDisplayBufferVk()257 const std::shared_ptr<DisplayVk::DisplayBufferInfo>& getDisplayBufferVk() 258 const { 259 return m_displayBufferVk; 260 }; 261 262 // ColorBuffer backing change methods 263 // 264 // Change to opaque fd or opaque win32 handle-backed VkDeviceMemory 265 // via GL_EXT_memory_objects 266 bool importMemory( 267 #ifdef _WIN32 268 void* handle, 269 #else 270 int handle, 271 #endif 272 uint64_t size, bool dedicated, bool linearTiling, bool vulkanOnly, 273 std::shared_ptr<DisplayVk::DisplayBufferInfo> displayBufferVk); 274 // Change to EGL native pixmap 275 bool importEglNativePixmap(void* pixmap); 276 // Change to some other native EGL image. nativeEglImage must not have 277 // been created from our s_egl.eglCreateImage. 278 bool importEglImage(void* nativeEglImage); 279 280 void setInUse(bool inUse); isInUse()281 bool isInUse() const { return m_inUse; } 282 283 void setSync(bool debug = false); 284 void waitSync(bool debug = false); setDisplay(uint32_t displayId)285 void setDisplay(uint32_t displayId) { m_displayId = displayId; } getDisplay()286 uint32_t getDisplay() { return m_displayId; } getFrameworkFormat()287 FrameworkFormat getFrameworkFormat() { return m_frameworkFormat; } 288 public: 289 void restore(); 290 291 private: 292 ColorBuffer(EGLDisplay display, HandleType hndl, Helper* helper); 293 // Helper function to get contents and clear current texture and EGL image. 294 std::vector<uint8_t> getContentsAndClearStorage(); 295 // Helper function to rebind EGL image as texture. Assumes storage cleared. 296 void restoreContentsAndEglImage(const std::vector<uint8_t>& contents, EGLImageKHR image); 297 // Helper function that does the above two operations in one go. 298 void rebindEglImage(EGLImageKHR image); 299 300 private: 301 GLuint m_tex = 0; 302 GLuint m_blitTex = 0; 303 EGLImageKHR m_eglImage = nullptr; 304 EGLImageKHR m_blitEGLImage = nullptr; 305 GLuint m_width = 0; 306 GLuint m_height = 0; 307 GLuint m_fbo = 0; 308 GLint m_internalFormat = 0; 309 GLint m_sizedInternalFormat = 0; 310 311 // This is helpful for bindFbo which may skip too many steps after the egl 312 // image is replaced. 313 bool m_needFboReattach = false; 314 315 // |m_format| and |m_type| are for reformatting purposes only 316 // to work around bugs in the guest. No need to snapshot those. 317 bool m_needFormatCheck = true; 318 GLenum m_format = 0; // TODO: Currently we treat m_internalFormat same as 319 // m_format, but if underlying drivers can take it, 320 // it may be a better idea to distinguish them, with 321 // m_internalFormat as an explicitly sized format; then 322 // guest can specify everything in terms of explicitly 323 // sized internal formats and things will get less 324 // ambiguous. 325 GLenum m_type = 0; 326 327 EGLDisplay m_display = nullptr; 328 Helper* m_helper = nullptr; 329 TextureResize* m_resizer = nullptr; 330 FrameworkFormat m_frameworkFormat; 331 GLuint m_yuv_conversion_fbo = 0; // FBO to offscreen-convert YUV to RGB 332 GLuint m_scaleRotationFbo = 0; // FBO to read scaled rotation pixels 333 std::unique_ptr<YUVConverter> m_yuv_converter; 334 HandleType mHndl; 335 336 GLsync m_sync = nullptr; 337 bool m_fastBlitSupported = false; 338 339 GLenum m_asyncReadbackType = GL_UNSIGNED_BYTE; 340 size_t m_numBytes = 0; 341 342 bool m_importedMemory = false; 343 GLuint m_memoryObject = 0; 344 bool m_inUse = false; 345 bool m_isBuffer = false; 346 GLuint m_buf = 0; 347 uint32_t m_displayId = 0; 348 bool m_BRSwizzle = false; 349 // Won't share with others so that m_displayBufferVk lives shorter than this 350 // ColorBuffer. 351 std::shared_ptr<DisplayVk::DisplayBufferInfo> m_displayBufferVk; 352 }; 353 354 typedef std::shared_ptr<ColorBuffer> ColorBufferPtr; 355 356 class Buffer : public android::snapshot::LazySnapshotObj<Buffer> { 357 public: create(size_t sizeBytes,HandleType hndl)358 static Buffer* create(size_t sizeBytes, HandleType hndl) { 359 return new Buffer(sizeBytes, hndl); 360 } 361 362 ~Buffer() = default; 363 getHndl()364 HandleType getHndl() const { return m_handle; } getSize()365 size_t getSize() const { return m_sizeBytes; } 366 367 protected: Buffer(size_t sizeBytes,HandleType hndl)368 Buffer(size_t sizeBytes, HandleType hndl) 369 : m_handle(hndl), m_sizeBytes(sizeBytes) {} 370 371 private: 372 HandleType m_handle; 373 size_t m_sizeBytes; 374 }; 375 376 typedef std::shared_ptr<Buffer> BufferPtr; 377 378 #endif 379