Diff
Modified: trunk/Source/WebCore/ChangeLog (180284 => 180285)
--- trunk/Source/WebCore/ChangeLog 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/ChangeLog 2015-02-18 20:42:53 UTC (rev 180285)
@@ -1,3 +1,63 @@
+2015-02-18 Roger Fong <roger_f...@apple.com>
+
+ WebGL2: Promote various WebGL1 extensions to core for WebGL2.
+ https://bugs.webkit.org/show_bug.cgi?id=141446
+ <rdar://problem/19633715>
+
+ Reviewed by Brent Fulham.
+
+ Tests covered by WebGL2 conformance tests.
+
+ This patch promotes the following WebGL1 extensions to core in WebGL2:
+ OES_element_index_uint
+ EXT_sRGB
+ EXT_blend_minmax
+ EXT_frag_depth
+ EXT_shader_texture_lod
+ OES_standard_derivatives
+
+ The latter 3 are enabled by default now for GLSL1, though we will get these extensions
+ for free when GLSL3 becomes available.
+
+ WebGL2 binding code should actually fall back to base implementation for getFramebufferAttachmentParameter.
+ * bindings/js/JSWebGL2RenderingContextCustom.cpp:
+ (WebCore::JSWebGL2RenderingContext::getFramebufferAttachmentParameter): Deleted.
+ * html/canvas/WebGL2RenderingContext.idl: Ditto.
+
+ * html/canvas/WebGL2RenderingContext.cpp:
+ (WebCore::WebGL2RenderingContext::getExtension): Enable WEBGL_lose_context as an extension again.
+ It was not promoted to core as I originally thought it had been.
+ (WebCore::WebGL2RenderingContext::getSupportedExtensions): Ditto.
+ (WebCore::WebGL2RenderingContext::WebGL2RenderingContext): Promote the 3 shader extensions for GLSL1 to core.
+ (WebCore::WebGL2RenderingContext::initializeShaderExtensions): Ditto.
+ (WebCore::WebGL2RenderingContext::getFramebufferAttachmentParameter): Promote SRGB extension to core.
+ (WebCore::WebGL2RenderingContext::renderbufferStorage): Ditto.
+ (WebCore::WebGL2RenderingContext::hint): Ditto.
+ (WebCore::WebGL2RenderingContext::validateTexFuncFormatAndType): Ditto.
+ (WebCore::WebGL2RenderingContext::validateIndexArrayConservative): Promote OES_element_index_uint extension to core.
+ (WebCore::WebGL2RenderingContext::validateDrawElements): Ditto.
+ (WebCore::WebGL2RenderingContext::validateBlendEquation): Promote EXT_blend_minmax extension to core.
+ * html/canvas/WebGL2RenderingContext.h:
+
+ * html/canvas/WebGLRenderingContext.cpp:
+ (WebCore::WebGLRenderingContext::getFramebufferAttachmentParameter): Copied form WebGLRenderingContextBase.
+ (WebCore::WebGLRenderingContext::renderbufferStorage): Ditto.
+ (WebCore::WebGLRenderingContext::hint): Ditto.
+ (WebCore::WebGLRenderingContext::validateIndexArrayConservative): Ditto.
+ (WebCore::WebGLRenderingContext::validateDrawElements): Ditto.
+ (WebCore::WebGLRenderingContext::validateBlendEquation): Ditto.
+ * html/canvas/WebGLRenderingContext.h:
+
+ * html/canvas/WebGLRenderingContextBase.cpp:
+ (WebCore::WebGLRenderingContextBase::validateIndexArrayConservative): Deleted.
+ (WebCore::WebGLRenderingContextBase::validateDrawElements): Deleted.
+ (WebCore::WebGLRenderingContextBase::getExtension): Deleted.
+ (WebCore::WebGLRenderingContextBase::getFramebufferAttachmentParameter): Deleted.
+ (WebCore::WebGLRenderingContextBase::hint): Deleted.
+ (WebCore::WebGLRenderingContextBase::renderbufferStorage): Deleted.
+ (WebCore::WebGLRenderingContextBase::validateBlendEquation): Deleted.
+ * html/canvas/WebGLRenderingContextBase.h:
+
2015-02-18 Alexey Proskuryakov <a...@apple.com>
Streamline unexported function build fixes
Modified: trunk/Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp (180284 => 180285)
--- trunk/Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp 2015-02-18 20:42:53 UTC (rev 180285)
@@ -69,12 +69,6 @@
{
visitor.addOpaqueRoot(&impl());
}
-
-JSValue JSWebGL2RenderingContext::getFramebufferAttachmentParameter(ExecState* exec)
-{
- UNUSED_PARAM(exec);
- return jsUndefined();
-}
JSValue JSWebGL2RenderingContext::getInternalformatParameter(ExecState* exec)
{
Modified: trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp 2015-02-18 20:42:53 UTC (rev 180285)
@@ -48,6 +48,7 @@
#include "WebGLDebugRendererInfo.h"
#include "WebGLDebugShaders.h"
#include "WebGLDepthTexture.h"
+#include "WebGLLoseContext.h"
#include "WebGLQuery.h"
#include "WebGLSampler.h"
#include "WebGLSync.h"
@@ -59,13 +60,23 @@
WebGL2RenderingContext::WebGL2RenderingContext(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
: WebGLRenderingContextBase(passedCanvas, attributes)
{
+ initializeShaderExtensions();
}
WebGL2RenderingContext::WebGL2RenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
GraphicsContext3D::Attributes attributes) : WebGLRenderingContextBase(passedCanvas, context, attributes)
{
+ initializeShaderExtensions();
}
+void WebGL2RenderingContext::initializeShaderExtensions()
+{
+ m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
+ m_context->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
+ m_context->getExtensions()->ensureEnabled("GL_EXT_shader_texture_lod");
+ m_context->getExtensions()->ensureEnabled("GL_EXT_frag_depth");
+}
+
void WebGL2RenderingContext::copyBufferSubData(GC3Denum readTarget, GC3Denum writeTarget, GC3Dint64 readOffset, GC3Dint64 writeOffset, GC3Dint64 size)
{
UNUSED_PARAM(readTarget);
@@ -89,15 +100,6 @@
UNUSED_PARAM(returnedData);
}
-WebGLGetInfo WebGL2RenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
-{
- UNUSED_PARAM(target);
- UNUSED_PARAM(attachment);
- UNUSED_PARAM(pname);
- UNUSED_PARAM(ec);
- return WebGLGetInfo();
-}
-
void WebGL2RenderingContext::blitFramebuffer(GC3Dint srcX0, GC3Dint srcY0, GC3Dint srcX1, GC3Dint srcY1, GC3Dint dstX0, GC3Dint dstY0, GC3Dint dstX1, GC3Dint dstY1, GC3Dbitfield mask, GC3Denum filter)
{
UNUSED_PARAM(srcX0);
@@ -830,6 +832,11 @@
}
return m_oesTextureHalfFloatLinear.get();
}
+ if (equalIgnoringCase(name, "WEBGL_lose_context")) {
+ if (!m_webglLoseContext)
+ m_webglLoseContext = std::make_unique<WebGLLoseContext>(this);
+ return m_webglLoseContext.get();
+ }
if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_atc"))
&& WebGLCompressedTextureATC::supported(this)) {
if (!m_webglCompressedTextureATC)
@@ -898,7 +905,7 @@
result.append("WEBGL_compressed_texture_s3tc");
if (WebGLDepthTexture::supported(graphicsContext3D()))
result.append("WEBGL_depth_texture");
-
+ result.append("WEBGL_lose_context");
if (allowPrivilegedExtensions()) {
if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
result.append("WEBGL_debug_shaders");
@@ -908,6 +915,156 @@
return result;
}
+WebGLGetInfo WebGL2RenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
+{
+ UNUSED_PARAM(ec);
+ if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
+ return WebGLGetInfo();
+
+ if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
+ return WebGLGetInfo();
+ }
+
+ WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
+ if (!object) {
+ if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
+ return WebGLGetInfo(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 WebGLGetInfo();
+ }
+
+ ASSERT(object->isTexture() || object->isRenderbuffer());
+ if (object->isTexture()) {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(GraphicsContext3D::TEXTURE);
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: {
+ GC3Dint value = 0;
+ m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
+ return WebGLGetInfo(value);
+ }
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
+ return WebGLGetInfo();
+ }
+ } else {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING : {
+ WebGLRenderbuffer* renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object);
+ GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
+ if (renderBufferFormat == GraphicsContext3D::SRGB8_ALPHA8
+ || renderBufferFormat == GraphicsContext3D::COMPRESSED_SRGB8_ETC2
+ || renderBufferFormat == GraphicsContext3D::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
+ || renderBufferFormat == GraphicsContext3D::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) {
+ return WebGLGetInfo(GraphicsContext3D::SRGB);
+ }
+ return WebGLGetInfo(GraphicsContext3D::LINEAR);
+ }
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
+ return WebGLGetInfo();
+ }
+ }
+}
+
+void WebGL2RenderingContext::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::DEPTH_COMPONENT32F:
+ case GraphicsContext3D::DEPTH_COMPONENT24:
+ case GraphicsContext3D::RGBA32I:
+ case GraphicsContext3D::RGBA32UI:
+ case GraphicsContext3D::RGBA16I:
+ case GraphicsContext3D::RGBA16UI:
+ case GraphicsContext3D::RGBA8:
+ case GraphicsContext3D::RGBA8I:
+ case GraphicsContext3D::RGBA8UI:
+ case GraphicsContext3D::RGB10_A2:
+ case GraphicsContext3D::RGB10_A2UI:
+ case GraphicsContext3D::RGBA4:
+ case GraphicsContext3D::RG32I:
+ case GraphicsContext3D::RG32UI:
+ case GraphicsContext3D::RG16I:
+ case GraphicsContext3D::RG16UI:
+ case GraphicsContext3D::RG8:
+ case GraphicsContext3D::RG8I:
+ case GraphicsContext3D::RG8UI:
+ case GraphicsContext3D::R32I:
+ case GraphicsContext3D::R32UI:
+ case GraphicsContext3D::R16I:
+ case GraphicsContext3D::R16UI:
+ case GraphicsContext3D::R8:
+ case GraphicsContext3D::R8I:
+ case GraphicsContext3D::R8UI:
+ case GraphicsContext3D::RGB5_A1:
+ case GraphicsContext3D::RGB565:
+ case GraphicsContext3D::STENCIL_INDEX8:
+ case GraphicsContext3D::SRGB8_ALPHA8:
+ m_context->renderbufferStorage(target, internalformat, width, height);
+ m_renderbufferBinding->setInternalFormat(internalformat);
+ m_renderbufferBinding->setIsValid(true);
+ m_renderbufferBinding->setSize(width, height);
+ break;
+ case GraphicsContext3D::DEPTH32F_STENCIL8:
+ case GraphicsContext3D::DEPTH24_STENCIL8:
+ if (!isDepthStencilSupported()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
+ return;
+ }
+ m_context->renderbufferStorage(target, internalformat, 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 WebGL2RenderingContext::hint(GC3Denum target, GC3Denum mode)
+{
+ if (isContextLostOrPending())
+ return;
+ bool isValid = false;
+ switch (target) {
+ case GraphicsContext3D::GENERATE_MIPMAP_HINT:
+ case GraphicsContext3D::FRAGMENT_SHADER_DERIVATIVE_HINT:
+ isValid = true;
+ break;
+ }
+ if (!isValid) {
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
+ return;
+ }
+ m_context->hint(target, mode);
+}
+
void WebGL2RenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
{
if (isContextLostOrPending())
@@ -1323,6 +1480,7 @@
case GraphicsContext3D::RGB8I:
case GraphicsContext3D::RGB8UI:
case GraphicsContext3D::SRGB8:
+ case GraphicsContext3D::SRGB8_ALPHA8:
case GraphicsContext3D::R11F_G11F_B10F:
case GraphicsContext3D::RGB9_E5:
case GraphicsContext3D::RG32F:
@@ -2034,6 +2192,159 @@
}
}
+bool WebGL2RenderingContext::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<WebGLBuffer> 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);
+
+ int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
+ if (maxIndex < 0) {
+ // 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<const GC3Dubyte*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ case GraphicsContext3D::UNSIGNED_SHORT: {
+ numElements /= sizeof(GC3Dushort);
+ const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ case GraphicsContext3D::UNSIGNED_INT: {
+ numElements /= sizeof(GC3Duint);
+ const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ default:
+ return false;
+ }
+ elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
+ }
+
+ if (maxIndex >= 0) {
+ // The number of required elements is one more than the maximum
+ // index that will be accessed.
+ numElementsRequired = maxIndex + 1;
+ return true;
+ }
+
+ return false;
+}
+
+bool WebGL2RenderingContext::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
+{
+ if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
+ return false;
+
+ if (!validateStencilSettings(functionName))
+ return false;
+
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ case GraphicsContext3D::UNSIGNED_SHORT:
+ break;
+ case GraphicsContext3D::UNSIGNED_INT:
+ break;
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
+ return false;
+ }
+
+ if (count < 0 || offset < 0) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
+ return false;
+ }
+
+ if (!count) {
+ markContextChanged();
+ return false;
+ }
+
+ if (primitiveCount < 0) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
+ return false;
+ }
+
+ if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
+ return false;
+ }
+
+ if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+ // Ensure we have a valid rendering state
+ if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
+ return false;
+ }
+ if (!count)
+ return false;
+
+ Checked<GC3Dint, RecordOverflow> checkedCount(count);
+ Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
+ if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+ return false;
+ }
+
+ if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+ if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+ return false;
+ }
+ }
+ } else {
+ if (!validateVertexAttributes(0)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
+ return false;
+ }
+ }
+
+ const char* reason = "framebuffer incomplete";
+ if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+ return false;
+ }
+
+ return true;
+}
+
+bool WebGL2RenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode)
+{
+ switch (mode) {
+ case GraphicsContext3D::FUNC_ADD:
+ case GraphicsContext3D::FUNC_SUBTRACT:
+ case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
+ case GraphicsContext3D::MIN:
+ case GraphicsContext3D::MAX:
+ return true;
+ break;
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
+ return false;
+ }
+}
+
bool WebGL2RenderingContext::validateCapability(const char* functionName, GC3Denum cap)
{
switch (cap) {
Modified: trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.h (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.h 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.h 2015-02-18 20:42:53 UTC (rev 180285)
@@ -48,7 +48,7 @@
void getBufferSubData(GC3Denum target, GC3Dint64 offset, ArrayBuffer* returnedData);
/* Framebuffer objects */
- WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&);
+ virtual WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&) override;
void blitFramebuffer(GC3Dint srcX0, GC3Dint srcY0, GC3Dint srcX1, GC3Dint srcY1, GC3Dint dstX0, GC3Dint dstY0, GC3Dint dstX1, GC3Dint dstY1, GC3Dbitfield mask, GC3Denum filter);
void framebufferTextureLayer(GC3Denum target, GC3Denum attachment, GC3Duint texture, GC3Dint level, GC3Dint layer);
WebGLGetInfo getInternalformatParameter(GC3Denum target, GC3Denum internalformat, GC3Denum pname);
@@ -167,9 +167,10 @@
/* Extensions */
virtual WebGLExtension* getExtension(const String&) override;
virtual Vector<String> getSupportedExtensions() override;
+ virtual WebGLGetInfo getParameter(GC3Denum pname, ExceptionCode&) override;
- virtual WebGLGetInfo getParameter(GC3Denum pname, ExceptionCode&) override;
-
+ virtual void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) override;
+ virtual void hint(GC3Denum target, GC3Denum mode) override;
virtual void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border) override;
virtual void texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum internalformat, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode&) override;
virtual void texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image*, GraphicsContext3D::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha, ExceptionCode&) override;
@@ -188,6 +189,9 @@
#endif
protected:
+ virtual bool validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired) override;
+ virtual bool validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount) override;
+ virtual bool validateBlendEquation(const char* functionName, GC3Denum mode) override;
virtual bool validateTexFuncFormatAndType(const char* functionName, GC3Denum internalformat, GC3Denum format, GC3Denum type, GC3Dint level) override;
virtual bool validateTexFuncParameters(const char* functionName,
TexFuncValidationFunctionType,
@@ -204,6 +208,7 @@
private:
GC3Denum baseInternalFormatFromInternalFormat(GC3Denum internalformat);
+ void initializeShaderExtensions();
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.idl (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.idl 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.idl 2015-02-18 20:42:53 UTC (rev 180285)
@@ -338,7 +338,6 @@
[StrictTypeChecking] void getBufferSubData(GLenum target, GLintptr offset, ArrayBuffer returnedData);
/* Framebuffer objects */
- [StrictTypeChecking, Custom] any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname);
[StrictTypeChecking] void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
[StrictTypeChecking] void framebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
[StrictTypeChecking, Custom] any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp 2015-02-18 20:42:53 UTC (rev 180285)
@@ -287,6 +287,135 @@
return result;
}
+WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
+{
+ UNUSED_PARAM(ec);
+ if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
+ return WebGLGetInfo();
+
+ if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
+ return WebGLGetInfo();
+ }
+
+ WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
+ if (!object) {
+ if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
+ return WebGLGetInfo(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 WebGLGetInfo();
+ }
+
+ ASSERT(object->isTexture() || object->isRenderbuffer());
+ if (object->isTexture()) {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(GraphicsContext3D::TEXTURE);
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(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 WebGLGetInfo(value);
+ }
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
+ return WebGLGetInfo();
+ }
+ } else {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
+ case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
+ if (!m_extsRGB) {
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
+ return WebGLGetInfo();
+ }
+ WebGLRenderbuffer* renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object);
+ GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
+ ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT);
+ if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT)
+ return WebGLGetInfo(Extensions3D::SRGB_EXT);
+ return WebGLGetInfo(GraphicsContext3D::LINEAR);
+ }
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
+ return WebGLGetInfo();
+ }
+ }
+}
+
+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::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
{
if (isContextLostOrPending())
@@ -976,6 +1105,168 @@
}
}
+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<WebGLBuffer> 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);
+
+ int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
+ if (maxIndex < 0) {
+ // 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<const GC3Dubyte*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ case GraphicsContext3D::UNSIGNED_SHORT: {
+ numElements /= sizeof(GC3Dushort);
+ const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ case GraphicsContext3D::UNSIGNED_INT: {
+ if (!m_oesElementIndexUint)
+ return false;
+ numElements /= sizeof(GC3Duint);
+ const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
+ for (GC3Dsizeiptr i = 0; i < numElements; i++)
+ maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
+ break;
+ }
+ default:
+ return false;
+ }
+ elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
+ }
+
+ if (maxIndex >= 0) {
+ // The number of required elements is one more than the maximum
+ // index that will be accessed.
+ numElementsRequired = maxIndex + 1;
+ return true;
+ }
+
+ return false;
+}
+
+bool WebGLRenderingContext::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
+{
+ if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
+ return false;
+
+ if (!validateStencilSettings(functionName))
+ return false;
+
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ case GraphicsContext3D::UNSIGNED_SHORT:
+ break;
+ case GraphicsContext3D::UNSIGNED_INT:
+ if (m_oesElementIndexUint)
+ break;
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
+ return false;
+ default:
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
+ return false;
+ }
+
+ if (count < 0 || offset < 0) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
+ return false;
+ }
+
+ if (!count) {
+ markContextChanged();
+ return false;
+ }
+
+ if (primitiveCount < 0) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
+ return false;
+ }
+
+ if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
+ return false;
+ }
+
+ if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+ // Ensure we have a valid rendering state
+ if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
+ return false;
+ }
+ if (!count)
+ return false;
+
+ Checked<GC3Dint, RecordOverflow> checkedCount(count);
+ Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
+ if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+ return false;
+ }
+
+ if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+ if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
+ return false;
+ }
+ }
+ } else {
+ if (!validateVertexAttributes(0)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
+ return false;
+ }
+ }
+
+ const char* reason = "framebuffer incomplete";
+ if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+ return false;
+ }
+
+ return true;
+}
+
+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) {
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContext.h (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContext.h 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContext.h 2015-02-18 20:42:53 UTC (rev 180285)
@@ -40,6 +40,9 @@
virtual WebGLGetInfo getParameter(GC3Denum pname, ExceptionCode&) override;
virtual Vector<String> getSupportedExtensions() override;
+ virtual WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&) override;
+ virtual void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) override;
+ virtual void hint(GC3Denum target, GC3Denum mode) override;
virtual void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border) override;
virtual void texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum internalformat, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode&) override;
virtual void texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image*, GraphicsContext3D::ImageHtmlDomSource, bool flipY, bool premultiplyAlpha, ExceptionCode&) override;
@@ -58,6 +61,9 @@
#endif
protected:
+ virtual bool validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired) override;
+ virtual bool validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount) override;
+ virtual bool validateBlendEquation(const char* functionName, GC3Denum mode) override;
virtual bool validateTexFuncParameters(const char* functionName,
TexFuncValidationFunctionType,
GC3Denum target, GC3Dint level,
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2015-02-18 20:42:53 UTC (rev 180285)
@@ -1720,68 +1720,6 @@
return true;
}
-bool WebGLRenderingContextBase::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<WebGLBuffer> 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);
-
- int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
- if (maxIndex < 0) {
- // 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<const GC3Dubyte*>(buffer->data());
- for (GC3Dsizeiptr i = 0; i < numElements; i++)
- maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
- break;
- }
- case GraphicsContext3D::UNSIGNED_SHORT: {
- numElements /= sizeof(GC3Dushort);
- const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
- for (GC3Dsizeiptr i = 0; i < numElements; i++)
- maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
- break;
- }
- case GraphicsContext3D::UNSIGNED_INT: {
- if (!m_oesElementIndexUint)
- return false;
- numElements /= sizeof(GC3Duint);
- const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
- for (GC3Dsizeiptr i = 0; i < numElements; i++)
- maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
- break;
- }
- default:
- return false;
- }
- elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
- }
-
- if (maxIndex >= 0) {
- // The number of required elements is one more than the maximum
- // index that will be accessed.
- numElementsRequired = maxIndex + 1;
- return true;
- }
-
- return false;
-}
-
bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
{
ASSERT(count >= 0 && offset >= 0);
@@ -1974,86 +1912,6 @@
markContextChanged();
}
-bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
-{
- if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
- return false;
-
- if (!validateStencilSettings(functionName))
- return false;
-
- switch (type) {
- case GraphicsContext3D::UNSIGNED_BYTE:
- case GraphicsContext3D::UNSIGNED_SHORT:
- break;
- case GraphicsContext3D::UNSIGNED_INT:
- if (m_oesElementIndexUint)
- break;
- synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
- return false;
- default:
- synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
- return false;
- }
-
- if (count < 0 || offset < 0) {
- synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
- return false;
- }
-
- if (!count) {
- markContextChanged();
- return false;
- }
-
- if (primitiveCount < 0) {
- synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
- return false;
- }
-
- if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
- return false;
- }
-
- if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
- // Ensure we have a valid rendering state
- if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
- return false;
- }
- if (!count)
- return false;
-
- Checked<GC3Dint, RecordOverflow> checkedCount(count);
- Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
- if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
- return false;
- }
-
- if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
- if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
- return false;
- }
- }
- } else {
- if (!validateVertexAttributes(0)) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
- return false;
- }
- }
-
- const char* reason = "framebuffer incomplete";
- if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
- synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
- return false;
- }
-
- return true;
-}
-
void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
@@ -2363,229 +2221,6 @@
return m_context->getError();
}
-WebGLExtension* WebGLRenderingContextBase::getExtension(const String& name)
-{
- if (isContextLostOrPending())
- return nullptr;
-
- if (equalIgnoringCase(name, "EXT_blend_minmax")
- && m_context->getExtensions()->supports("GL_EXT_blend_minmax")) {
- if (!m_extBlendMinMax) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_blend_minmax");
- m_extBlendMinMax = std::make_unique<EXTBlendMinMax>(this);
- }
- return m_extBlendMinMax.get();
- }
- if (equalIgnoringCase(name, "EXT_sRGB")
- && m_context->getExtensions()->supports("GL_EXT_sRGB")) {
- if (!m_extsRGB) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_sRGB");
- m_extsRGB = std::make_unique<EXTsRGB>(this);
- }
- return m_extsRGB.get();
- }
- if (equalIgnoringCase(name, "EXT_frag_depth")
- && m_context->getExtensions()->supports("GL_EXT_frag_depth")) {
- if (!m_extFragDepth) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_frag_depth");
- m_extFragDepth = std::make_unique<EXTFragDepth>(this);
- }
- return m_extFragDepth.get();
- }
- if (equalIgnoringCase(name, "EXT_shader_texture_lod")
- && (m_context->getExtensions()->supports("GL_EXT_shader_texture_lod") || m_context->getExtensions()->supports("GL_ARB_shader_texture_lod"))) {
- if (!m_extShaderTextureLOD) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_shader_texture_lod");
- m_extShaderTextureLOD = std::make_unique<EXTShaderTextureLOD>(this);
- }
- return m_extShaderTextureLOD.get();
- }
- if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
- && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
- if (!m_extTextureFilterAnisotropic) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
- m_extTextureFilterAnisotropic = std::make_unique<EXTTextureFilterAnisotropic>(this);
- }
- return m_extTextureFilterAnisotropic.get();
- }
- if (equalIgnoringCase(name, "OES_standard_derivatives")
- && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
- if (!m_oesStandardDerivatives) {
- m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
- m_oesStandardDerivatives = std::make_unique<OESStandardDerivatives>(this);
- }
- return m_oesStandardDerivatives.get();
- }
- if (equalIgnoringCase(name, "OES_texture_float")
- && m_context->getExtensions()->supports("GL_OES_texture_float")) {
- if (!m_oesTextureFloat) {
- m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
- m_oesTextureFloat = std::make_unique<OESTextureFloat>(this);
- }
- return m_oesTextureFloat.get();
- }
- if (equalIgnoringCase(name, "OES_texture_float_linear")
- && m_context->getExtensions()->supports("GL_OES_texture_float_linear")) {
- if (!m_oesTextureFloatLinear) {
- m_context->getExtensions()->ensureEnabled("GL_OES_texture_float_linear");
- m_oesTextureFloatLinear = std::make_unique<OESTextureFloatLinear>(this);
- }
- return m_oesTextureFloatLinear.get();
- }
- if (equalIgnoringCase(name, "OES_texture_half_float")
- && m_context->getExtensions()->supports("GL_OES_texture_half_float")) {
- if (!m_oesTextureHalfFloat) {
- m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float");
- m_oesTextureHalfFloat = std::make_unique<OESTextureHalfFloat>(this);
- }
- return m_oesTextureHalfFloat.get();
- }
- if (equalIgnoringCase(name, "OES_texture_half_float_linear")
- && m_context->getExtensions()->supports("GL_OES_texture_half_float_linear")) {
- if (!m_oesTextureHalfFloatLinear) {
- m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float_linear");
- m_oesTextureHalfFloatLinear = std::make_unique<OESTextureHalfFloatLinear>(this);
- }
- return m_oesTextureHalfFloatLinear.get();
- }
- if (equalIgnoringCase(name, "OES_vertex_array_object")
- && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
- if (!m_oesVertexArrayObject) {
- m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
- m_oesVertexArrayObject = std::make_unique<OESVertexArrayObject>(this);
- }
- return m_oesVertexArrayObject.get();
- }
- if (equalIgnoringCase(name, "OES_element_index_uint")
- && m_context->getExtensions()->supports("GL_OES_element_index_uint")) {
- if (!m_oesElementIndexUint) {
- m_context->getExtensions()->ensureEnabled("GL_OES_element_index_uint");
- m_oesElementIndexUint = std::make_unique<OESElementIndexUint>(this);
- }
- return m_oesElementIndexUint.get();
- }
- if (equalIgnoringCase(name, "WEBGL_lose_context")) {
- if (!m_webglLoseContext)
- m_webglLoseContext = std::make_unique<WebGLLoseContext>(this);
- return m_webglLoseContext.get();
- }
- if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_atc"))
- && WebGLCompressedTextureATC::supported(this)) {
- if (!m_webglCompressedTextureATC)
- m_webglCompressedTextureATC = std::make_unique<WebGLCompressedTextureATC>(this);
- return m_webglCompressedTextureATC.get();
- }
- if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_pvrtc"))
- && WebGLCompressedTexturePVRTC::supported(this)) {
- if (!m_webglCompressedTexturePVRTC)
- m_webglCompressedTexturePVRTC = std::make_unique<WebGLCompressedTexturePVRTC>(this);
- return m_webglCompressedTexturePVRTC.get();
- }
- if (equalIgnoringCase(name, "WEBGL_compressed_texture_s3tc")
- && WebGLCompressedTextureS3TC::supported(this)) {
- if (!m_webglCompressedTextureS3TC)
- m_webglCompressedTextureS3TC = std::make_unique<WebGLCompressedTextureS3TC>(this);
- return m_webglCompressedTextureS3TC.get();
- }
- if (equalIgnoringCase(name, "WEBGL_depth_texture")
- && WebGLDepthTexture::supported(graphicsContext3D())) {
- if (!m_webglDepthTexture) {
- m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
- m_webglDepthTexture = std::make_unique<WebGLDepthTexture>(this);
- }
- return m_webglDepthTexture.get();
- }
- if (equalIgnoringCase(name, "WEBGL_draw_buffers") && supportsDrawBuffers()) {
- if (!m_webglDrawBuffers) {
- m_context->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
- m_webglDrawBuffers = std::make_unique<WebGLDrawBuffers>(this);
- }
- return m_webglDrawBuffers.get();
- }
- if (equalIgnoringCase(name, "ANGLE_instanced_arrays") && ANGLEInstancedArrays::supported(this)) {
- if (!m_angleInstancedArrays) {
- m_context->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
- m_angleInstancedArrays = std::make_unique<ANGLEInstancedArrays>(this);
- }
- return m_angleInstancedArrays.get();
- }
- if (allowPrivilegedExtensions()) {
- if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
- if (!m_webglDebugRendererInfo)
- m_webglDebugRendererInfo = std::make_unique<WebGLDebugRendererInfo>(this);
- return m_webglDebugRendererInfo.get();
- }
- if (equalIgnoringCase(name, "WEBGL_debug_shaders")
- && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
- if (!m_webglDebugShaders)
- m_webglDebugShaders = std::make_unique<WebGLDebugShaders>(this);
- return m_webglDebugShaders.get();
- }
- }
-
- return nullptr;
-}
-
-WebGLGetInfo WebGLRenderingContextBase::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
-{
- UNUSED_PARAM(ec);
- if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
- return WebGLGetInfo();
-
- if (!m_framebufferBinding || !m_framebufferBinding->object()) {
- synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
- return WebGLGetInfo();
- }
-
- WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
- if (!object) {
- if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
- return WebGLGetInfo(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 WebGLGetInfo();
- }
-
- ASSERT(object->isTexture() || object->isRenderbuffer());
- if (object->isTexture()) {
- switch (pname) {
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return WebGLGetInfo(GraphicsContext3D::TEXTURE);
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(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 WebGLGetInfo(value);
- }
- default:
- synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
- return WebGLGetInfo();
- }
- } else {
- switch (pname) {
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
- case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
- WebGLRenderbuffer* renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object);
- GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
- ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT);
- if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT)
- return WebGLGetInfo(Extensions3D::SRGB_EXT);
- return WebGLGetInfo(GraphicsContext3D::LINEAR);
- }
- default:
- synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
- return WebGLGetInfo();
- }
- }
-}
-
WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
@@ -3003,27 +2638,6 @@
return static_cast<long long>(result);
}
-void WebGLRenderingContextBase::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);
-}
-
GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
{
if (!buffer || isContextLostOrPending())
@@ -3283,51 +2897,6 @@
m_context->releaseShaderCompiler();
}
-void WebGLRenderingContextBase::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 WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
{
if (isContextLostOrPending())
@@ -4883,26 +4452,6 @@
return true;
}
-bool WebGLRenderingContextBase::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 WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst)
{
if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h (180284 => 180285)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h 2015-02-18 20:15:53 UTC (rev 180284)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h 2015-02-18 20:42:53 UTC (rev 180285)
@@ -226,7 +226,7 @@
PassRefPtr<WebGLContextAttributes> getContextAttributes();
GC3Denum getError();
virtual WebGLExtension* getExtension(const String& name) = 0;
- WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&);
+ virtual WebGLGetInfo getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode&) = 0;
virtual WebGLGetInfo getParameter(GC3Denum pname, ExceptionCode&) = 0;
WebGLGetInfo getProgramParameter(WebGLProgram*, GC3Denum pname, ExceptionCode&);
String getProgramInfoLog(WebGLProgram*, ExceptionCode&);
@@ -242,7 +242,7 @@
WebGLGetInfo getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode&);
long long getVertexAttribOffset(GC3Duint index, GC3Denum pname);
- void hint(GC3Denum target, GC3Denum mode);
+ virtual void hint(GC3Denum target, GC3Denum mode) = 0;
GC3Dboolean isBuffer(WebGLBuffer*);
bool isContextLost() const;
GC3Dboolean isEnabled(GC3Denum cap);
@@ -258,7 +258,7 @@
void polygonOffset(GC3Dfloat factor, GC3Dfloat units);
void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&);
void releaseShaderCompiler();
- void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height);
+ virtual void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) = 0;
void sampleCoverage(GC3Dfloat value, GC3Dboolean invert);
void scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height);
void shaderSource(WebGLShader*, const String&, ExceptionCode&);
@@ -398,7 +398,7 @@
friend class WebGLRenderingContextErrorMessageCallback;
friend class WebGLVertexArrayObjectOES;
- void initializeNewContext();
+ virtual void initializeNewContext();
void setupFlags();
// ActiveDOMObject
@@ -432,7 +432,7 @@
bool validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset);
// Conservative but quick index validation
- bool validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired);
+ virtual bool validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired) = 0;
// Precise but slow index validation -- only done if conservative checks fail
bool validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired);
@@ -441,7 +441,7 @@
bool validateWebGLObject(const char*, WebGLObject*);
bool validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount);
- bool validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primcount);
+ virtual bool validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primcount) = 0;
// Adds a compressed texture format.
void addCompressedTextureFormat(GC3Denum);
@@ -770,7 +770,7 @@
bool validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment);
// Helper function to validate blend equation mode.
- bool validateBlendEquation(const char* functionName, GC3Denum);
+ virtual bool validateBlendEquation(const char* functionName, GC3Denum) = 0;
// Helper function to validate blend func factors.
bool validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst);