e5fde70337456a31e1571ee10f3fd2642db036b9
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLRenderingContext.cpp
1 /*
2  * Copyright (C) 2015-2017 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebGLRenderingContext.h"
28
29 #if ENABLE(WEBGL)
30
31 #include "ANGLEInstancedArrays.h"
32 #include "CachedImage.h"
33 #include "EXTBlendMinMax.h"
34 #include "EXTFragDepth.h"
35 #include "EXTShaderTextureLOD.h"
36 #include "EXTTextureFilterAnisotropic.h"
37 #include "EXTsRGB.h"
38 #include "Extensions3D.h"
39 #include "HTMLCanvasElement.h"
40 #include "HTMLImageElement.h"
41 #include "HTMLVideoElement.h"
42 #include "ImageData.h"
43 #include "InspectorInstrumentation.h"
44 #include "OESElementIndexUint.h"
45 #include "OESStandardDerivatives.h"
46 #include "OESTextureFloat.h"
47 #include "OESTextureFloatLinear.h"
48 #include "OESTextureHalfFloat.h"
49 #include "OESTextureHalfFloatLinear.h"
50 #include "OESVertexArrayObject.h"
51 #include "RenderBox.h"
52 #include "WebGLCompressedTextureASTC.h"
53 #include "WebGLCompressedTextureATC.h"
54 #include "WebGLCompressedTexturePVRTC.h"
55 #include "WebGLCompressedTextureS3TC.h"
56 #include "WebGLDebugRendererInfo.h"
57 #include "WebGLDebugShaders.h"
58 #include "WebGLDepthTexture.h"
59 #include "WebGLDrawBuffers.h"
60 #include "WebGLLoseContext.h"
61 #include "WebGLVertexArrayObjectOES.h"
62 #include <JavaScriptCore/GenericTypedArrayViewInlines.h>
63 #include <JavaScriptCore/HeapInlines.h>
64 #include <JavaScriptCore/JSCJSValueInlines.h>
65 #include <JavaScriptCore/JSCellInlines.h>
66 #include <JavaScriptCore/JSGenericTypedArrayViewInlines.h>
67 #include <wtf/IsoMallocInlines.h>
68
69 namespace WebCore {
70
71 WTF_MAKE_ISO_ALLOCATED_IMPL(WebGLRenderingContext);
72
73 std::unique_ptr<WebGLRenderingContext> WebGLRenderingContext::create(CanvasBase& canvas, GraphicsContext3DAttributes attributes)
74 {
75     auto renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, attributes));
76
77     InspectorInstrumentation::didCreateCanvasRenderingContext(*renderingContext);
78
79     return renderingContext;
80 }
81
82 std::unique_ptr<WebGLRenderingContext> WebGLRenderingContext::create(CanvasBase& canvas, Ref<GraphicsContext3D>&& context, GraphicsContext3DAttributes attributes)
83 {
84     auto renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, WTFMove(context), attributes));
85
86     InspectorInstrumentation::didCreateCanvasRenderingContext(*renderingContext);
87
88     return renderingContext;
89 }
90
91 WebGLRenderingContext::WebGLRenderingContext(CanvasBase& canvas, GraphicsContext3DAttributes attributes)
92     : WebGLRenderingContextBase(canvas, attributes)
93 {
94 }
95
96 WebGLRenderingContext::WebGLRenderingContext(CanvasBase& canvas, Ref<GraphicsContext3D>&& context, GraphicsContext3DAttributes attributes)
97     : WebGLRenderingContextBase(canvas, WTFMove(context), attributes)
98 {
99     initializeVertexArrayObjects();
100 }
101
102 void WebGLRenderingContext::initializeVertexArrayObjects()
103 {
104     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(*this, WebGLVertexArrayObjectOES::Type::Default);
105     addContextObject(*m_defaultVertexArrayObject);
106     m_boundVertexArrayObject = m_defaultVertexArrayObject;
107     if (!isGLES2Compliant())
108         initVertexAttrib0();
109 }
110
111 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
112 {
113     if (isContextLostOrPending())
114         return nullptr;
115
116 #define ENABLE_IF_REQUESTED(type, variable, nameLiteral, canEnable) \
117     if (equalIgnoringASCIICase(name, nameLiteral)) { \
118         if (!variable) { \
119             variable = (canEnable) ? makeUnique<type>(*this) : nullptr; \
120             if (variable != nullptr) \
121                 InspectorInstrumentation::didEnableExtension(*this, name); \
122         } \
123         return variable.get(); \
124     }
125
126     ENABLE_IF_REQUESTED(EXTBlendMinMax, m_extBlendMinMax, "EXT_blend_minmax", enableSupportedExtension("GL_EXT_blend_minmax"_s));
127     ENABLE_IF_REQUESTED(EXTsRGB, m_extsRGB, "EXT_sRGB", enableSupportedExtension("GL_EXT_sRGB"_s));
128     ENABLE_IF_REQUESTED(EXTFragDepth, m_extFragDepth, "EXT_frag_depth", enableSupportedExtension("GL_EXT_frag_depth"_s));
129     if (equalIgnoringASCIICase(name, "EXT_shader_texture_lod")) {
130         if (!m_extShaderTextureLOD) {
131             if (!(m_context->getExtensions().supports("GL_EXT_shader_texture_lod"_s) || m_context->getExtensions().supports("GL_ARB_shader_texture_lod"_s)))
132                 m_extShaderTextureLOD = nullptr;
133             else {
134                 m_context->getExtensions().ensureEnabled("GL_EXT_shader_texture_lod"_s);
135                 m_extShaderTextureLOD = makeUnique<EXTShaderTextureLOD>(*this);
136                 InspectorInstrumentation::didEnableExtension(*this, name);
137             }
138         }
139         return m_extShaderTextureLOD.get();
140     }
141     ENABLE_IF_REQUESTED(EXTTextureFilterAnisotropic, m_extTextureFilterAnisotropic, "EXT_texture_filter_anisotropic", enableSupportedExtension("GL_EXT_texture_filter_anisotropic"_s));
142     ENABLE_IF_REQUESTED(EXTTextureFilterAnisotropic, m_extTextureFilterAnisotropic, "WEBKIT_EXT_texture_filter_anisotropic", enableSupportedExtension("GL_EXT_texture_filter_anisotropic"_s));
143     ENABLE_IF_REQUESTED(OESStandardDerivatives, m_oesStandardDerivatives, "OES_standard_derivatives", enableSupportedExtension("GL_OES_standard_derivatives"_s));
144     ENABLE_IF_REQUESTED(OESTextureFloat, m_oesTextureFloat, "OES_texture_float", enableSupportedExtension("GL_OES_texture_float"_s));
145     ENABLE_IF_REQUESTED(OESTextureFloatLinear, m_oesTextureFloatLinear, "OES_texture_float_linear", enableSupportedExtension("GL_OES_texture_float_linear"_s));
146     ENABLE_IF_REQUESTED(OESTextureHalfFloat, m_oesTextureHalfFloat, "OES_texture_half_float", enableSupportedExtension("GL_OES_texture_half_float"_s));
147     ENABLE_IF_REQUESTED(OESTextureHalfFloatLinear, m_oesTextureHalfFloatLinear, "OES_texture_half_float_linear", enableSupportedExtension("GL_OES_texture_half_float_linear"_s));
148     ENABLE_IF_REQUESTED(OESVertexArrayObject, m_oesVertexArrayObject, "OES_vertex_array_object", enableSupportedExtension("GL_OES_vertex_array_object"_s));
149     ENABLE_IF_REQUESTED(OESElementIndexUint, m_oesElementIndexUint, "OES_element_index_uint", enableSupportedExtension("GL_OES_element_index_uint"_s));
150     ENABLE_IF_REQUESTED(WebGLLoseContext, m_webglLoseContext, "WEBGL_lose_context", true);
151     ENABLE_IF_REQUESTED(WebGLCompressedTextureATC, m_webglCompressedTextureATC, "WEBKIT_WEBGL_compressed_texture_atc", WebGLCompressedTextureATC::supported(*this));
152     ENABLE_IF_REQUESTED(WebGLCompressedTexturePVRTC, m_webglCompressedTexturePVRTC, "WEBKIT_WEBGL_compressed_texture_pvrtc", WebGLCompressedTexturePVRTC::supported(*this));
153     ENABLE_IF_REQUESTED(WebGLCompressedTextureS3TC, m_webglCompressedTextureS3TC, "WEBGL_compressed_texture_s3tc", WebGLCompressedTextureS3TC::supported(*this));
154     ENABLE_IF_REQUESTED(WebGLCompressedTextureASTC, m_webglCompressedTextureASTC, "WEBGL_compressed_texture_astc", WebGLCompressedTextureASTC::supported(*this));
155     ENABLE_IF_REQUESTED(WebGLDepthTexture, m_webglDepthTexture, "WEBGL_depth_texture", WebGLDepthTexture::supported(*m_context));
156     if (equalIgnoringASCIICase(name, "WEBGL_draw_buffers")) {
157         if (!m_webglDrawBuffers) {
158             if (!supportsDrawBuffers())
159                 m_webglDrawBuffers = nullptr;
160             else {
161                 m_context->getExtensions().ensureEnabled("GL_EXT_draw_buffers"_s);
162                 m_webglDrawBuffers = makeUnique<WebGLDrawBuffers>(*this);
163                 InspectorInstrumentation::didEnableExtension(*this, name);
164             }
165         }
166         return m_webglDrawBuffers.get();
167     }
168     if (equalIgnoringASCIICase(name, "ANGLE_instanced_arrays")) {
169         if (!m_angleInstancedArrays) {
170             if (!ANGLEInstancedArrays::supported(*this))
171                 m_angleInstancedArrays = nullptr;
172             else {
173                 m_context->getExtensions().ensureEnabled("GL_ANGLE_instanced_arrays"_s);
174                 m_angleInstancedArrays = makeUnique<ANGLEInstancedArrays>(*this);
175                 InspectorInstrumentation::didEnableExtension(*this, name);
176             }
177         }
178         return m_angleInstancedArrays.get();
179     }
180     ENABLE_IF_REQUESTED(WebGLDebugRendererInfo, m_webglDebugRendererInfo, "WEBGL_debug_renderer_info", true);
181     ENABLE_IF_REQUESTED(WebGLDebugShaders, m_webglDebugShaders, "WEBGL_debug_shaders", m_context->getExtensions().supports("GL_ANGLE_translated_shader_source"_s));
182     return nullptr;
183 }
184
185 Optional<Vector<String>> WebGLRenderingContext::getSupportedExtensions()
186 {
187     if (isContextLost())
188         return WTF::nullopt;
189
190     Vector<String> result;
191     
192     if (m_isPendingPolicyResolution)
193         return result;
194     
195     if (m_context->getExtensions().supports("GL_EXT_blend_minmax"_s))
196         result.append("EXT_blend_minmax"_s);
197     if (m_context->getExtensions().supports("GL_EXT_sRGB"_s))
198         result.append("EXT_sRGB"_s);
199     if (m_context->getExtensions().supports("GL_EXT_frag_depth"_s))
200         result.append("EXT_frag_depth"_s);
201     if (m_context->getExtensions().supports("GL_OES_texture_float"_s))
202         result.append("OES_texture_float"_s);
203     if (m_context->getExtensions().supports("GL_OES_texture_float_linear"_s))
204         result.append("OES_texture_float_linear"_s);
205     if (m_context->getExtensions().supports("GL_OES_texture_half_float"_s))
206         result.append("OES_texture_half_float"_s);
207     if (m_context->getExtensions().supports("GL_OES_texture_half_float_linear"_s))
208         result.append("OES_texture_half_float_linear"_s);
209     if (m_context->getExtensions().supports("GL_OES_standard_derivatives"_s))
210         result.append("OES_standard_derivatives"_s);
211     if (m_context->getExtensions().supports("GL_EXT_shader_texture_lod"_s) || m_context->getExtensions().supports("GL_ARB_shader_texture_lod"_s))
212         result.append("EXT_shader_texture_lod"_s);
213     if (m_context->getExtensions().supports("GL_EXT_texture_filter_anisotropic"_s))
214         result.append("EXT_texture_filter_anisotropic"_s);
215     if (m_context->getExtensions().supports("GL_OES_vertex_array_object"_s))
216         result.append("OES_vertex_array_object"_s);
217     if (m_context->getExtensions().supports("GL_OES_element_index_uint"_s))
218         result.append("OES_element_index_uint"_s);
219     result.append("WEBGL_lose_context"_s);
220     if (WebGLCompressedTextureATC::supported(*this))
221         result.append("WEBKIT_WEBGL_compressed_texture_atc"_s);
222     if (WebGLCompressedTexturePVRTC::supported(*this))
223         result.append("WEBKIT_WEBGL_compressed_texture_pvrtc"_s);
224     if (WebGLCompressedTextureS3TC::supported(*this))
225         result.append("WEBGL_compressed_texture_s3tc"_s);
226     if (WebGLCompressedTextureASTC::supported(*this))
227         result.append("WEBGL_compressed_texture_astc"_s);
228     if (WebGLDepthTexture::supported(*m_context))
229         result.append("WEBGL_depth_texture"_s);
230     if (supportsDrawBuffers())
231         result.append("WEBGL_draw_buffers"_s);
232     if (ANGLEInstancedArrays::supported(*this))
233         result.append("ANGLE_instanced_arrays"_s);
234     if (m_context->getExtensions().supports("GL_ANGLE_translated_shader_source"_s))
235         result.append("WEBGL_debug_shaders"_s);
236     result.append("WEBGL_debug_renderer_info"_s);
237
238     return result;
239 }
240
241 WebGLAny WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname)
242 {
243     if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
244         return nullptr;
245     
246     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
247         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
248         return nullptr;
249     }
250     
251     auto object = makeRefPtr(m_framebufferBinding->getAttachmentObject(attachment));
252     if (!object) {
253         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
254             return static_cast<unsigned>(GraphicsContext3D::NONE);
255         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
256         // specifies INVALID_OPERATION.
257         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
258         return nullptr;
259     }
260     
261     if (object->isTexture()) {
262         switch (pname) {
263         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
264             return static_cast<unsigned>(GraphicsContext3D::TEXTURE);
265         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
266             return makeRefPtr(reinterpret_cast<WebGLTexture&>(*object));
267         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
268         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
269         case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
270             GC3Dint value = 0;
271             m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
272             return value;
273         }
274         default:
275             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
276             return nullptr;
277         }
278     } else {
279         ASSERT(object->isRenderbuffer());
280         switch (pname) {
281         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
282             return static_cast<unsigned>(GraphicsContext3D::RENDERBUFFER);
283         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
284             return makeRefPtr(reinterpret_cast<WebGLRenderbuffer&>(*object));
285         case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
286             if (!m_extsRGB) {
287                 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
288                 return nullptr;
289             }
290             RefPtr<WebGLRenderbuffer> renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object.get());
291             GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
292             ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT);
293             if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT)
294                 return static_cast<unsigned>(Extensions3D::SRGB_EXT);
295             return static_cast<unsigned>(GraphicsContext3D::LINEAR);
296         }
297         default:
298             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
299             return nullptr;
300         }
301     }
302 }
303
304 bool WebGLRenderingContext::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment)
305 {
306     if (target != GraphicsContext3D::FRAMEBUFFER) {
307         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
308         return false;
309     }
310     // FIXME: Why does this return true unconditionally for COLOR_ATTACHMENT0,
311     // but false for other COLOR_ATTACHMENT values if m_webglDrawBuffers is false?
312     switch (attachment) {
313     case GraphicsContext3D::COLOR_ATTACHMENT0:
314     case GraphicsContext3D::DEPTH_ATTACHMENT:
315     case GraphicsContext3D::STENCIL_ATTACHMENT:
316     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
317         return true;
318     default:
319         if (m_webglDrawBuffers
320             && attachment >= GraphicsContext3D::COLOR_ATTACHMENT0
321             && attachment < static_cast<GC3Denum>(GraphicsContext3D::COLOR_ATTACHMENT0 + getMaxColorAttachments()))
322             return true;
323         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment");
324         return false;
325     }
326 }
327     
328 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
329 {
330     if (isContextLostOrPending())
331         return;
332     if (target != GraphicsContext3D::RENDERBUFFER) {
333         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
334         return;
335     }
336     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
337         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
338         return;
339     }
340     if (!validateSize("renderbufferStorage", width, height))
341         return;
342     switch (internalformat) {
343     case GraphicsContext3D::DEPTH_COMPONENT16:
344     case GraphicsContext3D::RGBA4:
345     case GraphicsContext3D::RGB5_A1:
346     case GraphicsContext3D::RGB565:
347     case GraphicsContext3D::STENCIL_INDEX8:
348     case Extensions3D::SRGB8_ALPHA8_EXT:
349         if (internalformat == Extensions3D::SRGB8_ALPHA8_EXT && !m_extsRGB) {
350             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
351             return;
352         }
353         m_context->renderbufferStorage(target, internalformat, width, height);
354         m_renderbufferBinding->setInternalFormat(internalformat);
355         m_renderbufferBinding->setIsValid(true);
356         m_renderbufferBinding->setSize(width, height);
357         break;
358     case GraphicsContext3D::DEPTH_STENCIL:
359         if (isDepthStencilSupported())
360             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
361         m_renderbufferBinding->setSize(width, height);
362         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
363         m_renderbufferBinding->setInternalFormat(internalformat);
364         break;
365     default:
366         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
367         return;
368     }
369     applyStencilTest();
370 }
371
372 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
373 {
374     if (isContextLostOrPending())
375         return;
376     bool isValid = false;
377     switch (target) {
378     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
379         isValid = true;
380         break;
381     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
382         if (m_oesStandardDerivatives)
383             isValid = true;
384         break;
385     }
386     if (!isValid) {
387         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
388         return;
389     }
390     m_context->hint(target, mode);
391 }
392     
393 void WebGLRenderingContext::clear(GC3Dbitfield mask)
394 {
395     if (isContextLostOrPending())
396         return;
397     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
398         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
399         return;
400     }
401     const char* reason = "framebuffer incomplete";
402     if (m_framebufferBinding && !m_framebufferBinding->onAccess(m_context.get(), &reason)) {
403         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
404         return;
405     }
406     if (!clearIfComposited(mask))
407         m_context->clear(mask);
408     markContextChangedAndNotifyCanvasObserver();
409 }
410
411 WebGLAny WebGLRenderingContext::getParameter(GC3Denum pname)
412 {
413     if (isContextLostOrPending())
414         return nullptr;
415
416     switch (pname) {
417     case GraphicsContext3D::ACTIVE_TEXTURE:
418         return getUnsignedIntParameter(pname);
419     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
420         return getWebGLFloatArrayParameter(pname);
421     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
422         return getWebGLFloatArrayParameter(pname);
423     case GraphicsContext3D::ALPHA_BITS:
424         if (!m_framebufferBinding && !m_attributes.alpha)
425             return 0;
426         return getIntParameter(pname);
427     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
428         return m_boundArrayBuffer;
429     case GraphicsContext3D::BLEND:
430         return getBooleanParameter(pname);
431     case GraphicsContext3D::BLEND_COLOR:
432         return getWebGLFloatArrayParameter(pname);
433     case GraphicsContext3D::BLEND_DST_ALPHA:
434         return getUnsignedIntParameter(pname);
435     case GraphicsContext3D::BLEND_DST_RGB:
436         return getUnsignedIntParameter(pname);
437     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
438         return getUnsignedIntParameter(pname);
439     case GraphicsContext3D::BLEND_EQUATION_RGB:
440         return getUnsignedIntParameter(pname);
441     case GraphicsContext3D::BLEND_SRC_ALPHA:
442         return getUnsignedIntParameter(pname);
443     case GraphicsContext3D::BLEND_SRC_RGB:
444         return getUnsignedIntParameter(pname);
445     case GraphicsContext3D::BLUE_BITS:
446         return getIntParameter(pname);
447     case GraphicsContext3D::COLOR_CLEAR_VALUE:
448         return getWebGLFloatArrayParameter(pname);
449     case GraphicsContext3D::COLOR_WRITEMASK:
450         return getBooleanArrayParameter(pname);
451     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
452         return Uint32Array::tryCreate(m_compressedTextureFormats.data(), m_compressedTextureFormats.size());
453     case GraphicsContext3D::CULL_FACE:
454         return getBooleanParameter(pname);
455     case GraphicsContext3D::CULL_FACE_MODE:
456         return getUnsignedIntParameter(pname);
457     case GraphicsContext3D::CURRENT_PROGRAM:
458         return m_currentProgram;
459     case GraphicsContext3D::DEPTH_BITS:
460         if (!m_framebufferBinding && !m_attributes.depth)
461             return 0;
462         return getIntParameter(pname);
463     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
464         return getFloatParameter(pname);
465     case GraphicsContext3D::DEPTH_FUNC:
466         return getUnsignedIntParameter(pname);
467     case GraphicsContext3D::DEPTH_RANGE:
468         return getWebGLFloatArrayParameter(pname);
469     case GraphicsContext3D::DEPTH_TEST:
470         return getBooleanParameter(pname);
471     case GraphicsContext3D::DEPTH_WRITEMASK:
472         return getBooleanParameter(pname);
473     case GraphicsContext3D::DITHER:
474         return getBooleanParameter(pname);
475     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
476         return makeRefPtr(m_boundVertexArrayObject->getElementArrayBuffer());
477     case GraphicsContext3D::FRAMEBUFFER_BINDING:
478         return m_framebufferBinding;
479     case GraphicsContext3D::FRONT_FACE:
480         return getUnsignedIntParameter(pname);
481     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
482         return getUnsignedIntParameter(pname);
483     case GraphicsContext3D::GREEN_BITS:
484         return getIntParameter(pname);
485     case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT:
486         return getIntParameter(pname);
487     case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE:
488         return getIntParameter(pname);
489     case GraphicsContext3D::LINE_WIDTH:
490         return getFloatParameter(pname);
491     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
492         return getIntParameter(pname);
493     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
494         return getIntParameter(pname);
495     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
496         return getIntParameter(pname);
497     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
498         return getIntParameter(pname);
499     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
500         return getIntParameter(pname);
501     case GraphicsContext3D::MAX_TEXTURE_SIZE:
502         return getIntParameter(pname);
503     case GraphicsContext3D::MAX_VARYING_VECTORS:
504         return getIntParameter(pname);
505     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
506         return getIntParameter(pname);
507     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
508         return getIntParameter(pname);
509     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
510         return getIntParameter(pname);
511     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
512         return getWebGLIntArrayParameter(pname);
513     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
514         return getIntParameter(pname);
515     case GraphicsContext3D::PACK_ALIGNMENT:
516         return getIntParameter(pname);
517     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
518         return getFloatParameter(pname);
519     case GraphicsContext3D::POLYGON_OFFSET_FILL:
520         return getBooleanParameter(pname);
521     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
522         return getFloatParameter(pname);
523     case GraphicsContext3D::RED_BITS:
524         return getIntParameter(pname);
525     case GraphicsContext3D::RENDERBUFFER_BINDING:
526         return m_renderbufferBinding;
527     case GraphicsContext3D::RENDERER:
528         return "WebKit WebGL"_str;
529     case GraphicsContext3D::SAMPLE_BUFFERS:
530         return getIntParameter(pname);
531     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
532         return getBooleanParameter(pname);
533     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
534         return getFloatParameter(pname);
535     case GraphicsContext3D::SAMPLES:
536         return getIntParameter(pname);
537     case GraphicsContext3D::SCISSOR_BOX:
538         return getWebGLIntArrayParameter(pname);
539     case GraphicsContext3D::SCISSOR_TEST:
540         return getBooleanParameter(pname);
541     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
542         return "WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")";
543     case GraphicsContext3D::STENCIL_BACK_FAIL:
544         return getUnsignedIntParameter(pname);
545     case GraphicsContext3D::STENCIL_BACK_FUNC:
546         return getUnsignedIntParameter(pname);
547     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
548         return getUnsignedIntParameter(pname);
549     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
550         return getUnsignedIntParameter(pname);
551     case GraphicsContext3D::STENCIL_BACK_REF:
552         return getIntParameter(pname);
553     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
554         return getUnsignedIntParameter(pname);
555     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
556         return getUnsignedIntParameter(pname);
557     case GraphicsContext3D::STENCIL_BITS:
558         if (!m_framebufferBinding && !m_attributes.stencil)
559             return 0;
560         return getIntParameter(pname);
561     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
562         return getIntParameter(pname);
563     case GraphicsContext3D::STENCIL_FAIL:
564         return getUnsignedIntParameter(pname);
565     case GraphicsContext3D::STENCIL_FUNC:
566         return getUnsignedIntParameter(pname);
567     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
568         return getUnsignedIntParameter(pname);
569     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
570         return getUnsignedIntParameter(pname);
571     case GraphicsContext3D::STENCIL_REF:
572         return getIntParameter(pname);
573     case GraphicsContext3D::STENCIL_TEST:
574         return getBooleanParameter(pname);
575     case GraphicsContext3D::STENCIL_VALUE_MASK:
576         return getUnsignedIntParameter(pname);
577     case GraphicsContext3D::STENCIL_WRITEMASK:
578         return getUnsignedIntParameter(pname);
579     case GraphicsContext3D::SUBPIXEL_BITS:
580         return getIntParameter(pname);
581     case GraphicsContext3D::TEXTURE_BINDING_2D:
582         return m_textureUnits[m_activeTextureUnit].texture2DBinding;
583     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
584         return m_textureUnits[m_activeTextureUnit].textureCubeMapBinding;
585     case GraphicsContext3D::UNPACK_ALIGNMENT:
586         return getIntParameter(pname);
587     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
588         return m_unpackFlipY;
589     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
590         return m_unpackPremultiplyAlpha;
591     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
592         return m_unpackColorspaceConversion;
593     case GraphicsContext3D::VENDOR:
594         return "WebKit"_str;
595     case GraphicsContext3D::VERSION:
596         return "WebGL 1.0"_str;
597     case GraphicsContext3D::VIEWPORT:
598         return getWebGLIntArrayParameter(pname);
599     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
600         if (m_oesStandardDerivatives)
601             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
602         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
603         return nullptr;
604     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
605         if (m_webglDebugRendererInfo) {
606 #if PLATFORM(IOS_FAMILY)
607             return "Apple GPU"_str;
608 #else
609             return m_context->getString(GraphicsContext3D::RENDERER);
610 #endif
611         }
612         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
613         return nullptr;
614     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
615         if (m_webglDebugRendererInfo)
616             return m_context->getString(GraphicsContext3D::VENDOR);
617         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
618         return nullptr;
619     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
620         if (m_oesVertexArrayObject) {
621             if (m_boundVertexArrayObject->isDefaultObject())
622                 return nullptr;
623             return makeRefPtr(static_cast<WebGLVertexArrayObjectOES&>(*m_boundVertexArrayObject));
624         }
625         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
626         return nullptr;
627     case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
628         if (m_extTextureFilterAnisotropic)
629             return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
630         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
631         return nullptr;
632     case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
633         if (m_webglDrawBuffers)
634             return getMaxColorAttachments();
635         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
636         return nullptr;
637     case Extensions3D::MAX_DRAW_BUFFERS_EXT:
638         if (m_webglDrawBuffers)
639             return getMaxDrawBuffers();
640         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
641         return nullptr;
642     default:
643         if (m_webglDrawBuffers
644             && pname >= Extensions3D::DRAW_BUFFER0_EXT
645             && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) {
646             GC3Dint value = GraphicsContext3D::NONE;
647             if (m_framebufferBinding)
648                 value = m_framebufferBinding->getDrawBuffer(pname);
649             else // emulated backbuffer
650                 value = m_backDrawBuffer;
651             return value;
652         }
653         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
654         return nullptr;
655     }
656 }
657
658 GC3Dint WebGLRenderingContext::getMaxDrawBuffers()
659 {
660     if (!supportsDrawBuffers())
661         return 0;
662     if (!m_maxDrawBuffers)
663         m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
664     if (!m_maxColorAttachments)
665         m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
666     // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
667     return std::min(m_maxDrawBuffers, m_maxColorAttachments);
668 }
669
670 GC3Dint WebGLRenderingContext::getMaxColorAttachments()
671 {
672     if (!supportsDrawBuffers())
673         return 0;
674     if (!m_maxColorAttachments)
675         m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
676     return m_maxColorAttachments;
677 }
678     
679 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired)
680 {
681     // Performs conservative validation by caching a maximum index of
682     // the given type per element array buffer. If all of the bound
683     // array buffers have enough elements to satisfy that maximum
684     // index, skips the expensive per-draw-call iteration in
685     // validateIndexArrayPrecise.
686     
687     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
688     
689     if (!elementArrayBuffer)
690         return false;
691     
692     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
693     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
694     if (!numElements)
695         return false;
696     auto buffer = elementArrayBuffer->elementArrayBuffer();
697     ASSERT(buffer);
698     
699     Optional<unsigned> maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
700     if (!maxIndex) {
701         // Compute the maximum index in the entire buffer for the given type of index.
702         switch (type) {
703         case GraphicsContext3D::UNSIGNED_BYTE: {
704             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
705             for (GC3Dsizeiptr i = 0; i < numElements; i++)
706                 maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
707             break;
708         }
709         case GraphicsContext3D::UNSIGNED_SHORT: {
710             numElements /= sizeof(GC3Dushort);
711             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
712             for (GC3Dsizeiptr i = 0; i < numElements; i++)
713                 maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
714             break;
715         }
716         case GraphicsContext3D::UNSIGNED_INT: {
717             if (!m_oesElementIndexUint)
718                 return false;
719             numElements /= sizeof(GC3Duint);
720             const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
721             for (GC3Dsizeiptr i = 0; i < numElements; i++)
722                 maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]);
723             break;
724         }
725         default:
726             return false;
727         }
728         if (maxIndex)
729             elementArrayBuffer->setCachedMaxIndex(type, maxIndex.value());
730     }
731     
732     if (!maxIndex)
733         return false;
734
735     // The number of required elements is one more than the maximum index that will be accessed.
736     auto checkedNumElementsRequired = checkedAddAndMultiply<unsigned>(maxIndex.value(), 1, 1);
737     if (!checkedNumElementsRequired)
738         return false;
739     numElementsRequired = checkedNumElementsRequired.value();
740
741     return true;
742 }
743
744 bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode)
745 {
746     switch (mode) {
747     case GraphicsContext3D::FUNC_ADD:
748     case GraphicsContext3D::FUNC_SUBTRACT:
749     case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
750     case Extensions3D::MIN_EXT:
751     case Extensions3D::MAX_EXT:
752         if ((mode == Extensions3D::MIN_EXT || mode == Extensions3D::MAX_EXT) && !m_extBlendMinMax) {
753             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
754             return false;
755         }
756         return true;
757         break;
758     default:
759         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
760         return false;
761     }
762 }
763
764 bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap)
765 {
766     switch (cap) {
767     case GraphicsContext3D::BLEND:
768     case GraphicsContext3D::CULL_FACE:
769     case GraphicsContext3D::DEPTH_TEST:
770     case GraphicsContext3D::DITHER:
771     case GraphicsContext3D::POLYGON_OFFSET_FILL:
772     case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
773     case GraphicsContext3D::SAMPLE_COVERAGE:
774     case GraphicsContext3D::SCISSOR_TEST:
775     case GraphicsContext3D::STENCIL_TEST:
776         return true;
777     default:
778         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability");
779         return false;
780     }
781 }
782
783 } // namespace WebCore
784
785 #endif // ENABLE(WEBGL)