/* * Copyright (C) 2015-2017 Apple 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. */ #include "config.h" #include "WebGLRenderingContext.h" #if ENABLE(WEBGL) #include "ANGLEInstancedArrays.h" #include "CachedImage.h" #include "EXTBlendMinMax.h" #include "EXTFragDepth.h" #include "EXTShaderTextureLOD.h" #include "EXTTextureFilterAnisotropic.h" #include "EXTsRGB.h" #include "Extensions3D.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" #include "HTMLVideoElement.h" #include "ImageData.h" #include "OESElementIndexUint.h" #include "OESStandardDerivatives.h" #include "OESTextureFloat.h" #include "OESTextureFloatLinear.h" #include "OESTextureHalfFloat.h" #include "OESTextureHalfFloatLinear.h" #include "OESVertexArrayObject.h" #include "RenderBox.h" #include "WebGLCompressedTextureATC.h" #include "WebGLCompressedTexturePVRTC.h" #include "WebGLCompressedTextureS3TC.h" #include "WebGLDebugRendererInfo.h" #include "WebGLDebugShaders.h" #include "WebGLDepthTexture.h" #include "WebGLDrawBuffers.h" #include "WebGLLoseContext.h" #include "WebGLVertexArrayObjectOES.h" #include #include #include #include #include namespace WebCore { WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement& passedCanvas, GraphicsContext3DAttributes attributes) : WebGLRenderingContextBase(passedCanvas, attributes) { } WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement& passedCanvas, Ref&& context, GraphicsContext3DAttributes attributes) : WebGLRenderingContextBase(passedCanvas, WTFMove(context), attributes) { initializeVertexArrayObjects(); } void WebGLRenderingContext::initializeVertexArrayObjects() { m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(*this, WebGLVertexArrayObjectOES::Type::Default); addContextObject(*m_defaultVertexArrayObject); m_boundVertexArrayObject = m_defaultVertexArrayObject; if (!isGLES2Compliant()) initVertexAttrib0(); } WebGLExtension* WebGLRenderingContext::getExtension(const String& name) { if (isContextLostOrPending()) return nullptr; if (equalIgnoringASCIICase(name, "EXT_blend_minmax")) { if (!m_extBlendMinMax) { m_extBlendMinMax = enableSupportedExtension("GL_EXT_blend_minmax") ? std::make_unique(*this) : nullptr; } return m_extBlendMinMax.get(); } if (equalIgnoringASCIICase(name, "EXT_sRGB")) { if (!m_extsRGB) { m_extsRGB = enableSupportedExtension("GL_EXT_sRGB") ? std::make_unique(*this) : nullptr; } return m_extsRGB.get(); } if (equalIgnoringASCIICase(name, "EXT_frag_depth")) { if (!m_extFragDepth) { m_extFragDepth = enableSupportedExtension("GL_EXT_frag_depth") ? std::make_unique(*this) : nullptr; } return m_extFragDepth.get(); } if (equalIgnoringASCIICase(name, "EXT_shader_texture_lod")) { if (!m_extShaderTextureLOD) { if (!(m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_shader_texture_lod" }) || m_context->getExtensions().supports(ASCIILiteral { "GL_ARB_shader_texture_lod" }))) m_extShaderTextureLOD = nullptr; else { m_context->getExtensions().ensureEnabled(ASCIILiteral { "GL_EXT_shader_texture_lod" }); m_extShaderTextureLOD = std::make_unique(*this); } } return m_extShaderTextureLOD.get(); } if (equalIgnoringASCIICase(name, "EXT_texture_filter_anisotropic") || equalIgnoringASCIICase(name, "WEBKIT_EXT_texture_filter_anisotropic")) { if (!m_extTextureFilterAnisotropic) { m_extTextureFilterAnisotropic = enableSupportedExtension("GL_EXT_texture_filter_anisotropic") ? std::make_unique(*this) : nullptr; } return m_extTextureFilterAnisotropic.get(); } if (equalIgnoringASCIICase(name, "OES_standard_derivatives")) { if (!m_oesStandardDerivatives) { m_oesStandardDerivatives = enableSupportedExtension("GL_OES_standard_derivatives") ? std::make_unique(*this) : nullptr; } return m_oesStandardDerivatives.get(); } if (equalIgnoringASCIICase(name, "OES_texture_float")) { if (!m_oesTextureFloat) { m_oesTextureFloat = enableSupportedExtension("GL_OES_texture_float") ? std::make_unique(*this) : nullptr; } return m_oesTextureFloat.get(); } if (equalIgnoringASCIICase(name, "OES_texture_float_linear")) { if (!m_oesTextureFloatLinear) { m_oesTextureFloatLinear = enableSupportedExtension("GL_OES_texture_float_linear") ? std::make_unique(*this) : nullptr; } return m_oesTextureFloatLinear.get(); } if (equalIgnoringASCIICase(name, "OES_texture_half_float")) { if (!m_oesTextureHalfFloat) { m_oesTextureHalfFloat = enableSupportedExtension("GL_OES_texture_half_float") ? std::make_unique(*this) : nullptr; } return m_oesTextureHalfFloat.get(); } if (equalIgnoringASCIICase(name, "OES_texture_half_float_linear")) { if (!m_oesTextureHalfFloatLinear) { m_oesTextureHalfFloatLinear = enableSupportedExtension("GL_OES_texture_half_float_linear") ? std::make_unique(*this) : nullptr; } return m_oesTextureHalfFloatLinear.get(); } if (equalIgnoringASCIICase(name, "OES_vertex_array_object")) { if (!m_oesVertexArrayObject) { m_oesVertexArrayObject = enableSupportedExtension("GL_OES_vertex_array_object") ? std::make_unique(*this) : nullptr; } return m_oesVertexArrayObject.get(); } if (equalIgnoringASCIICase(name, "OES_element_index_uint")) { if (!m_oesElementIndexUint) { m_oesElementIndexUint = enableSupportedExtension("GL_OES_element_index_uint") ? std::make_unique(*this) : nullptr; } return m_oesElementIndexUint.get(); } if (equalIgnoringASCIICase(name, "WEBGL_lose_context")) { if (!m_webglLoseContext) m_webglLoseContext = std::make_unique(*this); return m_webglLoseContext.get(); } if (equalIgnoringASCIICase(name, "WEBKIT_WEBGL_compressed_texture_atc")) { if (!m_webglCompressedTextureATC) { m_webglCompressedTextureATC = WebGLCompressedTextureATC::supported(*this) ? std::make_unique(*this) : nullptr; } return m_webglCompressedTextureATC.get(); } if (equalIgnoringASCIICase(name, "WEBKIT_WEBGL_compressed_texture_pvrtc")) { if (!m_webglCompressedTexturePVRTC) { m_webglCompressedTexturePVRTC = WebGLCompressedTexturePVRTC::supported(*this) ? std::make_unique(*this) : nullptr; } return m_webglCompressedTexturePVRTC.get(); } if (equalIgnoringASCIICase(name, "WEBGL_compressed_texture_s3tc")) { if (!m_webglCompressedTextureS3TC) { m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::supported(*this) ? std::make_unique(*this) : nullptr; } return m_webglCompressedTextureS3TC.get(); } if (equalIgnoringASCIICase(name, "WEBGL_depth_texture")) { if (!m_webglDepthTexture) { m_webglDepthTexture = WebGLDepthTexture::supported(*m_context) ? std::make_unique(*this) : nullptr; } return m_webglDepthTexture.get(); } if (equalIgnoringASCIICase(name, "WEBGL_draw_buffers")) { if (!m_webglDrawBuffers) { if (!supportsDrawBuffers()) m_webglDrawBuffers = nullptr; else { m_context->getExtensions().ensureEnabled(ASCIILiteral { "GL_EXT_draw_buffers" }); m_webglDrawBuffers = std::make_unique(*this); } } return m_webglDrawBuffers.get(); } if (equalIgnoringASCIICase(name, "ANGLE_instanced_arrays")) { if (!m_angleInstancedArrays) { if (!ANGLEInstancedArrays::supported(*this)) m_angleInstancedArrays = nullptr; else { m_context->getExtensions().ensureEnabled(ASCIILiteral { "GL_ANGLE_instanced_arrays" }); m_angleInstancedArrays = std::make_unique(*this); } } return m_angleInstancedArrays.get(); } if (equalIgnoringASCIICase(name, "WEBGL_debug_renderer_info")) { if (!m_webglDebugRendererInfo) m_webglDebugRendererInfo = std::make_unique(*this); return m_webglDebugRendererInfo.get(); } if (equalIgnoringASCIICase(name, "WEBGL_debug_shaders")) { if (!m_webglDebugShaders) { m_webglDebugShaders = m_context->getExtensions().supports(ASCIILiteral { "GL_ANGLE_translated_shader_source" }) ? std::make_unique(*this) : nullptr; } return m_webglDebugShaders.get(); } return nullptr; } std::optional> WebGLRenderingContext::getSupportedExtensions() { if (isContextLost()) return std::nullopt; Vector result; if (m_isPendingPolicyResolution) return result; if (m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_blend_minmax" })) result.append(ASCIILiteral { "EXT_blend_minmax" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_sRGB" })) result.append(ASCIILiteral { "EXT_sRGB" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_frag_depth" })) result.append(ASCIILiteral { "EXT_frag_depth" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_texture_float" })) result.append(ASCIILiteral { "OES_texture_float" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_texture_float_linear" })) result.append(ASCIILiteral { "OES_texture_float_linear" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_texture_half_float" })) result.append(ASCIILiteral { "OES_texture_half_float" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_texture_half_float_linear" })) result.append(ASCIILiteral { "OES_texture_half_float_linear" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_standard_derivatives" })) result.append(ASCIILiteral { "OES_standard_derivatives" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_shader_texture_lod" }) || m_context->getExtensions().supports(ASCIILiteral { "GL_ARB_shader_texture_lod" })) result.append(ASCIILiteral { "EXT_shader_texture_lod" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_EXT_texture_filter_anisotropic" })) result.append(ASCIILiteral { "EXT_texture_filter_anisotropic" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_vertex_array_object" })) result.append(ASCIILiteral { "OES_vertex_array_object" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_OES_element_index_uint" })) result.append(ASCIILiteral { "OES_element_index_uint" }); result.append(ASCIILiteral { "WEBGL_lose_context" }); if (WebGLCompressedTextureATC::supported(*this)) result.append(ASCIILiteral { "WEBKIT_WEBGL_compressed_texture_atc" }); if (WebGLCompressedTexturePVRTC::supported(*this)) result.append(ASCIILiteral { "WEBKIT_WEBGL_compressed_texture_pvrtc" }); if (WebGLCompressedTextureS3TC::supported(*this)) result.append("WEBGL_compressed_texture_s3tc"); if (WebGLDepthTexture::supported(*m_context)) result.append(ASCIILiteral { "WEBGL_depth_texture" }); if (supportsDrawBuffers()) result.append(ASCIILiteral { "WEBGL_draw_buffers" }); if (ANGLEInstancedArrays::supported(*this)) result.append(ASCIILiteral { "ANGLE_instanced_arrays" }); if (m_context->getExtensions().supports(ASCIILiteral { "GL_ANGLE_translated_shader_source" })) result.append(ASCIILiteral { "WEBGL_debug_shaders" }); result.append(ASCIILiteral { "WEBGL_debug_renderer_info" }); return result; } WebGLAny WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname) { if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment)) return nullptr; if (!m_framebufferBinding || !m_framebufferBinding->object()) { synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound"); return nullptr; } auto* object = m_framebufferBinding->getAttachmentObject(attachment); if (!object) { if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) return static_cast(GraphicsContext3D::NONE); // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL // specifies INVALID_OPERATION. synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name"); return nullptr; } if (object->isTexture()) { switch (pname) { case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: return static_cast(GraphicsContext3D::TEXTURE); case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: return makeRefPtr(reinterpret_cast(*object)); case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: { GC3Dint value = 0; m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value); return value; } default: synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment"); return nullptr; } } else { ASSERT(object->isRenderbuffer()); switch (pname) { case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: return static_cast(GraphicsContext3D::RENDERBUFFER); case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: return makeRefPtr(reinterpret_cast(*object)); case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: { if (!m_extsRGB) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment"); return nullptr; } WebGLRenderbuffer* renderBuffer = reinterpret_cast(object); GC3Denum renderBufferFormat = renderBuffer->getInternalFormat(); ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT); if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT) return static_cast(Extensions3D::SRGB_EXT); return static_cast(GraphicsContext3D::LINEAR); } default: synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment"); return nullptr; } } } bool WebGLRenderingContext::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment) { if (target != GraphicsContext3D::FRAMEBUFFER) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target"); return false; } // FIXME: Why does this return true unconditionally for COLOR_ATTACHMENT0, // but false for other COLOR_ATTACHMENT values if m_webglDrawBuffers is false? switch (attachment) { case GraphicsContext3D::COLOR_ATTACHMENT0: case GraphicsContext3D::DEPTH_ATTACHMENT: case GraphicsContext3D::STENCIL_ATTACHMENT: case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: return true; default: if (m_webglDrawBuffers && attachment >= GraphicsContext3D::COLOR_ATTACHMENT0 && attachment < static_cast(GraphicsContext3D::COLOR_ATTACHMENT0 + getMaxColorAttachments())) return true; synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment"); return false; } } void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) { if (isContextLostOrPending()) return; if (target != GraphicsContext3D::RENDERBUFFER) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target"); return; } if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer"); return; } if (!validateSize("renderbufferStorage", width, height)) return; switch (internalformat) { case GraphicsContext3D::DEPTH_COMPONENT16: case GraphicsContext3D::RGBA4: case GraphicsContext3D::RGB5_A1: case GraphicsContext3D::RGB565: case GraphicsContext3D::STENCIL_INDEX8: case Extensions3D::SRGB8_ALPHA8_EXT: if (internalformat == Extensions3D::SRGB8_ALPHA8_EXT && !m_extsRGB) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat"); return; } m_context->renderbufferStorage(target, internalformat, width, height); m_renderbufferBinding->setInternalFormat(internalformat); m_renderbufferBinding->setIsValid(true); m_renderbufferBinding->setSize(width, height); break; case GraphicsContext3D::DEPTH_STENCIL: if (isDepthStencilSupported()) m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height); m_renderbufferBinding->setSize(width, height); m_renderbufferBinding->setIsValid(isDepthStencilSupported()); m_renderbufferBinding->setInternalFormat(internalformat); break; default: synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat"); return; } applyStencilTest(); } void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode) { if (isContextLostOrPending()) return; bool isValid = false; switch (target) { case GraphicsContext3D::GENERATE_MIPMAP_HINT: isValid = true; break; case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives if (m_oesStandardDerivatives) isValid = true; break; } if (!isValid) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target"); return; } m_context->hint(target, mode); } void WebGLRenderingContext::clear(GC3Dbitfield mask) { if (isContextLostOrPending()) return; if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) { synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask"); return; } const char* reason = "framebuffer incomplete"; if (m_framebufferBinding && !m_framebufferBinding->onAccess(m_context.get(), &reason)) { synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason); return; } if (!clearIfComposited(mask)) m_context->clear(mask); markContextChanged(); } WebGLAny WebGLRenderingContext::getParameter(GC3Denum pname) { if (isContextLostOrPending()) return nullptr; switch (pname) { case GraphicsContext3D::ACTIVE_TEXTURE: return getUnsignedIntParameter(pname); case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE: return getWebGLFloatArrayParameter(pname); case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE: return getWebGLFloatArrayParameter(pname); case GraphicsContext3D::ALPHA_BITS: return getIntParameter(pname); case GraphicsContext3D::ARRAY_BUFFER_BINDING: return m_boundArrayBuffer; case GraphicsContext3D::BLEND: return getBooleanParameter(pname); case GraphicsContext3D::BLEND_COLOR: return getWebGLFloatArrayParameter(pname); case GraphicsContext3D::BLEND_DST_ALPHA: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLEND_DST_RGB: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLEND_EQUATION_ALPHA: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLEND_EQUATION_RGB: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLEND_SRC_ALPHA: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLEND_SRC_RGB: return getUnsignedIntParameter(pname); case GraphicsContext3D::BLUE_BITS: return getIntParameter(pname); case GraphicsContext3D::COLOR_CLEAR_VALUE: return getWebGLFloatArrayParameter(pname); case GraphicsContext3D::COLOR_WRITEMASK: return getBooleanArrayParameter(pname); case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS: return Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()); case GraphicsContext3D::CULL_FACE: return getBooleanParameter(pname); case GraphicsContext3D::CULL_FACE_MODE: return getUnsignedIntParameter(pname); case GraphicsContext3D::CURRENT_PROGRAM: return m_currentProgram; case GraphicsContext3D::DEPTH_BITS: if (!m_framebufferBinding && !m_attributes.depth) return 0; return getIntParameter(pname); case GraphicsContext3D::DEPTH_CLEAR_VALUE: return getFloatParameter(pname); case GraphicsContext3D::DEPTH_FUNC: return getUnsignedIntParameter(pname); case GraphicsContext3D::DEPTH_RANGE: return getWebGLFloatArrayParameter(pname); case GraphicsContext3D::DEPTH_TEST: return getBooleanParameter(pname); case GraphicsContext3D::DEPTH_WRITEMASK: return getBooleanParameter(pname); case GraphicsContext3D::DITHER: return getBooleanParameter(pname); case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING: return makeRefPtr(m_boundVertexArrayObject->getElementArrayBuffer()); case GraphicsContext3D::FRAMEBUFFER_BINDING: return m_framebufferBinding; case GraphicsContext3D::FRONT_FACE: return getUnsignedIntParameter(pname); case GraphicsContext3D::GENERATE_MIPMAP_HINT: return getUnsignedIntParameter(pname); case GraphicsContext3D::GREEN_BITS: return getIntParameter(pname); case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT: return getIntParameter(pname); case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE: return getIntParameter(pname); case GraphicsContext3D::LINE_WIDTH: return getFloatParameter(pname); case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS: return getIntParameter(pname); case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE: return getIntParameter(pname); case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS: return getIntParameter(pname); case GraphicsContext3D::MAX_RENDERBUFFER_SIZE: return getIntParameter(pname); case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS: return getIntParameter(pname); case GraphicsContext3D::MAX_TEXTURE_SIZE: return getIntParameter(pname); case GraphicsContext3D::MAX_VARYING_VECTORS: return getIntParameter(pname); case GraphicsContext3D::MAX_VERTEX_ATTRIBS: return getIntParameter(pname); case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS: return getIntParameter(pname); case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS: return getIntParameter(pname); case GraphicsContext3D::MAX_VIEWPORT_DIMS: return getWebGLIntArrayParameter(pname); case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS: return getIntParameter(pname); case GraphicsContext3D::PACK_ALIGNMENT: return getIntParameter(pname); case GraphicsContext3D::POLYGON_OFFSET_FACTOR: return getFloatParameter(pname); case GraphicsContext3D::POLYGON_OFFSET_FILL: return getBooleanParameter(pname); case GraphicsContext3D::POLYGON_OFFSET_UNITS: return getFloatParameter(pname); case GraphicsContext3D::RED_BITS: return getIntParameter(pname); case GraphicsContext3D::RENDERBUFFER_BINDING: return m_renderbufferBinding; case GraphicsContext3D::RENDERER: return String { ASCIILiteral { "WebKit WebGL" } }; case GraphicsContext3D::SAMPLE_BUFFERS: return getIntParameter(pname); case GraphicsContext3D::SAMPLE_COVERAGE_INVERT: return getBooleanParameter(pname); case GraphicsContext3D::SAMPLE_COVERAGE_VALUE: return getFloatParameter(pname); case GraphicsContext3D::SAMPLES: return getIntParameter(pname); case GraphicsContext3D::SCISSOR_BOX: return getWebGLIntArrayParameter(pname); case GraphicsContext3D::SCISSOR_TEST: return getBooleanParameter(pname); case GraphicsContext3D::SHADING_LANGUAGE_VERSION: return "WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")"; case GraphicsContext3D::STENCIL_BACK_FAIL: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_FUNC: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_REF: return getIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_VALUE_MASK: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BACK_WRITEMASK: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_BITS: if (!m_framebufferBinding && !m_attributes.stencil) return 0; return getIntParameter(pname); case GraphicsContext3D::STENCIL_CLEAR_VALUE: return getIntParameter(pname); case GraphicsContext3D::STENCIL_FAIL: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_FUNC: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_REF: return getIntParameter(pname); case GraphicsContext3D::STENCIL_TEST: return getBooleanParameter(pname); case GraphicsContext3D::STENCIL_VALUE_MASK: return getUnsignedIntParameter(pname); case GraphicsContext3D::STENCIL_WRITEMASK: return getUnsignedIntParameter(pname); case GraphicsContext3D::SUBPIXEL_BITS: return getIntParameter(pname); case GraphicsContext3D::TEXTURE_BINDING_2D: return m_textureUnits[m_activeTextureUnit].texture2DBinding; case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP: return m_textureUnits[m_activeTextureUnit].textureCubeMapBinding; case GraphicsContext3D::UNPACK_ALIGNMENT: return getIntParameter(pname); case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL: return m_unpackFlipY; case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL: return m_unpackPremultiplyAlpha; case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL: return m_unpackColorspaceConversion; case GraphicsContext3D::VENDOR: return String { ASCIILiteral { "WebKit" } }; case GraphicsContext3D::VERSION: return "WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")"; case GraphicsContext3D::VIEWPORT: return getWebGLIntArrayParameter(pname); case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives if (m_oesStandardDerivatives) return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled"); return nullptr; case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL: if (m_webglDebugRendererInfo) return m_context->getString(GraphicsContext3D::RENDERER); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled"); return nullptr; case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL: if (m_webglDebugRendererInfo) return m_context->getString(GraphicsContext3D::VENDOR); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled"); return nullptr; case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object if (m_oesVertexArrayObject) { if (m_boundVertexArrayObject->isDefaultObject()) return nullptr; return makeRefPtr(static_cast(*m_boundVertexArrayObject)); } synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled"); return nullptr; case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic if (m_extTextureFilterAnisotropic) return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled"); return nullptr; case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN if (m_webglDrawBuffers) return getMaxColorAttachments(); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled"); return nullptr; case Extensions3D::MAX_DRAW_BUFFERS_EXT: if (m_webglDrawBuffers) return getMaxDrawBuffers(); synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled"); return nullptr; default: if (m_webglDrawBuffers && pname >= Extensions3D::DRAW_BUFFER0_EXT && pname < static_cast(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) { GC3Dint value = GraphicsContext3D::NONE; if (m_framebufferBinding) value = m_framebufferBinding->getDrawBuffer(pname); else // emulated backbuffer value = m_backDrawBuffer; return value; } synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name"); return nullptr; } } GC3Dint WebGLRenderingContext::getMaxDrawBuffers() { if (!supportsDrawBuffers()) return 0; if (!m_maxDrawBuffers) m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers); if (!m_maxColorAttachments) m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS. return std::min(m_maxDrawBuffers, m_maxColorAttachments); } GC3Dint WebGLRenderingContext::getMaxColorAttachments() { if (!supportsDrawBuffers()) return 0; if (!m_maxColorAttachments) m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); return m_maxColorAttachments; } bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired) { // Performs conservative validation by caching a maximum index of // the given type per element array buffer. If all of the bound // array buffers have enough elements to satisfy that maximum // index, skips the expensive per-draw-call iteration in // validateIndexArrayPrecise. RefPtr elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); if (!elementArrayBuffer) return false; GC3Dsizeiptr numElements = elementArrayBuffer->byteLength(); // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative. if (!numElements) return false; const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer(); ASSERT(buffer); std::optional maxIndex = elementArrayBuffer->getCachedMaxIndex(type); if (!maxIndex) { // Compute the maximum index in the entire buffer for the given type of index. switch (type) { case GraphicsContext3D::UNSIGNED_BYTE: { const GC3Dubyte* p = static_cast(buffer->data()); for (GC3Dsizeiptr i = 0; i < numElements; i++) maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast(p[i])) : static_cast(p[i]); break; } case GraphicsContext3D::UNSIGNED_SHORT: { numElements /= sizeof(GC3Dushort); const GC3Dushort* p = static_cast(buffer->data()); for (GC3Dsizeiptr i = 0; i < numElements; i++) maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast(p[i])) : static_cast(p[i]); break; } case GraphicsContext3D::UNSIGNED_INT: { if (!m_oesElementIndexUint) return false; numElements /= sizeof(GC3Duint); const GC3Duint* p = static_cast(buffer->data()); for (GC3Dsizeiptr i = 0; i < numElements; i++) maxIndex = maxIndex ? std::max(maxIndex.value(), static_cast(p[i])) : static_cast(p[i]); break; } default: return false; } if (maxIndex) elementArrayBuffer->setCachedMaxIndex(type, maxIndex.value()); } if (!maxIndex) return false; // The number of required elements is one more than the maximum // index that will be accessed. numElementsRequired = maxIndex.value() + 1; // Check for overflow. return numElementsRequired > 0; } bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode) { switch (mode) { case GraphicsContext3D::FUNC_ADD: case GraphicsContext3D::FUNC_SUBTRACT: case GraphicsContext3D::FUNC_REVERSE_SUBTRACT: case Extensions3D::MIN_EXT: case Extensions3D::MAX_EXT: if ((mode == Extensions3D::MIN_EXT || mode == Extensions3D::MAX_EXT) && !m_extBlendMinMax) { synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode"); return false; } return true; break; default: synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode"); return false; } } bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap) { switch (cap) { case GraphicsContext3D::BLEND: case GraphicsContext3D::CULL_FACE: case GraphicsContext3D::DEPTH_TEST: case GraphicsContext3D::DITHER: case GraphicsContext3D::POLYGON_OFFSET_FILL: case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE: case GraphicsContext3D::SAMPLE_COVERAGE: case GraphicsContext3D::SCISSOR_TEST: case GraphicsContext3D::STENCIL_TEST: return true; default: synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability"); return false; } } } // namespace WebCore #endif // ENABLE(WEBGL)