Index: Source/modules/webgl/WebGL2RenderingContextBase.cpp |
diff --git a/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
index a839b1ce73f670ac09edba0b3d0937e1988734ec..dd46ba74ed7ce7026ffe71b71c8c124d99114382 100644 |
--- a/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
+++ b/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
@@ -84,6 +84,17 @@ void WebGL2RenderingContextBase::initializeNewContext() |
m_samplerUnits.clear(); |
m_samplerUnits.resize(numCombinedTextureImageUnits); |
+ GLint maxTransformFeedbackSeparateAttribs = 0; |
+ webContext()->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTransformFeedbackSeparateAttribs); |
+ m_boundIndexedTransformFeedbackBuffers.clear(); |
+ m_boundIndexedTransformFeedbackBuffers.resize(maxTransformFeedbackSeparateAttribs); |
+ |
+ GLint maxUniformBufferBindings = 0; |
+ webContext()->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings); |
+ m_boundIndexedUniformBuffers.clear(); |
+ m_boundIndexedUniformBuffers.resize(maxUniformBufferBindings); |
+ m_maxBoundUniformBufferIndex = 0; |
+ |
WebGLRenderingContextBase::initializeNewContext(); |
} |
@@ -1650,19 +1661,28 @@ void WebGL2RenderingContextBase::bindBufferBase(GLenum target, GLuint index, Web |
return; |
if (deleted) |
buffer = 0; |
+ if (!validateAndUpdateBufferBindBaseTarget("bindBufferBase", target, index, buffer)) |
+ return; |
webContext()->bindBufferBase(target, index, objectOrZero(buffer)); |
} |
void WebGL2RenderingContextBase::bindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, long long offset, long long size) |
{ |
- if (isContextLost() || !validateWebGLObject("bindBufferRange", buffer)) |
+ if (isContextLost()) |
return; |
- |
+ bool deleted; |
+ if (!checkObjectToBeBound("bindBufferRange", buffer, deleted)) |
+ return; |
+ if (deleted) |
+ buffer = 0; |
if (!validateValueFitNonNegInt32("bindBufferRange", "offset", offset) |
|| !validateValueFitNonNegInt32("bindBufferRange", "size", size)) { |
return; |
} |
+ if (!validateAndUpdateBufferBindBaseTarget("bindBufferRange", target, index, buffer)) |
+ return; |
+ |
webContext()->bindBufferRange(target, index, objectOrZero(buffer), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size)); |
} |
@@ -1673,9 +1693,17 @@ ScriptValue WebGL2RenderingContextBase::getIndexedParameter(ScriptState* scriptS |
switch (target) { |
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: |
+ if (index >= m_boundIndexedTransformFeedbackBuffers.size()) { |
+ synthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter", "index out of range"); |
+ return ScriptValue::createNull(scriptState); |
+ } |
+ return WebGLAny(scriptState, m_boundIndexedTransformFeedbackBuffers[index].get()); |
case GL_UNIFORM_BUFFER_BINDING: |
- notImplemented(); |
- return ScriptValue::createNull(scriptState); |
+ if (index >= m_boundIndexedUniformBuffers.size()) { |
+ synthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter", "index out of range"); |
+ return ScriptValue::createNull(scriptState); |
+ } |
+ return WebGLAny(scriptState, m_boundIndexedUniformBuffers[index].get()); |
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: |
case GL_TRANSFORM_FEEDBACK_BUFFER_START: |
case GL_UNIFORM_BUFFER_SIZE: |
@@ -2055,6 +2083,95 @@ bool WebGL2RenderingContextBase::validateCapability(const char* functionName, GL |
} |
} |
+bool WebGL2RenderingContextBase::isBufferBoundToTransformFeedback(WebGLBuffer* buffer) |
+{ |
+ ASSERT(buffer); |
+ |
+ if (m_boundTransformFeedbackBuffer == buffer) |
+ return true; |
+ |
+ for (size_t i = 0; i < m_boundIndexedTransformFeedbackBuffers.size(); ++i) { |
+ if (m_boundIndexedTransformFeedbackBuffers[i] == buffer) |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+bool WebGL2RenderingContextBase::isBufferBoundToNonTransformFeedback(WebGLBuffer* buffer) |
+{ |
+ ASSERT(buffer); |
+ |
+ if (m_boundArrayBuffer == buffer |
+ || m_boundVertexArrayObject->boundElementArrayBuffer() == buffer |
+ || m_boundCopyReadBuffer == buffer |
+ || m_boundCopyWriteBuffer == buffer |
+ || m_boundPixelPackBuffer == buffer |
+ || m_boundPixelUnpackBuffer == buffer |
+ || m_boundUniformBuffer == buffer) { |
+ return true; |
+ } |
+ |
+ for (size_t i = 0; i <= m_maxBoundUniformBufferIndex; ++i) { |
+ if (m_boundIndexedUniformBuffers[i] == buffer) |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+bool WebGL2RenderingContextBase::validateBufferTargetCompatibility(const char* functionName, GLenum target, WebGLBuffer* buffer) |
+{ |
+ ASSERT(buffer); |
+ |
+ switch (buffer->getInitialTarget()) { |
+ case GL_ELEMENT_ARRAY_BUFFER: |
+ switch (target) { |
+ case GL_ARRAY_BUFFER: |
+ case GL_PIXEL_PACK_BUFFER: |
+ case GL_PIXEL_UNPACK_BUFFER: |
+ case GL_TRANSFORM_FEEDBACK_BUFFER: |
+ case GL_UNIFORM_BUFFER: |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, |
+ "element array buffers can not be bound to a different target"); |
+ |
+ return false; |
+ default: |
+ break; |
+ } |
+ break; |
+ case GL_ARRAY_BUFFER: |
+ case GL_COPY_READ_BUFFER: |
+ case GL_COPY_WRITE_BUFFER: |
+ case GL_PIXEL_PACK_BUFFER: |
+ case GL_PIXEL_UNPACK_BUFFER: |
+ case GL_UNIFORM_BUFFER: |
+ case GL_TRANSFORM_FEEDBACK_BUFFER: |
+ if (target == GL_ELEMENT_ARRAY_BUFFER) { |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, |
+ "buffers bound to non ELEMENT_ARRAY_BUFFER targets can not be bound to ELEMENT_ARRAY_BUFFER target"); |
+ return false; |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ |
+ if (target == GL_TRANSFORM_FEEDBACK_BUFFER) { |
+ if (isBufferBoundToNonTransformFeedback(buffer)) { |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, |
+ "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to any other targets"); |
+ return false; |
+ } |
+ } else if (isBufferBoundToTransformFeedback(buffer)) { |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, |
+ "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to any other targets"); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
bool WebGL2RenderingContextBase::validateBufferTarget(const char* functionName, GLenum target) |
{ |
switch (target) { |
@@ -2078,57 +2195,8 @@ bool WebGL2RenderingContextBase::validateAndUpdateBufferBindTarget(const char* f |
if (!validateBufferTarget(functionName, target)) |
return false; |
- if (buffer) { |
- switch (buffer->getInitialTarget()) { |
- case GL_ELEMENT_ARRAY_BUFFER: |
- switch (target) { |
- case GL_ARRAY_BUFFER: |
- case GL_PIXEL_PACK_BUFFER: |
- case GL_PIXEL_UNPACK_BUFFER: |
- case GL_TRANSFORM_FEEDBACK_BUFFER: |
- case GL_UNIFORM_BUFFER: |
- synthesizeGLError(GL_INVALID_OPERATION, functionName, |
- "element array buffers can not be bound to a different target"); |
- |
- return false; |
- default: |
- break; |
- } |
- break; |
- case GL_ARRAY_BUFFER: |
- case GL_COPY_READ_BUFFER: |
- case GL_COPY_WRITE_BUFFER: |
- case GL_PIXEL_PACK_BUFFER: |
- case GL_PIXEL_UNPACK_BUFFER: |
- case GL_UNIFORM_BUFFER: |
- case GL_TRANSFORM_FEEDBACK_BUFFER: |
- if (target == GL_ELEMENT_ARRAY_BUFFER) { |
- synthesizeGLError(GL_INVALID_OPERATION, functionName, |
- "buffers bound to non ELEMENT_ARRAY_BUFFER targets can not be bound to ELEMENT_ARRAY_BUFFER target"); |
- return false; |
- } |
- break; |
- default: |
- break; |
- } |
- if (target == GL_TRANSFORM_FEEDBACK_BUFFER) { |
- if (m_boundArrayBuffer == buffer |
- || m_boundVertexArrayObject->boundElementArrayBuffer() == buffer |
- || m_boundCopyReadBuffer == buffer |
- || m_boundCopyWriteBuffer == buffer |
- || m_boundPixelPackBuffer == buffer |
- || m_boundPixelUnpackBuffer == buffer |
- || m_boundUniformBuffer == buffer) { |
- synthesizeGLError(GL_INVALID_OPERATION, functionName, |
- "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to any other targets"); |
- return false; |
- } |
- } else if (m_boundTransformFeedbackBuffer == buffer) { |
- synthesizeGLError(GL_INVALID_OPERATION, functionName, |
- "a buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to any other targets"); |
- return false; |
- } |
- } |
+ if (buffer && !validateBufferTargetCompatibility(functionName, target, buffer)) |
+ return false; |
switch (target) { |
case GL_ARRAY_BUFFER: |
@@ -2165,6 +2233,66 @@ bool WebGL2RenderingContextBase::validateAndUpdateBufferBindTarget(const char* f |
return true; |
} |
+bool WebGL2RenderingContextBase::validateBufferBaseTarget(const char* functionName, GLenum target) |
+{ |
+ switch (target) { |
+ case GL_TRANSFORM_FEEDBACK_BUFFER: |
+ case GL_UNIFORM_BUFFER: |
+ return true; |
+ default: |
+ synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target"); |
+ return false; |
+ } |
+} |
+ |
+bool WebGL2RenderingContextBase::validateAndUpdateBufferBindBaseTarget(const char* functionName, GLenum target, GLuint index, WebGLBuffer* buffer) |
+{ |
+ if (!validateBufferBaseTarget(functionName, target)) |
+ return false; |
+ |
+ if (buffer && !validateBufferTargetCompatibility(functionName, target, buffer)) |
+ return false; |
+ |
+ switch (target) { |
+ case GL_TRANSFORM_FEEDBACK_BUFFER: |
+ if (index >= m_boundIndexedTransformFeedbackBuffers.size()) { |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, "index out of range"); |
+ return false; |
+ } |
+ m_boundIndexedTransformFeedbackBuffers[index] = buffer; |
+ m_boundTransformFeedbackBuffer = buffer; |
+ break; |
+ case GL_UNIFORM_BUFFER: |
+ if (index >= m_boundIndexedUniformBuffers.size()) { |
+ synthesizeGLError(GL_INVALID_OPERATION, functionName, "index out of range"); |
+ return false; |
+ } |
+ m_boundIndexedUniformBuffers[index] = buffer; |
+ m_boundUniformBuffer = buffer; |
+ |
+ // Keep track of what the maximum bound uniform buffer index is |
+ if (buffer) { |
+ if (index > m_maxBoundUniformBufferIndex) |
+ m_maxBoundUniformBufferIndex = index; |
+ } else if (m_maxBoundUniformBufferIndex > 0 && index == m_maxBoundUniformBufferIndex) { |
+ size_t i = m_maxBoundUniformBufferIndex - 1; |
+ for (; i > 0; --i) { |
+ if (m_boundIndexedUniformBuffers[i].get()) |
+ break; |
+ } |
+ m_maxBoundUniformBufferIndex = i; |
+ } |
+ break; |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ break; |
+ } |
+ |
+ if (buffer && !buffer->getInitialTarget()) |
+ buffer->setInitialTarget(target); |
+ return true; |
+} |
+ |
bool WebGL2RenderingContextBase::validateFramebufferTarget(GLenum target) |
{ |
switch (target) { |