Fix buffer alignment math in draw validation.
We had a bug where we would require "stride * primCount" bytes when
drawing from a buffer, when the last element would not require the
full stride. The correct expression: "stride * (primCount-1) + size.
BUG=angleproject:1086
TEST=dEQP-GLES3.functional.vertex_arrays.single_attribute.strides.*
Change-Id: I7e2897c9d18b0e9849289d033f0ae2573237e4e5
Reviewed-on: https://chromium-review.googlesource.com/287320
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 2896519..7f28528 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -25,6 +25,73 @@
namespace gl
{
+namespace
+{
+bool ValidateDrawAttribs(gl::Context *context, GLint primcount, GLint maxVertex)
+{
+ const gl::State &state = context->getState();
+ const gl::Program *program = state.getProgram();
+
+ const VertexArray *vao = state.getVertexArray();
+ const auto &vertexAttribs = vao->getVertexAttributes();
+ const int *semanticIndexes = program->getSemanticIndexes();
+ size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
+ for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
+ {
+ const VertexAttribute &attrib = vertexAttribs[attributeIndex];
+ bool attribActive = (semanticIndexes[attributeIndex] != -1);
+ if (attribActive && attrib.enabled)
+ {
+ gl::Buffer *buffer = attrib.buffer.get();
+
+ if (buffer)
+ {
+ GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
+ GLint64 maxVertexElement = 0;
+
+ if (attrib.divisor > 0)
+ {
+ maxVertexElement =
+ static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
+ }
+ else
+ {
+ maxVertexElement = static_cast<GLint64>(maxVertex);
+ }
+
+ // If we're drawing zero vertices, we have enough data.
+ if (maxVertexElement > 0)
+ {
+ // Note: Last vertex element does not take the full stride!
+ GLint64 attribSize =
+ static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
+ GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
+
+ // [OpenGL ES 3.0.2] section 2.9.4 page 40:
+ // We can return INVALID_OPERATION if our vertex attribute does not have
+ // enough backing data.
+ if (attribDataSize > buffer->getSize())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ }
+ else if (attrib.pointer == NULL)
+ {
+ // This is an application error that would normally result in a crash,
+ // but we catch it and return an error
+ context->recordError(Error(
+ GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // anonymous namespace
bool ValidCap(const Context *context, GLenum cap)
{
@@ -1403,51 +1470,9 @@
}
// Buffer validations
- const VertexArray *vao = state.getVertexArray();
- const auto &vertexAttribs = vao->getVertexAttributes();
- const int *semanticIndexes = program->getSemanticIndexes();
- size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
- for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
+ if (!ValidateDrawAttribs(context, primcount, maxVertex))
{
- const VertexAttribute &attrib = vertexAttribs[attributeIndex];
- bool attribActive = (semanticIndexes[attributeIndex] != -1);
- if (attribActive && attrib.enabled)
- {
- gl::Buffer *buffer = attrib.buffer.get();
-
- if (buffer)
- {
- GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
- GLint64 maxVertexElement = 0;
-
- if (attrib.divisor > 0)
- {
- maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
- }
- else
- {
- maxVertexElement = static_cast<GLint64>(maxVertex);
- }
-
- GLint64 attribDataSize = maxVertexElement * attribStride;
-
- // [OpenGL ES 3.0.2] section 2.9.4 page 40:
- // We can return INVALID_OPERATION if our vertex attribute does not have
- // enough backing data.
- if (attribDataSize > buffer->getSize())
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
- else if (attrib.pointer == NULL)
- {
- // This is an application error that would normally result in a crash,
- // but we catch it and return an error
- context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
- return false;
- }
- }
+ return false;
}
// Uniform buffer validation