WebGL: Fix DrawElements test and remove size check.
Also optimizes the DrawElements validation to remove redundant tests.
Also make some more validation WebGL-specific.
Bug: angleproject:2979
Change-Id: I2d5c3094ed86ebadbc572e46b8ae105431f7ae68
Reviewed-on: https://chromium-review.googlesource.com/c/1343139
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 5e20b7d..b5dc8d8 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -3030,10 +3030,10 @@
Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
GLuint typeBytes = GetTypeInfo(type).bytes;
+ ASSERT(isPow2(typeBytes) && typeBytes > 0);
if (context->getExtensions().webglCompatibility)
{
- ASSERT(isPow2(typeBytes) && typeBytes > 0);
if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
{
// [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
@@ -3051,19 +3051,7 @@
context->validationError(GL_INVALID_VALUE, kNegativeOffset);
return false;
}
- }
- else if (elementArrayBuffer && elementArrayBuffer->isMapped())
- {
- // WebGL buffers cannot be mapped/unmapped because the MapBufferRange,
- // FlushMappedBufferRange, and UnmapBuffer entry points are removed from the WebGL 2.0 API.
- // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
- context->validationError(GL_INVALID_OPERATION, "Index buffer is mapped.");
- return false;
- }
- if (context->getExtensions().webglCompatibility ||
- !context->getGLState().areClientArraysEnabled())
- {
if (!elementArrayBuffer)
{
// [WebGL 1.0] Section 6.2 No Client Side Arrays
@@ -3072,86 +3060,103 @@
context->validationError(GL_INVALID_OPERATION, kMustHaveElementArrayBinding);
return false;
}
- }
- if (count > 0 && !elementArrayBuffer && !indices)
- {
- // This is an application error that would normally result in a crash, but we catch it and
- // return an error
- context->validationError(GL_INVALID_OPERATION, "No element array buffer and no pointer.");
- return false;
- }
-
- if (count > 0 && elementArrayBuffer)
- {
- // The max possible type size is 8 and count is on 32 bits so doing the multiplication
- // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
- static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
- constexpr uint64_t kMaxTypeSize = 8;
- constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
- constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
- static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
-
- uint64_t typeSize = typeBytes;
- uint64_t elementCount = static_cast<uint64_t>(count);
- ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
-
- // Doing the multiplication here is overflow-safe
- uint64_t elementDataSizeNoOffset = typeSize * elementCount;
-
- // The offset can be any value, check for overflows
- uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
- if (elementDataSizeNoOffset > kUint64Max - offset)
- {
- context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
- return false;
- }
-
- uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
- if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
- {
- context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
- return false;
- }
-
- ASSERT(isPow2(typeSize) && typeSize > 0);
- if ((elementArrayBuffer->getSize() & (typeSize - 1)) != 0)
- {
- context->validationError(GL_INVALID_OPERATION, kMismatchedByteCountType);
- return false;
- }
-
- if (context->getExtensions().webglCompatibility &&
- elementArrayBuffer->isBoundForTransformFeedbackAndOtherUse())
+ if (elementArrayBuffer->isBoundForTransformFeedbackAndOtherUse())
{
context->validationError(GL_INVALID_OPERATION,
kElementArrayBufferBoundForTransformFeedback);
return false;
}
}
-
- if (!context->getExtensions().robustBufferAccessBehavior && count > 0 && primcount > 0)
+ else
{
- // Use the parameter buffer to retrieve and cache the index range.
- IndexRange indexRange;
- ANGLE_VALIDATION_TRY(vao->getIndexRange(context, type, count, indices, &indexRange));
-
- // If we use an index greater than our maximum supported index range, return an error.
- // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
- // return an error if possible here.
- if (static_cast<GLuint64>(indexRange.end) >= context->getCaps().maxElementIndex)
+ if (elementArrayBuffer)
{
- context->validationError(GL_INVALID_OPERATION, kExceedsMaxElement);
+ if (elementArrayBuffer->isMapped())
+ {
+ // WebGL buffers cannot be mapped/unmapped because the MapBufferRange,
+ // FlushMappedBufferRange, and UnmapBuffer entry points are removed from the
+ // WebGL 2.0 API. https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
+ context->validationError(GL_INVALID_OPERATION, "Index buffer is mapped.");
+ return false;
+ }
+ }
+ else if (!context->getGLState().areClientArraysEnabled())
+ {
+ context->validationError(GL_INVALID_OPERATION, kMustHaveElementArrayBinding);
return false;
}
+ }
- if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRange.end)))
+ if (count > 0)
+ {
+ if (!elementArrayBuffer)
{
- return false;
+ if (!indices)
+ {
+ // This is an application error that would normally result in a crash, but we catch
+ // it and return an error
+ context->validationError(GL_INVALID_OPERATION,
+ "No element array buffer and no pointer.");
+ return false;
+ }
+ }
+ else
+ {
+ // The max possible type size is 8 and count is on 32 bits so doing the multiplication
+ // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
+ static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
+ constexpr uint64_t kMaxTypeSize = 8;
+ constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
+ constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
+ static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
+
+ uint64_t typeSize = typeBytes;
+ uint64_t elementCount = static_cast<uint64_t>(count);
+ ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
+
+ // Doing the multiplication here is overflow-safe
+ uint64_t elementDataSizeNoOffset = typeSize * elementCount;
+
+ // The offset can be any value, check for overflows
+ uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
+ if (elementDataSizeNoOffset > kUint64Max - offset)
+ {
+ context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
+ return false;
+ }
+
+ uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
+ if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
+ {
+ context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
+ return false;
+ }
}
- // No op if there are no real indices in the index data (all are primitive restart).
- return (indexRange.vertexIndexCount > 0);
+ if (!context->getExtensions().robustBufferAccessBehavior && primcount > 0)
+ {
+ // Use the parameter buffer to retrieve and cache the index range.
+ IndexRange indexRange;
+ ANGLE_VALIDATION_TRY(vao->getIndexRange(context, type, count, indices, &indexRange));
+
+ // If we use an index greater than our maximum supported index range, return an error.
+ // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should
+ // always return an error if possible here.
+ if (static_cast<GLuint64>(indexRange.end) >= context->getCaps().maxElementIndex)
+ {
+ context->validationError(GL_INVALID_OPERATION, kExceedsMaxElement);
+ return false;
+ }
+
+ if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRange.end)))
+ {
+ return false;
+ }
+
+ // No op if there are no real indices in the index data (all are primitive restart).
+ return (indexRange.vertexIndexCount > 0);
+ }
}
return true;