• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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