Commit 0c7baf1b by Corentin Wallez Committed by Commit Bot

Implement the WebGL VertexAttribPointer restrictions

BUG=angleproject:1523 BUG=chromium:668223 Change-Id: Ic89c476a6c95824069772e22ede596ba85ac8859 Reviewed-on: https://chromium-review.googlesource.com/422347 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 71168a07
...@@ -33,8 +33,10 @@ namespace gl ...@@ -33,8 +33,10 @@ namespace gl
const unsigned int Float32One = 0x3F800000; const unsigned int Float32One = 0x3F800000;
const unsigned short Float16One = 0x3C00; const unsigned short Float16One = 0x3C00;
inline bool isPow2(int x) template<typename T>
inline bool isPow2(T x)
{ {
static_assert(std::is_integral<T>::value, "isPow2 must be called on an integer type.");
return (x & (x - 1)) == 0 && (x != 0); return (x & (x - 1)) == 0 && (x != 0);
} }
......
...@@ -1654,6 +1654,123 @@ const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType) ...@@ -1654,6 +1654,123 @@ const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType)
} }
} }
size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType)
{
switch (vertexFormatType)
{
case VERTEX_FORMAT_SBYTE1:
case VERTEX_FORMAT_SBYTE1_NORM:
case VERTEX_FORMAT_UBYTE1:
case VERTEX_FORMAT_UBYTE1_NORM:
case VERTEX_FORMAT_SBYTE1_INT:
case VERTEX_FORMAT_UBYTE1_INT:
return 1;
case VERTEX_FORMAT_SBYTE2:
case VERTEX_FORMAT_SBYTE2_NORM:
case VERTEX_FORMAT_UBYTE2:
case VERTEX_FORMAT_UBYTE2_NORM:
case VERTEX_FORMAT_SBYTE2_INT:
case VERTEX_FORMAT_UBYTE2_INT:
case VERTEX_FORMAT_SSHORT1:
case VERTEX_FORMAT_SSHORT1_NORM:
case VERTEX_FORMAT_USHORT1:
case VERTEX_FORMAT_USHORT1_NORM:
case VERTEX_FORMAT_SSHORT1_INT:
case VERTEX_FORMAT_USHORT1_INT:
case VERTEX_FORMAT_HALF1:
return 2;
case VERTEX_FORMAT_SBYTE3:
case VERTEX_FORMAT_SBYTE3_NORM:
case VERTEX_FORMAT_UBYTE3:
case VERTEX_FORMAT_UBYTE3_NORM:
case VERTEX_FORMAT_SBYTE3_INT:
case VERTEX_FORMAT_UBYTE3_INT:
return 3;
case VERTEX_FORMAT_SBYTE4:
case VERTEX_FORMAT_SBYTE4_NORM:
case VERTEX_FORMAT_UBYTE4:
case VERTEX_FORMAT_UBYTE4_NORM:
case VERTEX_FORMAT_SBYTE4_INT:
case VERTEX_FORMAT_UBYTE4_INT:
case VERTEX_FORMAT_SSHORT2:
case VERTEX_FORMAT_SSHORT2_NORM:
case VERTEX_FORMAT_USHORT2:
case VERTEX_FORMAT_USHORT2_NORM:
case VERTEX_FORMAT_SSHORT2_INT:
case VERTEX_FORMAT_USHORT2_INT:
case VERTEX_FORMAT_SINT1:
case VERTEX_FORMAT_SINT1_NORM:
case VERTEX_FORMAT_UINT1:
case VERTEX_FORMAT_UINT1_NORM:
case VERTEX_FORMAT_SINT1_INT:
case VERTEX_FORMAT_UINT1_INT:
case VERTEX_FORMAT_HALF2:
case VERTEX_FORMAT_FIXED1:
case VERTEX_FORMAT_FLOAT1:
case VERTEX_FORMAT_SINT210:
case VERTEX_FORMAT_UINT210:
case VERTEX_FORMAT_SINT210_NORM:
case VERTEX_FORMAT_UINT210_NORM:
case VERTEX_FORMAT_SINT210_INT:
case VERTEX_FORMAT_UINT210_INT:
return 4;
case VERTEX_FORMAT_SSHORT3:
case VERTEX_FORMAT_SSHORT3_NORM:
case VERTEX_FORMAT_USHORT3:
case VERTEX_FORMAT_USHORT3_NORM:
case VERTEX_FORMAT_SSHORT3_INT:
case VERTEX_FORMAT_USHORT3_INT:
case VERTEX_FORMAT_HALF3:
return 6;
case VERTEX_FORMAT_SSHORT4:
case VERTEX_FORMAT_SSHORT4_NORM:
case VERTEX_FORMAT_USHORT4:
case VERTEX_FORMAT_USHORT4_NORM:
case VERTEX_FORMAT_SSHORT4_INT:
case VERTEX_FORMAT_USHORT4_INT:
case VERTEX_FORMAT_SINT2:
case VERTEX_FORMAT_SINT2_NORM:
case VERTEX_FORMAT_UINT2:
case VERTEX_FORMAT_UINT2_NORM:
case VERTEX_FORMAT_SINT2_INT:
case VERTEX_FORMAT_UINT2_INT:
case VERTEX_FORMAT_HALF4:
case VERTEX_FORMAT_FIXED2:
case VERTEX_FORMAT_FLOAT2:
return 8;
case VERTEX_FORMAT_SINT3:
case VERTEX_FORMAT_SINT3_NORM:
case VERTEX_FORMAT_UINT3:
case VERTEX_FORMAT_UINT3_NORM:
case VERTEX_FORMAT_SINT3_INT:
case VERTEX_FORMAT_UINT3_INT:
case VERTEX_FORMAT_FIXED3:
case VERTEX_FORMAT_FLOAT3:
return 12;
case VERTEX_FORMAT_SINT4:
case VERTEX_FORMAT_SINT4_NORM:
case VERTEX_FORMAT_UINT4:
case VERTEX_FORMAT_UINT4_NORM:
case VERTEX_FORMAT_SINT4_INT:
case VERTEX_FORMAT_UINT4_INT:
case VERTEX_FORMAT_FIXED4:
case VERTEX_FORMAT_FLOAT4:
return 16;
case VERTEX_FORMAT_INVALID:
default:
UNREACHABLE();
return 0;
}
}
VertexFormat::VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn) VertexFormat::VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn)
: type(typeIn), : type(typeIn),
normalized(normalizedIn), normalized(normalizedIn),
......
...@@ -293,6 +293,7 @@ VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint c ...@@ -293,6 +293,7 @@ VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint c
VertexFormatType GetVertexFormatType(const VertexAttribute &attrib); VertexFormatType GetVertexFormatType(const VertexAttribute &attrib);
VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType); VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType);
const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType); const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType);
size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType);
// Implemented in format_map_autogen.cpp // Implemented in format_map_autogen.cpp
bool ValidES3Format(GLenum format); bool ValidES3Format(GLenum format);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/validationES.h" #include "libANGLE/validationES.h"
#include "libANGLE/validationES3.h" #include "libANGLE/validationES3.h"
#include "libANGLE/VertexArray.h"
namespace gl namespace gl
{ {
...@@ -3881,4 +3882,126 @@ bool ValidateLineWidth(ValidationContext *context, GLfloat width) ...@@ -3881,4 +3882,126 @@ bool ValidateLineWidth(ValidationContext *context, GLfloat width)
return true; return true;
} }
bool ValidateVertexAttribPointer(ValidationContext *context,
GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid *ptr)
{
if (index >= MAX_VERTEX_ATTRIBS)
{
context->handleError(Error(GL_INVALID_VALUE, "Invalid index value."));
return false;
}
if (size < 1 || size > 4)
{
context->handleError(Error(GL_INVALID_VALUE, "Invalide size value."));
return false;
}
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_FIXED:
case GL_FLOAT:
break;
case GL_HALF_FLOAT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
if (context->getClientMajorVersion() < 3)
{
context->handleError(
Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
return false;
}
break;
default:
context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
return false;
}
if (stride < 0)
{
context->handleError(Error(GL_INVALID_VALUE, "Invalid stride."));
return false;
}
if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4)
{
context->handleError(Error(GL_INVALID_OPERATION, "Invalid size for a sized vertex type."));
return false;
}
// [OpenGL ES 3.0.2] Section 2.8 page 24:
// An INVALID_OPERATION error is generated when a non-zero vertex array object
// is bound, zero is bound to the ARRAY_BUFFER buffer object binding point,
// and the pointer argument is not NULL.
if (context->getGLState().getVertexArray()->id() != 0 &&
context->getGLState().getArrayBufferId() == 0 && ptr != NULL)
{
context->handleError(
Error(GL_INVALID_OPERATION,
"Pointer is null with a non-zero VAO bound and zero bound to GL_ARRAY_BUFFER."));
return false;
}
if (context->getExtensions().webglCompatibility)
{
// WebGL 1.0 [Section 6.14] Fixed point support
// The WebGL API does not support the GL_FIXED data type.
if (type == GL_FIXED)
{
context->handleError(Error(GL_INVALID_ENUM, "GL_FIXED is not supported in WebGL."));
return false;
}
// WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
// The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
// vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
// parameter exceeds 255.
constexpr GLsizei kMaxWebGLStride = 255;
if (stride > kMaxWebGLStride)
{
context->handleError(
Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
return false;
}
// WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
// The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
// vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
// or an INVALID_OPERATION error is generated.
VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, false);
size_t typeSize = GetVertexFormatTypeSize(internalType);
ASSERT(isPow2(typeSize) && typeSize > 0);
size_t sizeMask = (typeSize - 1);
if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
{
context->handleError(
Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
return false;
}
if ((stride & sizeMask) != 0)
{
context->handleError(
Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
return false;
}
}
return true;
}
} // namespace gl } // namespace gl
...@@ -372,6 +372,13 @@ bool ValidateBlendFuncSeparate(ValidationContext *context, ...@@ -372,6 +372,13 @@ bool ValidateBlendFuncSeparate(ValidationContext *context,
bool ValidateGetString(Context *context, GLenum name); bool ValidateGetString(Context *context, GLenum name);
bool ValidateLineWidth(ValidationContext *context, GLfloat width); bool ValidateLineWidth(ValidationContext *context, GLfloat width);
bool ValidateVertexAttribPointer(ValidationContext *context,
GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid *ptr);
} // namespace gl } // namespace gl
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
#include "libANGLE/Texture.h" #include "libANGLE/Texture.h"
#include "libANGLE/VertexArray.h" #include "libANGLE/VertexArray.h"
#include "libANGLE/VertexAttribute.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/validationES.h" #include "libANGLE/validationES.h"
...@@ -2740,65 +2739,9 @@ void GL_APIENTRY VertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo ...@@ -2740,65 +2739,9 @@ void GL_APIENTRY VertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (index >= MAX_VERTEX_ATTRIBS) if (!context->skipValidation() &&
{ !ValidateVertexAttribPointer(context, index, size, type, normalized, stride, ptr))
context->handleError(Error(GL_INVALID_VALUE));
return;
}
if (size < 1 || size > 4)
{
context->handleError(Error(GL_INVALID_VALUE));
return;
}
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_FIXED:
case GL_FLOAT:
break;
case GL_HALF_FLOAT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
if (context->getClientMajorVersion() < 3)
{
context->handleError(Error(GL_INVALID_ENUM));
return;
}
break;
default:
context->handleError(Error(GL_INVALID_ENUM));
return;
}
if (stride < 0)
{
context->handleError(Error(GL_INVALID_VALUE));
return;
}
if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4)
{
context->handleError(Error(GL_INVALID_OPERATION));
return;
}
// [OpenGL ES 3.0.2] Section 2.8 page 24:
// An INVALID_OPERATION error is generated when a non-zero vertex array object
// is bound, zero is bound to the ARRAY_BUFFER buffer object binding point,
// and the pointer argument is not NULL.
if (context->getGLState().getVertexArray()->id() != 0 &&
context->getGLState().getArrayBufferId() == 0 && ptr != NULL)
{ {
context->handleError(Error(GL_INVALID_OPERATION));
return; return;
} }
......
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