summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
blob: 856619c9f29ca377a638362f3e0598a2ef23557c (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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/*
 * Copyright (c) 2010, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DrawingBuffer_h
#define DrawingBuffer_h

#include "platform/PlatformExport.h"
#include "platform/geometry/IntSize.h"
#include "platform/graphics/GraphicsTypes3D.h"
#include "platform/graphics/gpu/WebGLImageConversion.h"
#include "public/platform/WebExternalTextureLayerClient.h"
#include "public/platform/WebExternalTextureMailbox.h"
#include "public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "wtf/Deque.h"
#include "wtf/Noncopyable.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"

namespace gpu {
namespace gles2 {
class GLES2Interface;
}
}

namespace WTF {
class ArrayBufferContents;
}

namespace blink {

class Extensions3DUtil;
class ImageBuffer;
class WebExternalBitmap;
class WebExternalTextureLayer;
class WebGraphicsContext3D;
class WebLayer;

// Manages a rendering target (framebuffer + attachment) for a canvas.  Can publish its rendering
// results to a WebLayer for compositing.
class PLATFORM_EXPORT DrawingBuffer : public RefCounted<DrawingBuffer>, public WebExternalTextureLayerClient  {
    WTF_MAKE_NONCOPYABLE(DrawingBuffer);
public:
    enum PreserveDrawingBuffer {
        Preserve,
        Discard
    };

    static PassRefPtr<DrawingBuffer> create(PassOwnPtr<WebGraphicsContext3D>, const IntSize&, PreserveDrawingBuffer, WebGraphicsContext3D::Attributes requestedAttributes);
    static void forceNextDrawingBufferCreationToFail();

    ~DrawingBuffer() override;

    // Destruction will be completed after all mailboxes are released.
    void beginDestruction();

    // Issues a glClear() on all framebuffers associated with this DrawingBuffer. The caller is responsible for
    // making the context current and setting the clear values and masks. Modifies the framebuffer binding.
    void clearFramebuffers(GLbitfield clearMask);

    // Indicates whether the DrawingBuffer internally allocated a packed depth-stencil renderbuffer
    // in the situation where the end user only asked for a depth buffer. In this case, we need to
    // upgrade clears of the depth buffer to clears of the depth and stencil buffers in order to
    // avoid performance problems on some GPUs.
    bool hasImplicitStencilBuffer() const;

    // Given the desired buffer size, provides the largest dimensions that will fit in the pixel budget.
    static IntSize adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize);
    bool reset(const IntSize&);
    void bind(GLenum target);
    IntSize size() const { return m_size; }

    // Copies the multisample color buffer to the normal color buffer and leaves m_fbo bound.
    void commit();

    // commit should copy the full multisample buffer, and not respect the
    // current scissor bounds. Track the state of the scissor test so that it
    // can be disabled during calls to commit.
    void setScissorEnabled(bool scissorEnabled) { m_scissorEnabled = scissorEnabled; }

    // The DrawingBuffer needs to track the texture bound to texture unit 0.
    // The bound texture is tracked to avoid costly queries during rendering.
    void setTexture2DBinding(Platform3DObject texture) { m_texture2DBinding = texture; }

    // The DrawingBuffer needs to track the currently bound framebuffer so it
    // restore the binding when needed.
    void setFramebufferBinding(GLenum target, Platform3DObject fbo)
    {
        switch (target) {
        case GL_FRAMEBUFFER:
            m_drawFramebufferBinding = fbo;
            m_readFramebufferBinding = fbo;
            break;
        case GL_DRAW_FRAMEBUFFER:
            m_drawFramebufferBinding = fbo;
            break;
        case GL_READ_FRAMEBUFFER:
            m_readFramebufferBinding = fbo;
            break;
        default:
            ASSERT(0);
        }
    }

    // Track the currently active texture unit. Texture unit 0 is used as host for a scratch
    // texture.
    void setActiveTextureUnit(GLint textureUnit) { m_activeTextureUnit = textureUnit; }

    bool multisample() const;

    Platform3DObject framebuffer() const;

    bool discardFramebufferSupported() const { return m_discardFramebufferSupported; }

    void markContentsChanged();
    void setBufferClearNeeded(bool);
    bool bufferClearNeeded() const;
    void setIsHidden(bool);
    void setFilterQuality(SkFilterQuality);

    WebLayer* platformLayer();

    WebGraphicsContext3D* context();
    gpu::gles2::GLES2Interface* contextGL();

    // Returns the actual context attributes for this drawing buffer which may differ from the
    // requested context attributes due to implementation limits.
    WebGraphicsContext3D::Attributes getActualAttributes() const { return m_actualAttributes; }

    // WebExternalTextureLayerClient implementation.
    bool prepareMailbox(WebExternalTextureMailbox*, WebExternalBitmap*) override;
    void mailboxReleased(const WebExternalTextureMailbox&, bool lostResource = false) override;

    // Destroys the TEXTURE_2D binding for the owned context
    bool copyToPlatformTexture(WebGraphicsContext3D*, gpu::gles2::GLES2Interface*, Platform3DObject texture, GLenum internalFormat,
        GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, SourceDrawingBuffer);

    void setPackAlignment(GLint param);

    bool paintRenderingResultsToImageData(int&, int&, SourceDrawingBuffer, WTF::ArrayBufferContents&);

    int sampleCount() const { return m_sampleCount; }
    bool explicitResolveOfMultisampleData() const { return m_antiAliasingMode == MSAAExplicitResolve; }

    // Bind to m_drawFramebufferBinding or m_readFramebufferBinding if it's not 0.
    // Otherwise, bind to the default FBO.
    void restoreFramebufferBindings();

    void addNewMailboxCallback(PassOwnPtr<SameThreadClosure> closure) { m_newMailboxCallback = std::move(closure); }

protected: // For unittests
    DrawingBuffer(
        PassOwnPtr<WebGraphicsContext3D>,
        gpu::gles2::GLES2Interface*,
        PassOwnPtr<Extensions3DUtil>,
        bool multisampleExtensionSupported,
        bool discardFramebufferSupported,
        PreserveDrawingBuffer,
        WebGraphicsContext3D::Attributes requestedAttributes);

    bool initialize(const IntSize&);

private:
    struct TextureParameters {
        DISALLOW_NEW();
        WGC3Denum target;
        WGC3Denum internalColorFormat;
        WGC3Denum colorFormat;
        WGC3Denum internalRenderbufferFormat;

        TextureParameters()
            : target(0)
            , internalColorFormat(0)
            , colorFormat(0)
            , internalRenderbufferFormat(0)
        {
        }
    };

    // If we used CHROMIUM_image as the backing storage for our buffers,
    // we need to know the mapping from texture id to image.
    struct TextureInfo {
        DISALLOW_NEW();
        Platform3DObject textureId;
        WGC3Duint imageId;
        TextureParameters parameters;

        TextureInfo()
            : textureId(0)
            , imageId(0)
        {
        }
    };

    struct MailboxInfo : public RefCounted<MailboxInfo> {
        WTF_MAKE_NONCOPYABLE(MailboxInfo);

    public:
        MailboxInfo() {}

        WebExternalTextureMailbox mailbox;
        TextureInfo textureInfo;
        IntSize size;
        // This keeps the parent drawing buffer alive as long as the compositor is
        // referring to one of the mailboxes DrawingBuffer produced. The parent drawing buffer is
        // cleared when the compositor returns the mailbox. See mailboxReleased().
        RefPtr<DrawingBuffer> m_parentDrawingBuffer;
    };

    // The texture parameters to use for a texture that will be backed by a
    // CHROMIUM_image.
    TextureParameters chromiumImageTextureParameters();

    // The texture parameters to use for a default texture.
    TextureParameters defaultTextureParameters();

    void mailboxReleasedWithoutRecycling(const WebExternalTextureMailbox&);

    // Creates and binds a texture with the given parameters. Returns 0 on
    // failure, or the newly created texture id on success. The caller takes
    // ownership of the newly created texture.
    WebGLId createColorTexture(const TextureParameters&);

    // Create the depth/stencil and multisample buffers, if needed.
    void createSecondaryBuffers();
    bool resizeFramebuffer(const IntSize&);
    bool resizeMultisampleFramebuffer(const IntSize&);
    void resizeDepthStencil(const IntSize&);

    void clearPlatformLayer();

    PassRefPtr<MailboxInfo> recycledMailbox();
    PassRefPtr<MailboxInfo> createNewMailbox(const TextureInfo&);
    void deleteMailbox(const WebExternalTextureMailbox&);
    void freeRecycledMailboxes();

    // Updates the current size of the buffer, ensuring that s_currentResourceUsePixels is updated.
    void setSize(const IntSize& size);

    // This is the order of bytes to use when doing a readback.
    enum ReadbackOrder {
        ReadbackRGBA,
        ReadbackSkia
    };

    // Helper function which does a readback from the currently-bound
    // framebuffer into a buffer of a certain size with 4-byte pixels.
    void readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder, WebGLImageConversion::AlphaOp);

    // Helper function to flip a bitmap vertically.
    void flipVertically(uint8_t* data, int width, int height);

    // Helper to texImage2D with pixel==0 case: pixels are initialized to 0.
    // By default, alignment is 4, the OpenGL default setting.
    void texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint alignment = 4);
    // Allocate buffer storage to be sent to compositor using either texImage2D or CHROMIUM_image based on available support.
    void deleteChromiumImageForTexture(TextureInfo*);

    // Tries to create a CHROMIUM_image backed texture if
    // RuntimeEnabledFeatures::webGLImageChromiumEnabled() is true. On failure,
    // or if the flag is false, creates a default texture.
    TextureInfo createTextureAndAllocateMemory(const IntSize&);

    // Creates and allocates space for a default texture.
    TextureInfo createDefaultTextureAndAllocateMemory(const IntSize&);

    void resizeTextureMemory(TextureInfo*, const IntSize&);

    void attachColorBufferToCurrentFBO();

    PreserveDrawingBuffer m_preserveDrawingBuffer;
    bool m_scissorEnabled;
    Platform3DObject m_texture2DBinding;
    Platform3DObject m_drawFramebufferBinding;
    Platform3DObject m_readFramebufferBinding;
    GLenum m_activeTextureUnit;

    OwnPtr<WebGraphicsContext3D> m_context;
    gpu::gles2::GLES2Interface* m_gl; // Lifetime is tied to the m_context.
    OwnPtr<Extensions3DUtil> m_extensionsUtil;
    IntSize m_size;
    WebGraphicsContext3D::Attributes m_requestedAttributes;
    bool m_multisampleExtensionSupported;
    bool m_discardFramebufferSupported;
    Platform3DObject m_fbo;
    // DrawingBuffer's output is double-buffered. m_colorBuffer is the back buffer.
    TextureInfo m_colorBuffer;
    struct FrontBufferInfo {
        TextureInfo texInfo;
        WebExternalTextureMailbox mailbox;
    };
    FrontBufferInfo m_frontColorBuffer;

    OwnPtr<SameThreadClosure> m_newMailboxCallback;

    // This is used when the user requests either a depth or stencil buffer.
    Platform3DObject m_depthStencilBuffer;

    // For multisampling.
    Platform3DObject m_multisampleFBO;
    Platform3DObject m_multisampleColorBuffer;

    // True if our contents have been modified since the last presentation of this buffer.
    bool m_contentsChanged;

    // True if commit() has been called since the last time markContentsChanged() had been called.
    bool m_contentsChangeCommitted;
    bool m_bufferClearNeeded;

    enum AntialiasingMode {
        None,
        MSAAImplicitResolve,
        MSAAExplicitResolve,
        ScreenSpaceAntialiasing,
    };

    AntialiasingMode m_antiAliasingMode;

    WebGraphicsContext3D::Attributes m_actualAttributes;
    int m_maxTextureSize;
    int m_sampleCount;
    int m_packAlignment;
    bool m_destructionInProgress;
    bool m_isHidden;
    SkFilterQuality m_filterQuality;

    OwnPtr<WebExternalTextureLayer> m_layer;

    // All of the mailboxes that this DrawingBuffer has ever created.
    Vector<RefPtr<MailboxInfo>> m_textureMailboxes;
    // Mailboxes that were released by the compositor can be used again by this DrawingBuffer.
    Deque<WebExternalTextureMailbox> m_recycledMailboxQueue;

    // If the width and height of the Canvas's backing store don't
    // match those that we were given in the most recent call to
    // reshape(), then we need an intermediate bitmap to read back the
    // frame buffer into. This seems to happen when CSS styles are
    // used to resize the Canvas.
    SkBitmap m_resizingBitmap;

    // Used to flip a bitmap vertically.
    Vector<uint8_t> m_scanline;
};

} // namespace blink

#endif // DrawingBuffer_h