Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLDrawBuffers.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(WEBGL)
29 #include "WebGLDrawBuffers.h"
30
31 #include "Extensions3D.h"
32
33 namespace WebCore {
34
35 WebGLDrawBuffers::WebGLDrawBuffers(WebGLRenderingContextBase& context)
36     : WebGLExtension(context)
37 {
38 }
39
40 WebGLDrawBuffers::~WebGLDrawBuffers() = default;
41
42 WebGLExtension::ExtensionName WebGLDrawBuffers::getName() const
43 {
44     return WebGLExtension::WebGLDrawBuffersName;
45 }
46
47 bool WebGLDrawBuffers::supported(WebGLRenderingContextBase& context)
48 {
49     return context.graphicsContext3D()->getExtensions().supports("GL_EXT_draw_buffers")
50         && satisfiesWebGLRequirements(context);
51 }
52
53 void WebGLDrawBuffers::drawBuffersWEBGL(const Vector<GC3Denum>& buffers)
54 {
55     if (m_context.isContextLost())
56         return;
57     GC3Dsizei n = buffers.size();
58     const GC3Denum* bufs = buffers.data();
59     if (!m_context.m_framebufferBinding) {
60         if (n != 1) {
61             m_context.synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawBuffersWEBGL", "more than one buffer");
62             return;
63         }
64         if (bufs[0] != GraphicsContext3D::BACK && bufs[0] != GraphicsContext3D::NONE) {
65             m_context.synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawBuffersWEBGL", "BACK or NONE");
66             return;
67         }
68         // Because the backbuffer is simulated on all current WebKit ports, we need to change BACK to COLOR_ATTACHMENT0.
69         GC3Denum value = (bufs[0] == GraphicsContext3D::BACK) ? GraphicsContext3D::COLOR_ATTACHMENT0 : GraphicsContext3D::NONE;
70         m_context.graphicsContext3D()->getExtensions().drawBuffersEXT(1, &value);
71         m_context.setBackDrawBuffer(bufs[0]);
72     } else {
73         if (n > m_context.getMaxDrawBuffers()) {
74             m_context.synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawBuffersWEBGL", "more than max draw buffers");
75             return;
76         }
77         for (GC3Dsizei i = 0; i < n; ++i) {
78             if (bufs[i] != GraphicsContext3D::NONE && bufs[i] != static_cast<GC3Denum>(Extensions3D::COLOR_ATTACHMENT0_EXT + i)) {
79                 m_context.synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawBuffersWEBGL", "COLOR_ATTACHMENTi_EXT or NONE");
80                 return;
81             }
82         }
83         m_context.m_framebufferBinding->drawBuffers(buffers);
84     }
85 }
86
87 // static
88 bool WebGLDrawBuffers::satisfiesWebGLRequirements(WebGLRenderingContextBase& webglContext)
89 {
90     GraphicsContext3D* context = webglContext.graphicsContext3D();
91
92     // This is called after we make sure GL_EXT_draw_buffers is supported.
93     GC3Dint maxDrawBuffers = 0;
94     GC3Dint maxColorAttachments = 0;
95     context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
96     context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments);
97     if (maxDrawBuffers < 4 || maxColorAttachments < 4)
98         return false;
99
100     Platform3DObject fbo = context->createFramebuffer();
101     context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, fbo);
102
103     const unsigned char buffer[4] = { 0, 0, 0, 0 }; // textures are required to be initialized for other ports.
104     bool supportsDepth = context->getExtensions().supports("GL_OES_depth_texture")
105         || context->getExtensions().supports("GL_ARB_depth_texture");
106     bool supportsDepthStencil = (context->getExtensions().supports("GL_EXT_packed_depth_stencil")
107         || context->getExtensions().supports("GL_OES_packed_depth_stencil"));
108     Platform3DObject depthStencil = 0;
109     if (supportsDepthStencil) {
110         depthStencil = context->createTexture();
111         context->bindTexture(GraphicsContext3D::TEXTURE_2D, depthStencil);
112         context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::DEPTH_STENCIL, 1, 1, 0, GraphicsContext3D::DEPTH_STENCIL, GraphicsContext3D::UNSIGNED_INT_24_8, buffer);
113     }
114     Platform3DObject depth = 0;
115     if (supportsDepth) {
116         depth = context->createTexture();
117         context->bindTexture(GraphicsContext3D::TEXTURE_2D, depth);
118         context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::DEPTH_COMPONENT, 1, 1, 0, GraphicsContext3D::DEPTH_COMPONENT, GraphicsContext3D::UNSIGNED_INT, buffer);
119     }
120
121     Vector<Platform3DObject> colors;
122     bool ok = true;
123     GC3Dint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments);
124     for (GC3Dint i = 0; i < maxAllowedBuffers; ++i) {
125         Platform3DObject color = context->createTexture();
126         colors.append(color);
127         context->bindTexture(GraphicsContext3D::TEXTURE_2D, color);
128         context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, buffer);
129         context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0 + i, GraphicsContext3D::TEXTURE_2D, color, 0);
130         if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
131             ok = false;
132             break;
133         }
134         if (supportsDepth) {
135             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depth, 0);
136             if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
137                 ok = false;
138                 break;
139             }
140             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
141         }
142         if (supportsDepthStencil) {
143             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depthStencil, 0);
144             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, depthStencil, 0);
145             if (context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
146                 ok = false;
147                 break;
148             }
149             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
150             context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::TEXTURE_2D, 0, 0);
151         }
152     }
153
154     webglContext.restoreCurrentFramebuffer();
155     context->deleteFramebuffer(fbo);
156     webglContext.restoreCurrentTexture2D();
157     if (supportsDepth)
158         context->deleteTexture(depth);
159     if (supportsDepthStencil)
160         context->deleteTexture(depthStencil);
161     for (auto& color : colors)
162         context->deleteTexture(color);
163     return ok;
164 }
165
166 } // namespace WebCore
167
168 #endif // ENABLE(WEBGL)