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) ? std::make_unique<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 = std::make_unique<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 = std::make_unique<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 = std::make_unique<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 | return getIntParameter(pname); |
425 | case GraphicsContext3D::ARRAY_BUFFER_BINDING: |
426 | return m_boundArrayBuffer; |
427 | case GraphicsContext3D::BLEND: |
428 | return getBooleanParameter(pname); |
429 | case GraphicsContext3D::BLEND_COLOR: |
430 | return getWebGLFloatArrayParameter(pname); |
431 | case GraphicsContext3D::BLEND_DST_ALPHA: |
432 | return getUnsignedIntParameter(pname); |
433 | case GraphicsContext3D::BLEND_DST_RGB: |
434 | return getUnsignedIntParameter(pname); |
435 | case GraphicsContext3D::BLEND_EQUATION_ALPHA: |
436 | return getUnsignedIntParameter(pname); |
437 | case GraphicsContext3D::BLEND_EQUATION_RGB: |
438 | return getUnsignedIntParameter(pname); |
439 | case GraphicsContext3D::BLEND_SRC_ALPHA: |
440 | return getUnsignedIntParameter(pname); |
441 | case GraphicsContext3D::BLEND_SRC_RGB: |
442 | return getUnsignedIntParameter(pname); |
443 | case GraphicsContext3D::BLUE_BITS: |
444 | return getIntParameter(pname); |
445 | case GraphicsContext3D::COLOR_CLEAR_VALUE: |
446 | return getWebGLFloatArrayParameter(pname); |
447 | case GraphicsContext3D::COLOR_WRITEMASK: |
448 | return getBooleanArrayParameter(pname); |
449 | case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS: |
450 | return Uint32Array::tryCreate(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()); |
451 | case GraphicsContext3D::CULL_FACE: |
452 | return getBooleanParameter(pname); |
453 | case GraphicsContext3D::CULL_FACE_MODE: |
454 | return getUnsignedIntParameter(pname); |
455 | case GraphicsContext3D::CURRENT_PROGRAM: |
456 | return m_currentProgram; |
457 | case GraphicsContext3D::DEPTH_BITS: |
458 | if (!m_framebufferBinding && !m_attributes.depth) |
459 | return 0; |
460 | return getIntParameter(pname); |
461 | case GraphicsContext3D::DEPTH_CLEAR_VALUE: |
462 | return getFloatParameter(pname); |
463 | case GraphicsContext3D::DEPTH_FUNC: |
464 | return getUnsignedIntParameter(pname); |
465 | case GraphicsContext3D::DEPTH_RANGE: |
466 | return getWebGLFloatArrayParameter(pname); |
467 | case GraphicsContext3D::DEPTH_TEST: |
468 | return getBooleanParameter(pname); |
469 | case GraphicsContext3D::DEPTH_WRITEMASK: |
470 | return getBooleanParameter(pname); |
471 | case GraphicsContext3D::DITHER: |
472 | return getBooleanParameter(pname); |
473 | case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING: |
474 | return makeRefPtr(m_boundVertexArrayObject->getElementArrayBuffer()); |
475 | case GraphicsContext3D::FRAMEBUFFER_BINDING: |
476 | return m_framebufferBinding; |
477 | case GraphicsContext3D::FRONT_FACE: |
478 | return getUnsignedIntParameter(pname); |
479 | case GraphicsContext3D::GENERATE_MIPMAP_HINT: |
480 | return getUnsignedIntParameter(pname); |
481 | case GraphicsContext3D::GREEN_BITS: |
482 | return getIntParameter(pname); |
483 | case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT: |
484 | return getIntParameter(pname); |
485 | case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE: |
486 | return getIntParameter(pname); |
487 | case GraphicsContext3D::LINE_WIDTH: |
488 | return getFloatParameter(pname); |
489 | case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS: |
490 | return getIntParameter(pname); |
491 | case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE: |
492 | return getIntParameter(pname); |
493 | case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS: |
494 | return getIntParameter(pname); |
495 | case GraphicsContext3D::MAX_RENDERBUFFER_SIZE: |
496 | return getIntParameter(pname); |
497 | case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS: |
498 | return getIntParameter(pname); |
499 | case GraphicsContext3D::MAX_TEXTURE_SIZE: |
500 | return getIntParameter(pname); |
501 | case GraphicsContext3D::MAX_VARYING_VECTORS: |
502 | return getIntParameter(pname); |
503 | case GraphicsContext3D::MAX_VERTEX_ATTRIBS: |
504 | return getIntParameter(pname); |
505 | case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS: |
506 | return getIntParameter(pname); |
507 | case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS: |
508 | return getIntParameter(pname); |
509 | case GraphicsContext3D::MAX_VIEWPORT_DIMS: |
510 | return getWebGLIntArrayParameter(pname); |
511 | case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS: |
512 | return getIntParameter(pname); |
513 | case GraphicsContext3D::PACK_ALIGNMENT: |
514 | return getIntParameter(pname); |
515 | case GraphicsContext3D::POLYGON_OFFSET_FACTOR: |
516 | return getFloatParameter(pname); |
517 | case GraphicsContext3D::POLYGON_OFFSET_FILL: |
518 | return getBooleanParameter(pname); |
519 | case GraphicsContext3D::POLYGON_OFFSET_UNITS: |
520 | return getFloatParameter(pname); |
521 | case GraphicsContext3D::RED_BITS: |
522 | return getIntParameter(pname); |
523 | case GraphicsContext3D::RENDERBUFFER_BINDING: |
524 | return m_renderbufferBinding; |
525 | case GraphicsContext3D::RENDERER: |
526 | return "WebKit WebGL"_str ; |
527 | case GraphicsContext3D::SAMPLE_BUFFERS: |
528 | return getIntParameter(pname); |
529 | case GraphicsContext3D::SAMPLE_COVERAGE_INVERT: |
530 | return getBooleanParameter(pname); |
531 | case GraphicsContext3D::SAMPLE_COVERAGE_VALUE: |
532 | return getFloatParameter(pname); |
533 | case GraphicsContext3D::SAMPLES: |
534 | return getIntParameter(pname); |
535 | case GraphicsContext3D::SCISSOR_BOX: |
536 | return getWebGLIntArrayParameter(pname); |
537 | case GraphicsContext3D::SCISSOR_TEST: |
538 | return getBooleanParameter(pname); |
539 | case GraphicsContext3D::SHADING_LANGUAGE_VERSION: |
540 | return "WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")" ; |
541 | case GraphicsContext3D::STENCIL_BACK_FAIL: |
542 | return getUnsignedIntParameter(pname); |
543 | case GraphicsContext3D::STENCIL_BACK_FUNC: |
544 | return getUnsignedIntParameter(pname); |
545 | case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL: |
546 | return getUnsignedIntParameter(pname); |
547 | case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS: |
548 | return getUnsignedIntParameter(pname); |
549 | case GraphicsContext3D::STENCIL_BACK_REF: |
550 | return getIntParameter(pname); |
551 | case GraphicsContext3D::STENCIL_BACK_VALUE_MASK: |
552 | return getUnsignedIntParameter(pname); |
553 | case GraphicsContext3D::STENCIL_BACK_WRITEMASK: |
554 | return getUnsignedIntParameter(pname); |
555 | case GraphicsContext3D::STENCIL_BITS: |
556 | if (!m_framebufferBinding && !m_attributes.stencil) |
557 | return 0; |
558 | return getIntParameter(pname); |
559 | case GraphicsContext3D::STENCIL_CLEAR_VALUE: |
560 | return getIntParameter(pname); |
561 | case GraphicsContext3D::STENCIL_FAIL: |
562 | return getUnsignedIntParameter(pname); |
563 | case GraphicsContext3D::STENCIL_FUNC: |
564 | return getUnsignedIntParameter(pname); |
565 | case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL: |
566 | return getUnsignedIntParameter(pname); |
567 | case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS: |
568 | return getUnsignedIntParameter(pname); |
569 | case GraphicsContext3D::STENCIL_REF: |
570 | return getIntParameter(pname); |
571 | case GraphicsContext3D::STENCIL_TEST: |
572 | return getBooleanParameter(pname); |
573 | case GraphicsContext3D::STENCIL_VALUE_MASK: |
574 | return getUnsignedIntParameter(pname); |
575 | case GraphicsContext3D::STENCIL_WRITEMASK: |
576 | return getUnsignedIntParameter(pname); |
577 | case GraphicsContext3D::SUBPIXEL_BITS: |
578 | return getIntParameter(pname); |
579 | case GraphicsContext3D::TEXTURE_BINDING_2D: |
580 | return m_textureUnits[m_activeTextureUnit].texture2DBinding; |
581 | case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP: |
582 | return m_textureUnits[m_activeTextureUnit].textureCubeMapBinding; |
583 | case GraphicsContext3D::UNPACK_ALIGNMENT: |
584 | return getIntParameter(pname); |
585 | case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL: |
586 | return m_unpackFlipY; |
587 | case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL: |
588 | return m_unpackPremultiplyAlpha; |
589 | case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL: |
590 | return m_unpackColorspaceConversion; |
591 | case GraphicsContext3D::VENDOR: |
592 | return "WebKit"_str ; |
593 | case GraphicsContext3D::VERSION: |
594 | return "WebGL 1.0"_str ; |
595 | case GraphicsContext3D::VIEWPORT: |
596 | return getWebGLIntArrayParameter(pname); |
597 | case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives |
598 | if (m_oesStandardDerivatives) |
599 | return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES); |
600 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, OES_standard_derivatives not enabled" ); |
601 | return nullptr; |
602 | case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL: |
603 | if (m_webglDebugRendererInfo) { |
604 | #if PLATFORM(IOS_FAMILY) |
605 | return "Apple GPU"_str ; |
606 | #else |
607 | return m_context->getString(GraphicsContext3D::RENDERER); |
608 | #endif |
609 | } |
610 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, WEBGL_debug_renderer_info not enabled" ); |
611 | return nullptr; |
612 | case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL: |
613 | if (m_webglDebugRendererInfo) |
614 | return m_context->getString(GraphicsContext3D::VENDOR); |
615 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, WEBGL_debug_renderer_info not enabled" ); |
616 | return nullptr; |
617 | case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object |
618 | if (m_oesVertexArrayObject) { |
619 | if (m_boundVertexArrayObject->isDefaultObject()) |
620 | return nullptr; |
621 | return makeRefPtr(static_cast<WebGLVertexArrayObjectOES&>(*m_boundVertexArrayObject)); |
622 | } |
623 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, OES_vertex_array_object not enabled" ); |
624 | return nullptr; |
625 | case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic |
626 | if (m_extTextureFilterAnisotropic) |
627 | return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT); |
628 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, EXT_texture_filter_anisotropic not enabled" ); |
629 | return nullptr; |
630 | case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN |
631 | if (m_webglDrawBuffers) |
632 | return getMaxColorAttachments(); |
633 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, WEBGL_draw_buffers not enabled" ); |
634 | return nullptr; |
635 | case Extensions3D::MAX_DRAW_BUFFERS_EXT: |
636 | if (m_webglDrawBuffers) |
637 | return getMaxDrawBuffers(); |
638 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name, WEBGL_draw_buffers not enabled" ); |
639 | return nullptr; |
640 | default: |
641 | if (m_webglDrawBuffers |
642 | && pname >= Extensions3D::DRAW_BUFFER0_EXT |
643 | && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) { |
644 | GC3Dint value = GraphicsContext3D::NONE; |
645 | if (m_framebufferBinding) |
646 | value = m_framebufferBinding->getDrawBuffer(pname); |
647 | else // emulated backbuffer |
648 | value = m_backDrawBuffer; |
649 | return value; |
650 | } |
651 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter" , "invalid parameter name" ); |
652 | return nullptr; |
653 | } |
654 | } |
655 | |
656 | GC3Dint WebGLRenderingContext::getMaxDrawBuffers() |
657 | { |
658 | if (!supportsDrawBuffers()) |
659 | return 0; |
660 | if (!m_maxDrawBuffers) |
661 | m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers); |
662 | if (!m_maxColorAttachments) |
663 | m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); |
664 | // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS. |
665 | return std::min(m_maxDrawBuffers, m_maxColorAttachments); |
666 | } |
667 | |
668 | GC3Dint WebGLRenderingContext::getMaxColorAttachments() |
669 | { |
670 | if (!supportsDrawBuffers()) |
671 | return 0; |
672 | if (!m_maxColorAttachments) |
673 | m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); |
674 | return m_maxColorAttachments; |
675 | } |
676 | |
677 | bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired) |
678 | { |
679 | // Performs conservative validation by caching a maximum index of |
680 | // the given type per element array buffer. If all of the bound |
681 | // array buffers have enough elements to satisfy that maximum |
682 | // index, skips the expensive per-draw-call iteration in |
683 | // validateIndexArrayPrecise. |
684 | |
685 | RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); |
686 | |
687 | if (!elementArrayBuffer) |
688 | return false; |
689 | |
690 | GC3Dsizeiptr numElements = elementArrayBuffer->byteLength(); |
691 | // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative. |
692 | if (!numElements) |
693 | return false; |
694 | auto buffer = elementArrayBuffer->elementArrayBuffer(); |
695 | ASSERT(buffer); |
696 | |
697 | Optional<unsigned> maxIndex = elementArrayBuffer->getCachedMaxIndex(type); |
698 | if (!maxIndex) { |
699 | // Compute the maximum index in the entire buffer for the given type of index. |
700 | switch (type) { |
701 | case GraphicsContext3D::UNSIGNED_BYTE: { |
702 | const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data()); |
703 | for (GC3Dsizeiptr i = 0; i < numElements; i++) |
704 | maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]); |
705 | break; |
706 | } |
707 | case GraphicsContext3D::UNSIGNED_SHORT: { |
708 | numElements /= sizeof(GC3Dushort); |
709 | const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data()); |
710 | for (GC3Dsizeiptr i = 0; i < numElements; i++) |
711 | maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]); |
712 | break; |
713 | } |
714 | case GraphicsContext3D::UNSIGNED_INT: { |
715 | if (!m_oesElementIndexUint) |
716 | return false; |
717 | numElements /= sizeof(GC3Duint); |
718 | const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data()); |
719 | for (GC3Dsizeiptr i = 0; i < numElements; i++) |
720 | maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast<unsigned>(p[i])) : static_cast<unsigned>(p[i]); |
721 | break; |
722 | } |
723 | default: |
724 | return false; |
725 | } |
726 | if (maxIndex) |
727 | elementArrayBuffer->setCachedMaxIndex(type, maxIndex.value()); |
728 | } |
729 | |
730 | if (!maxIndex) |
731 | return false; |
732 | |
733 | // The number of required elements is one more than the maximum index that will be accessed. |
734 | auto checkedNumElementsRequired = checkedAddAndMultiply<unsigned>(maxIndex.value(), 1, 1); |
735 | if (!checkedNumElementsRequired) |
736 | return false; |
737 | numElementsRequired = checkedNumElementsRequired.value(); |
738 | |
739 | return true; |
740 | } |
741 | |
742 | bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode) |
743 | { |
744 | switch (mode) { |
745 | case GraphicsContext3D::FUNC_ADD: |
746 | case GraphicsContext3D::FUNC_SUBTRACT: |
747 | case GraphicsContext3D::FUNC_REVERSE_SUBTRACT: |
748 | case Extensions3D::MIN_EXT: |
749 | case Extensions3D::MAX_EXT: |
750 | if ((mode == Extensions3D::MIN_EXT || mode == Extensions3D::MAX_EXT) && !m_extBlendMinMax) { |
751 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode" ); |
752 | return false; |
753 | } |
754 | return true; |
755 | break; |
756 | default: |
757 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode" ); |
758 | return false; |
759 | } |
760 | } |
761 | |
762 | bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap) |
763 | { |
764 | switch (cap) { |
765 | case GraphicsContext3D::BLEND: |
766 | case GraphicsContext3D::CULL_FACE: |
767 | case GraphicsContext3D::DEPTH_TEST: |
768 | case GraphicsContext3D::DITHER: |
769 | case GraphicsContext3D::POLYGON_OFFSET_FILL: |
770 | case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE: |
771 | case GraphicsContext3D::SAMPLE_COVERAGE: |
772 | case GraphicsContext3D::SCISSOR_TEST: |
773 | case GraphicsContext3D::STENCIL_TEST: |
774 | return true; |
775 | default: |
776 | synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability" ); |
777 | return false; |
778 | } |
779 | } |
780 | |
781 | } // namespace WebCore |
782 | |
783 | #endif // ENABLE(WEBGL) |
784 | |