Commit 1ca7467f by Jamie Madill

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/287320Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 63046e2b
...@@ -25,6 +25,73 @@ ...@@ -25,6 +25,73 @@
namespace gl 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) bool ValidCap(const Context *context, GLenum cap)
{ {
...@@ -1403,51 +1470,9 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz ...@@ -1403,51 +1470,9 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz
} }
// Buffer validations // Buffer validations
const VertexArray *vao = state.getVertexArray(); if (!ValidateDrawAttribs(context, primcount, maxVertex))
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]; return false;
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;
}
}
} }
// Uniform buffer validation // Uniform buffer validation
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment