summaryrefslogtreecommitdiff
path: root/stream-servers/ColorBuffer.h
blob: 81530041c47a13f0d60ba5f8da06e2b477921f14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*
* 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.
*/
#ifndef _LIBRENDER_COLORBUFFER_H
#define _LIBRENDER_COLORBUFFER_H

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES3/gl3.h>
#include "base/Stream.h"
// #include "android/skin/rect.h"
#include <memory>

#include "DisplayVk.h"
#include "FrameworkFormats.h"
#include "Hwc2.h"
#include "RenderContext.h"
#include "snapshot/LazySnapshotObj.h"

// From ANGLE "src/common/angleutils.h"
#define GL_BGR10_A2_ANGLEX 0x6AF9

class TextureDraw;
class TextureResize;
class YUVConverter;

// 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 ColorBuffer instance. When gralloc_lock() is called,
//    the guest will use ColorBuffer::readPixels() to read the current content
//    of the buffer. When gralloc_unlock() is later called, it will call
//    ColorBuffer::subUpdate() to send the updated pixels.
//
//  - Every guest window EGLSurface is implemented by a host PBuffer
//    (see WindowSurface.h) that can have a ColorBuffer instance attached to
//    it (through WindowSurface::attachColorBuffer()). When such an attachment
//    exists, WindowSurface::flushColorBuffer() will copy the PBuffer's
//    pixel data into the ColorBuffer. The latter can then be displayed
//    in the client's UI sub-window with ColorBuffer::post().
//
//  - Guest EGLImages are implemented as native gralloc buffers too.
//    The guest glEGLImageTargetTexture2DOES() implementations will end up
//    calling ColorBuffer::bindToTexture() to bind the current context's
//    GL_TEXTURE_2D to the buffer. Similarly, the guest versions of
//    glEGLImageTargetRenderbufferStorageOES() will end up calling
//    ColorBuffer::bindToRenderbuffer().
//
// This forces the implementation to use a host EGLImage to implement each
// ColorBuffer.
//
// As an additional twist.

class ColorBuffer :
        public android::snapshot::LazySnapshotObj<ColorBuffer> {
public:
    // Helper interface class used during ColorBuffer operations. This is
    // introduced to remove coupling from the FrameBuffer class implementation.
    class Helper {
    public:
        Helper() = default;
        virtual ~Helper();
        virtual bool setupContext() = 0;
        virtual void teardownContext() = 0;
        virtual TextureDraw* getTextureDraw() const = 0;
        virtual bool isBound() const = 0;
    };

    // Helper class to use a ColorBuffer::Helper context.
    // Usage is pretty simple:
    //
    //     {
    //        RecursiveScopedHelperContext context(m_helper);
    //        if (!context.isOk()) {
    //            return false;   // something bad happened.
    //        }
    //        .... do something ....
    //     }   // automatically calls m_helper->teardownContext();
    //
    class RecursiveScopedHelperContext {
    public:
        RecursiveScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) {
            if (helper->isBound()) return;
            if (!helper->setupContext()) {
                mHelper = NULL;
                return;
            }
            mNeedUnbind = true;
        }

        bool isOk() const { return mHelper != NULL; }

        ~RecursiveScopedHelperContext() { release(); }

        void release() {
            if (mNeedUnbind) {
                mHelper->teardownContext();
                mNeedUnbind = false;
            }
            mHelper = NULL;
        }

    private:
        ColorBuffer::Helper* mHelper;
        bool mNeedUnbind = false;
    };

    // Create a new ColorBuffer instance.
    // |p_display| is the host EGLDisplay handle.
    // |p_width| and |p_height| are the buffer's dimensions in pixels.
    // |p_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.
    // |p_frameworkFormat| specifies the original format of the guest
    // color buffer so that we know how to convert to |p_internalFormat|,
    // if necessary (otherwise, p_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 ColorBuffer can be
    // blitted and posted to swapchain without context switches.
    static ColorBuffer* create(EGLDisplay p_display,
                               int p_width,
                               int p_height,
                               GLint p_internalFormat,
                               FrameworkFormat p_frameworkFormat,
                               HandleType hndl,
                               Helper* helper,
                               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.
    ~ColorBuffer();

    // Return ColorBuffer 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 ColorBuffer 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);

    void readPixelsScaled(int width,
                          int height,
                          GLenum p_format,
                          GLenum p_type,
                          int skinRotation,
                          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(uint32_t texture_type, uint32_t* textures);

    // Update the ColorBuffer 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|.
    void subUpdate(int x,
                   int y,
                   int width,
                   int height,
                   GLenum p_format,
                   GLenum p_type,
                   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 ColorBuffer instance, i.e. blit it to the current guest
    // framebuffer object / window surface. This doesn't display anything.
    bool draw();

    // Scale the underlying texture of this ColorBuffer to match viewport size.
    // It returns the texture name after scaling.
    GLuint scale();
    // 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 ColorBuffer 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 postWithOverlay(GLuint tex, float rotation, float dx, float dy);

    // Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer'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
    // ColorBuffer'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
    // ColorBuffer. 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 ColorBuffer 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 ColorBuffer* onLoad(android::base::Stream* stream,
                               EGLDisplay p_display,
                               Helper* helper,
                               bool fastBlitSupported);

    HandleType getHndl() const;

    bool isFastBlitSupported() const { return m_fastBlitSupported; }
    void postLayer(ComposeLayer* l, int frameWidth, int frameHeight);
    GLuint getTexture();

    const std::shared_ptr<DisplayVk::DisplayBufferInfo>& getDisplayBufferVk()
        const {
        return m_displayBufferVk;
    };

    bool importMemory(
#ifdef _WIN32
        void* handle,
#else
        int handle,
#endif
        uint64_t size, bool dedicated, bool linearTiling, bool vulkanOnly,
        std::shared_ptr<DisplayVk::DisplayBufferInfo> displayBufferVk);
    void setInUse(bool inUse);
    bool isInUse() const { return m_inUse; }

    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:
    ColorBuffer(EGLDisplay display, HandleType hndl, Helper* helper);

private:
    GLuint m_tex = 0;
    GLuint m_blitTex = 0;
    EGLImageKHR m_eglImage = nullptr;
    EGLImageKHR m_blitEGLImage = nullptr;
    GLuint m_width = 0;
    GLuint m_height = 0;
    GLuint m_fbo = 0;
    GLint m_internalFormat = 0;
    GLint m_sizedInternalFormat = 0;

    // |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;
    Helper* m_helper = 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;

    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;
    // Won't share with others so that m_displayBufferVk lives shorter than this
    // ColorBuffer.
    std::shared_ptr<DisplayVk::DisplayBufferInfo> m_displayBufferVk;
};

typedef std::shared_ptr<ColorBuffer> ColorBufferPtr;

class Buffer : public android::snapshot::LazySnapshotObj<Buffer> {
public:
    static Buffer* create(size_t sizeBytes, HandleType hndl) {
        return new Buffer(sizeBytes, hndl);
    }

    ~Buffer() = default;

    HandleType getHndl() const { return m_handle; }
    size_t getSize() const { return m_sizeBytes; }

protected:
    Buffer(size_t sizeBytes, HandleType hndl)
        : m_handle(hndl), m_sizeBytes(sizeBytes) {}

private:
    HandleType m_handle;
    size_t m_sizeBytes;
};

typedef std::shared_ptr<Buffer> BufferPtr;

#endif