| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| #include <GLES/gl.h> |
| #include <GLES3/gl3.h> |
| |
| #include <memory> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| #include "BorrowedImage.h" |
| #include "ContextHelper.h" |
| #include "FrameworkFormats.h" |
| #include "Handle.h" |
| #include "Hwc2.h" |
| #include "aemu/base/ManagedDescriptor.hpp" |
| #include "aemu/base/files/Stream.h" |
| #include "render-utils/Renderer.h" |
| |
| // From ANGLE "src/common/angleutils.h" |
| #define GL_BGR10_A2_ANGLEX 0x6AF9 |
| |
| // A class used to model a guest color buffer, and used to implement several |
| // related things: |
| // |
| // - Every gralloc native buffer with HW read or write requirements will |
| // allocate a host ColorBufferGl instance. When gralloc_lock() is called, |
| // the guest will use ColorBufferGl::readPixels() to read the current content |
| // of the buffer. When gralloc_unlock() is later called, it will call |
| // ColorBufferGl::subUpdate() to send the updated pixels. |
| // |
| // - Every guest window EGLSurface is implemented by a host PBuffer |
| // (see WindowSurface.h) that can have a ColorBufferGl instance attached to |
| // it (through WindowSurface::attachColorBuffer()). When such an attachment |
| // exists, WindowSurface::flushColorBuffer() will copy the PBuffer's |
| // pixel data into the ColorBufferGl. The latter can then be displayed |
| // in the client's UI sub-window with ColorBufferGl::post(). |
| // |
| // - Guest EGLImages are implemented as native gralloc buffers too. |
| // The guest glEGLImageTargetTexture2DOES() implementations will end up |
| // calling ColorBufferGl::bindToTexture() to bind the current context's |
| // GL_TEXTURE_2D to the buffer. Similarly, the guest versions of |
| // glEGLImageTargetRenderbufferStorageOES() will end up calling |
| // ColorBufferGl::bindToRenderbuffer(). |
| // |
| // This forces the implementation to use a host EGLImage to implement each |
| // ColorBufferGl. |
| // |
| // As an additional twist. |
| |
| namespace gfxstream { |
| namespace gl { |
| |
| class TextureDraw; |
| class TextureResize; |
| class YUVConverter; |
| |
| class ColorBufferGl { |
| public: |
| // Create a new ColorBufferGl instance. |
| // |display| is the host EGLDisplay handle. |
| // |width| and |height| are the buffer's dimensions in pixels. |
| // |internalFormat| is the internal OpenGL pixel format to use, valid |
| // values |
| // are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES. |
| // Implementation is free to use something else though. |
| // |frameworkFormat| specifies the original format of the guest |
| // color buffer so that we know how to convert to |internalFormat|, |
| // if necessary (otherwise, frameworkFormat == |
| // FRAMEWORK_FORMAT_GL_COMPATIBLE). |
| // It is assumed underlying EGL has EGL_KHR_gl_texture_2D_image. |
| // Returns NULL on failure. |
| // |fastBlitSupported|: whether or not this ColorBufferGl can be |
| // blitted and posted to swapchain without context switches. |
| static std::unique_ptr<ColorBufferGl> create(EGLDisplay display, int width, int height, |
| GLint internalFormat, |
| FrameworkFormat frameworkFormat, HandleType handle, |
| ContextHelper* helper, TextureDraw* textureDraw, |
| bool fastBlitSupported); |
| |
| // Sometimes things happen and we need to reformat the GL texture |
| // used. This function replaces the format of the underlying texture |
| // with the internalformat specified. |
| void reformat(GLint internalformat, GLenum type); |
| |
| // Destructor. |
| ~ColorBufferGl(); |
| |
| // Return ColorBufferGl width and height in pixels |
| GLuint getWidth() const { return m_width; } |
| GLuint getHeight() const { return m_height; } |
| GLint getInternalFormat() const { return m_internalFormat; } |
| |
| // Read the ColorBufferGl instance's pixel values into host memory. |
| void readPixels(int x, |
| int y, |
| int width, |
| int height, |
| GLenum p_format, |
| GLenum p_type, |
| void* pixels); |
| // Read the ColorBuffer instance's pixel values by first scaling |
| // to the size of width x height, then clipping a |rect| from the |
| // screen defined by width x height. |
| void readPixelsScaled(int width, int height, GLenum p_format, GLenum p_type, int skinRotation, |
| Rect rect, void* pixels); |
| |
| // Read cached YUV pixel values into host memory. |
| void readPixelsYUVCached(int x, |
| int y, |
| int width, |
| int height, |
| void* pixels, |
| uint32_t pixels_size); |
| |
| void swapYUVTextures(FrameworkFormat texture_type, GLuint* textures); |
| |
| // Update the ColorBufferGl instance's pixel values from host memory. |
| // |p_format / p_type| are the desired OpenGL color buffer format |
| // and data type. |
| // Otherwise, subUpdate() will explicitly convert |pixels| |
| // to be in |p_format|. |
| bool subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type, |
| const void* pixels); |
| bool subUpdateFromFrameworkFormat(int x, int y, int width, int height, |
| FrameworkFormat fwkFormat, GLenum p_format, GLenum p_type, |
| const void* pixels); |
| |
| // Completely replaces contents, assuming that |pixels| is a buffer |
| // that is allocated and filled with the same format. |
| bool replaceContents(const void* pixels, size_t numBytes); |
| |
| // Reads back entire contents, tightly packed rows. |
| // If the framework format is YUV, it will read back as raw YUV data. |
| bool readContents(size_t* numBytes, void* pixels); |
| |
| // Draw a ColorBufferGl instance, i.e. blit it to the current guest |
| // framebuffer object / window surface. This doesn't display anything. |
| bool draw(); |
| |
| // Returns the texture name of a texture containing the contents of this |
| // ColorBuffer but that is scaled to match the current viewport. This |
| // ColorBuffer retains ownership of the returned texture. |
| GLuint getViewportScaledTexture(); |
| // Post this ColorBuffer to the host native sub-window. |
| // |rotation| is the rotation angle in degrees, clockwise in the GL |
| // coordinate space. |
| bool post(GLuint tex, float rotation, float dx, float dy); |
| // Post this ColorBufferGl to the host native sub-window and apply |
| // the device screen overlay (if there is one). |
| // |rotation| is the rotation angle in degrees, clockwise in the GL |
| // coordinate space. |
| bool postViewportScaledWithOverlay(float rotation, float dx, float dy); |
| |
| // Bind the current context's EGL_TEXTURE_2D texture to this ColorBufferGl's |
| // EGLImage. This is intended to implement glEGLImageTargetTexture2DOES() |
| // for all GLES versions. |
| bool bindToTexture(); |
| bool bindToTexture2(); |
| |
| // Bind the current context's EGL_RENDERBUFFER_OES render buffer to this |
| // ColorBufferGl's EGLImage. This is intended to implement |
| // glEGLImageTargetRenderbufferStorageOES() for all GLES versions. |
| bool bindToRenderbuffer(); |
| |
| // Copy the content of the current context's read surface to this |
| // ColorBufferGl. This is used from WindowSurface::flushColorBuffer(). |
| // Return true on success, false on failure (e.g. no current context). |
| bool blitFromCurrentReadBuffer(); |
| |
| // Read the content of the whole ColorBufferGl as 32-bit RGBA pixels. |
| // |img| must be a buffer large enough (i.e. width * height * 4). |
| void readback(unsigned char* img, bool readbackBgra = false); |
| // readback() but async (to the specified |buffer|) |
| void readbackAsync(GLuint buffer, bool readbackBgra = false); |
| |
| void onSave(android::base::Stream* stream); |
| static std::unique_ptr<ColorBufferGl> onLoad(android::base::Stream* stream, |
| EGLDisplay p_display, ContextHelper* helper, |
| TextureDraw* textureDraw, bool fastBlitSupported); |
| |
| HandleType getHndl() const; |
| |
| bool isFastBlitSupported() const { return m_fastBlitSupported; } |
| void postLayer(const ComposeLayer& l, int frameWidth, int frameHeight); |
| GLuint getTexture(); |
| |
| std::unique_ptr<BorrowedImageInfo> getBorrowedImageInfo(); |
| |
| // ColorBufferGl backing change methods |
| // |
| // Change to opaque fd or opaque win32 handle-backed VkDeviceMemory |
| // via GL_EXT_memory_objects |
| bool importMemory(android::base::ManagedDescriptor externalDescriptor, uint64_t size, |
| bool dedicated, bool linearTiling); |
| // Change to EGL native pixmap |
| bool importEglNativePixmap(void* pixmap, bool preserveContent); |
| // Change to some other native EGL image. nativeEglImage must not have |
| // been created from our s_egl.eglCreateImage. |
| bool importEglImage(void* nativeEglImage, bool preserveContent); |
| |
| void setSync(bool debug = false); |
| void waitSync(bool debug = false); |
| void setDisplay(uint32_t displayId) { m_displayId = displayId; } |
| uint32_t getDisplay() { return m_displayId; } |
| FrameworkFormat getFrameworkFormat() { return m_frameworkFormat; } |
| |
| public: |
| void restore(); |
| |
| private: |
| ColorBufferGl(EGLDisplay display, HandleType hndl, GLuint width, GLuint height, |
| ContextHelper* helper, TextureDraw* textureDraw); |
| // Helper function to get contents. |
| std::vector<uint8_t> getContents(); |
| // Helper function to clear current EGL image. |
| void clearStorage(); |
| // Helper function to bind EGL image as texture. Assumes storage cleared. |
| void restoreEglImage(EGLImageKHR image); |
| // Helper function that does the above two operations in one go. |
| void rebindEglImage(EGLImageKHR image, bool preserveContent); |
| |
| private: |
| GLuint m_tex = 0; |
| GLuint m_blitTex = 0; |
| EGLImageKHR m_eglImage = nullptr; |
| EGLImageKHR m_blitEGLImage = nullptr; |
| const GLuint m_width = 0; |
| const GLuint m_height = 0; |
| GLuint m_fbo = 0; |
| GLint m_internalFormat = 0; |
| GLint m_sizedInternalFormat = 0; |
| |
| // This is helpful for bindFbo which may skip too many steps after the egl |
| // image is replaced. |
| bool m_needFboReattach = false; |
| |
| // |m_format| and |m_type| are for reformatting purposes only |
| // to work around bugs in the guest. No need to snapshot those. |
| bool m_needFormatCheck = true; |
| GLenum m_format = 0; // TODO: Currently we treat m_internalFormat same as |
| // m_format, but if underlying drivers can take it, |
| // it may be a better idea to distinguish them, with |
| // m_internalFormat as an explicitly sized format; then |
| // guest can specify everything in terms of explicitly |
| // sized internal formats and things will get less |
| // ambiguous. |
| GLenum m_type = 0; |
| |
| EGLDisplay m_display = nullptr; |
| ContextHelper* m_helper = nullptr; |
| TextureDraw* m_textureDraw = nullptr; |
| TextureResize* m_resizer = nullptr; |
| FrameworkFormat m_frameworkFormat; |
| GLuint m_yuv_conversion_fbo = 0; // FBO to offscreen-convert YUV to RGB |
| GLuint m_scaleRotationFbo = 0; // FBO to read scaled rotation pixels |
| std::unique_ptr<YUVConverter> m_yuv_converter; |
| HandleType mHndl; |
| |
| GLsync m_sync = nullptr; |
| bool m_fastBlitSupported = false; |
| bool m_vulkanOnly = false; |
| |
| GLenum m_asyncReadbackType = GL_UNSIGNED_BYTE; |
| size_t m_numBytes = 0; |
| |
| bool m_importedMemory = false; |
| GLuint m_memoryObject = 0; |
| bool m_inUse = false; |
| bool m_isBuffer = false; |
| GLuint m_buf = 0; |
| uint32_t m_displayId = 0; |
| bool m_BRSwizzle = false; |
| }; |
| |
| typedef std::shared_ptr<ColorBufferGl> ColorBufferGlPtr; |
| |
| } // namespace gl |
| } // namespace gfxstream |