Commit 80957d99 by Shao Committed by Commit Bot

ES31: Implement Vertex Attrib Binding entry points

This patch intends to implement all entry points related to Vertex Attrib Binding. (1) Add entry points and validation code on following APIs: - VertexAttribFormat - VertexAttribIFormat - VertexAttribBinding - BindVertexBuffer - VertexBindingDivisor (2) Add queries on following parameters: - VERTEX_ATTRIB_BINDING - VERTEX_ATTRIB_RELATIVE_OFFSET - VERTEX_BINDING_DIVISOR - VERTEX_BINDING_OFFSET - VERTEX_BINDING_STRIDE - VERTEX_BINDING_BUFFER BUG=angleproject:1593 TEST=angle_end2end_tests TEST=angle_unittests TEST=dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_relative_offset_* TEST=dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_bindings_* TEST=dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_stride_* TEST=dEQP-GLES31.functional.state_query.vertex_attribute_binding.* TEST=dEQP-GLES31.functional.debug.negative_coverage.log.vertex_array.vertex_attrib_pointer TEST=dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.vertex_attrib_format TEST=dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.vertex_attrib_i_format Change-Id: I4b477a82df6aad89b89b088580a06d66963e6666 Reviewed-on: https://chromium-review.googlesource.com/446124 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 484dd7b1
...@@ -994,7 +994,7 @@ void Context::bindDrawIndirectBuffer(GLuint bufferHandle) ...@@ -994,7 +994,7 @@ void Context::bindDrawIndirectBuffer(GLuint bufferHandle)
void Context::bindElementArrayBuffer(GLuint bufferHandle) void Context::bindElementArrayBuffer(GLuint bufferHandle)
{ {
Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle); Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle);
mGLState.getVertexArray()->setElementArrayBuffer(buffer); mGLState.setElementArrayBuffer(buffer);
} }
void Context::bindTexture(GLenum target, GLuint handle) void Context::bindTexture(GLenum target, GLuint handle)
...@@ -1034,6 +1034,15 @@ void Context::bindVertexArray(GLuint vertexArrayHandle) ...@@ -1034,6 +1034,15 @@ void Context::bindVertexArray(GLuint vertexArrayHandle)
mGLState.setVertexArrayBinding(vertexArray); mGLState.setVertexArrayBinding(vertexArray);
} }
void Context::bindVertexBuffer(GLuint bindingIndex,
GLuint bufferHandle,
GLintptr offset,
GLsizei stride)
{
Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle);
mGLState.bindVertexBuffer(bindingIndex, buffer, offset, stride);
}
void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle) void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle)
{ {
ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits);
...@@ -3581,6 +3590,34 @@ void Context::vertexAttribPointer(GLuint index, ...@@ -3581,6 +3590,34 @@ void Context::vertexAttribPointer(GLuint index,
normalized == GL_TRUE, false, stride, ptr); normalized == GL_TRUE, false, stride, ptr);
} }
void Context::vertexAttribFormat(GLuint attribIndex,
GLint size,
GLenum type,
GLboolean normalized,
GLuint relativeOffset)
{
mGLState.setVertexAttribFormat(attribIndex, size, type, normalized == GL_TRUE, false,
relativeOffset);
}
void Context::vertexAttribIFormat(GLuint attribIndex,
GLint size,
GLenum type,
GLuint relativeOffset)
{
mGLState.setVertexAttribFormat(attribIndex, size, type, false, true, relativeOffset);
}
void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
{
mGLState.setVertexAttribBinding(attribIndex, bindingIndex);
}
void Context::setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
{
mGLState.setVertexBindingDivisor(bindingIndex, divisor);
}
void Context::viewport(GLint x, GLint y, GLsizei width, GLsizei height) void Context::viewport(GLint x, GLint y, GLsizei width, GLsizei height)
{ {
mGLState.setViewportParams(x, y, width, height); mGLState.setViewportParams(x, y, width, height);
......
...@@ -129,6 +129,10 @@ class Context final : public ValidationContext ...@@ -129,6 +129,10 @@ class Context final : public ValidationContext
void bindReadFramebuffer(GLuint framebufferHandle); void bindReadFramebuffer(GLuint framebufferHandle);
void bindDrawFramebuffer(GLuint framebufferHandle); void bindDrawFramebuffer(GLuint framebufferHandle);
void bindVertexArray(GLuint vertexArrayHandle); void bindVertexArray(GLuint vertexArrayHandle);
void bindVertexBuffer(GLuint bindingIndex,
GLuint bufferHandle,
GLintptr offset,
GLsizei stride);
void bindSampler(GLuint textureUnit, GLuint samplerHandle); void bindSampler(GLuint textureUnit, GLuint samplerHandle);
void bindGenericUniformBuffer(GLuint bufferHandle); void bindGenericUniformBuffer(GLuint bufferHandle);
void bindIndexedUniformBuffer(GLuint bufferHandle, void bindIndexedUniformBuffer(GLuint bufferHandle,
...@@ -163,6 +167,7 @@ class Context final : public ValidationContext ...@@ -163,6 +167,7 @@ class Context final : public ValidationContext
void getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params); void getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params);
void setVertexAttribDivisor(GLuint index, GLuint divisor); void setVertexAttribDivisor(GLuint index, GLuint divisor);
void setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor);
void getBufferParameteriv(GLenum target, GLenum pname, GLint *params); void getBufferParameteriv(GLenum target, GLenum pname, GLint *params);
void getFramebufferAttachmentParameteriv(GLenum target, void getFramebufferAttachmentParameteriv(GLenum target,
...@@ -265,19 +270,26 @@ class Context final : public ValidationContext ...@@ -265,19 +270,26 @@ class Context final : public ValidationContext
void vertexAttrib3fv(GLuint index, const GLfloat *values); void vertexAttrib3fv(GLuint index, const GLfloat *values);
void vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); void vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(GLuint index, const GLfloat *values); void vertexAttrib4fv(GLuint index, const GLfloat *values);
void vertexAttribFormat(GLuint attribIndex,
GLint size,
GLenum type,
GLboolean normalized,
GLuint relativeOffset);
void vertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset);
void vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex);
void vertexAttribPointer(GLuint index, void vertexAttribPointer(GLuint index,
GLint size, GLint size,
GLenum type, GLenum type,
GLboolean normalized, GLboolean normalized,
GLsizei stride, GLsizei stride,
const GLvoid *ptr); const GLvoid *ptr);
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
void vertexAttribIPointer(GLuint index, void vertexAttribIPointer(GLuint index,
GLint size, GLint size,
GLenum type, GLenum type,
GLsizei stride, GLsizei stride,
const GLvoid *pointer); const GLvoid *pointer);
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
void vertexAttribI4iv(GLuint index, const GLint *v); void vertexAttribI4iv(GLuint index, const GLint *v);
......
...@@ -687,6 +687,10 @@ bool ValidationContext::getIndexedQueryParameterInfo(GLenum target, ...@@ -687,6 +687,10 @@ bool ValidationContext::getIndexedQueryParameterInfo(GLenum target,
case GL_MAX_COMPUTE_WORK_GROUP_COUNT: case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
case GL_MAX_COMPUTE_WORK_GROUP_SIZE: case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
case GL_ATOMIC_COUNTER_BUFFER_BINDING: case GL_ATOMIC_COUNTER_BUFFER_BINDING:
case GL_VERTEX_BINDING_BUFFER:
case GL_VERTEX_BINDING_DIVISOR:
case GL_VERTEX_BINDING_OFFSET:
case GL_VERTEX_BINDING_STRIDE:
{ {
*type = GL_INT; *type = GL_INT;
*numParams = 1; *numParams = 1;
......
...@@ -1041,6 +1041,45 @@ bool State::removeVertexArrayBinding(GLuint vertexArray) ...@@ -1041,6 +1041,45 @@ bool State::removeVertexArrayBinding(GLuint vertexArray)
return false; return false;
} }
void State::setElementArrayBuffer(Buffer *buffer)
{
getVertexArray()->setElementArrayBuffer(buffer);
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::bindVertexBuffer(GLuint bindingIndex,
Buffer *boundBuffer,
GLintptr offset,
GLsizei stride)
{
getVertexArray()->bindVertexBuffer(bindingIndex, boundBuffer, offset, stride);
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::setVertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
{
getVertexArray()->setVertexAttribBinding(attribIndex, bindingIndex);
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::setVertexAttribFormat(GLuint attribIndex,
GLint size,
GLenum type,
bool normalized,
bool pureInteger,
GLuint relativeOffset)
{
getVertexArray()->setVertexAttribFormat(attribIndex, size, type, normalized, pureInteger,
relativeOffset);
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
{
getVertexArray()->setVertexBindingDivisor(bindingIndex, divisor);
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::setProgram(const Context *context, Program *newProgram) void State::setProgram(const Context *context, Program *newProgram)
{ {
if (mProgram != newProgram) if (mProgram != newProgram)
...@@ -1936,6 +1975,22 @@ void State::getIntegeri_v(GLenum target, GLuint index, GLint *data) ...@@ -1936,6 +1975,22 @@ void State::getIntegeri_v(GLenum target, GLuint index, GLint *data)
ASSERT(static_cast<size_t>(index) < mAtomicCounterBuffers.size()); ASSERT(static_cast<size_t>(index) < mAtomicCounterBuffers.size());
*data = mAtomicCounterBuffers[index].id(); *data = mAtomicCounterBuffers[index].id();
break; break;
case GL_VERTEX_BINDING_BUFFER:
ASSERT(static_cast<size_t>(index) < mVertexArray->getMaxBindings());
*data = mVertexArray->getVertexBinding(index).buffer.id();
break;
case GL_VERTEX_BINDING_DIVISOR:
ASSERT(static_cast<size_t>(index) < mVertexArray->getMaxBindings());
*data = mVertexArray->getVertexBinding(index).divisor;
break;
case GL_VERTEX_BINDING_OFFSET:
ASSERT(static_cast<size_t>(index) < mVertexArray->getMaxBindings());
*data = static_cast<GLuint>(mVertexArray->getVertexBinding(index).offset);
break;
case GL_VERTEX_BINDING_STRIDE:
ASSERT(static_cast<size_t>(index) < mVertexArray->getMaxBindings());
*data = mVertexArray->getVertexBinding(index).stride;
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -251,6 +251,7 @@ class State : angle::NonCopyable ...@@ -251,6 +251,7 @@ class State : angle::NonCopyable
// Vertex attrib manipulation // Vertex attrib manipulation
void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
void setElementArrayBuffer(Buffer *buffer);
void setVertexAttribf(GLuint index, const GLfloat values[4]); void setVertexAttribf(GLuint index, const GLfloat values[4]);
void setVertexAttribu(GLuint index, const GLuint values[4]); void setVertexAttribu(GLuint index, const GLuint values[4]);
void setVertexAttribi(GLuint index, const GLint values[4]); void setVertexAttribi(GLuint index, const GLint values[4]);
...@@ -259,6 +260,18 @@ class State : angle::NonCopyable ...@@ -259,6 +260,18 @@ class State : angle::NonCopyable
void setVertexAttribDivisor(GLuint index, GLuint divisor); void setVertexAttribDivisor(GLuint index, GLuint divisor);
const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const;
const void *getVertexAttribPointer(unsigned int attribNum) const; const void *getVertexAttribPointer(unsigned int attribNum) const;
void bindVertexBuffer(GLuint bindingIndex,
Buffer *boundBuffer,
GLintptr offset,
GLsizei stride);
void setVertexAttribFormat(GLuint attribIndex,
GLint size,
GLenum type,
bool normalized,
bool pureInteger,
GLuint relativeOffset);
void setVertexAttribBinding(GLuint attribIndex, GLuint bindingIndex);
void setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor);
// Pixel pack state manipulation // Pixel pack state manipulation
void setPackAlignment(GLint alignment); void setPackAlignment(GLint alignment);
......
...@@ -96,8 +96,8 @@ size_t VertexArray::GetAttribIndex(unsigned long dirtyBit) ...@@ -96,8 +96,8 @@ size_t VertexArray::GetAttribIndex(unsigned long dirtyBit)
{ {
static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
"The stride of vertex attributes should equal to that of vertex bindings."); "The stride of vertex attributes should equal to that of vertex bindings.");
ASSERT(dirtyBit > gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER); ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
return (dirtyBit - gl::VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS; return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS;
} }
void VertexArray::bindVertexBuffer(size_t bindingIndex, void VertexArray::bindVertexBuffer(size_t bindingIndex,
...@@ -119,8 +119,7 @@ void VertexArray::setVertexAttribBinding(size_t attribIndex, size_t bindingIndex ...@@ -119,8 +119,7 @@ void VertexArray::setVertexAttribBinding(size_t attribIndex, size_t bindingIndex
{ {
ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings()); ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
// TODO(jiawei.shao@intel.com): Vertex Attrib Bindings mState.mVertexAttributes[attribIndex].bindingIndex = static_cast<GLuint>(bindingIndex);
ASSERT(attribIndex == bindingIndex);
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex); mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex);
} }
...@@ -162,6 +161,7 @@ void VertexArray::setVertexAttribDivisor(size_t index, GLuint divisor) ...@@ -162,6 +161,7 @@ void VertexArray::setVertexAttribDivisor(size_t index, GLuint divisor)
void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
{ {
ASSERT(attribIndex < getMaxAttribs()); ASSERT(attribIndex < getMaxAttribs());
mState.mVertexAttributes[attribIndex].enabled = enabledState; mState.mVertexAttributes[attribIndex].enabled = enabledState;
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex); mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex);
......
...@@ -100,6 +100,18 @@ class VertexArray final : public LabeledObject ...@@ -100,6 +100,18 @@ class VertexArray final : public LabeledObject
bool pureInteger, bool pureInteger,
GLsizei stride, GLsizei stride,
const void *pointer); const void *pointer);
void setVertexAttribFormat(size_t attribIndex,
GLint size,
GLenum type,
bool normalized,
bool pureInteger,
GLintptr relativeOffset);
void bindVertexBuffer(size_t bindingIndex,
Buffer *boundBuffer,
GLintptr offset,
GLsizei stride);
void setVertexAttribBinding(size_t attribIndex, size_t bindingIndex);
void setVertexBindingDivisor(size_t bindingIndex, GLuint divisor);
void setElementArrayBuffer(Buffer *buffer); void setElementArrayBuffer(Buffer *buffer);
...@@ -164,21 +176,6 @@ class VertexArray final : public LabeledObject ...@@ -164,21 +176,6 @@ class VertexArray final : public LabeledObject
bool hasAnyDirtyBit() const { return mDirtyBits.any(); } bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
private: private:
// TODO(jiawei.shao@intel.com): make these functions public when Vertex Attrib Binding entries
// are ready.
void setVertexAttribFormat(size_t attribIndex,
GLint size,
GLenum type,
bool normalized,
bool pureInteger,
GLintptr relativeOffset);
void bindVertexBuffer(size_t bindingIndex,
Buffer *boundBuffer,
GLintptr offset,
GLsizei stride);
void setVertexAttribBinding(size_t attribIndex, size_t bindingIndex);
void setVertexBindingDivisor(size_t bindingIndex, GLuint divisor);
GLuint mId; GLuint mId;
VertexArrayState mState; VertexArrayState mState;
......
...@@ -390,6 +390,15 @@ void QueryVertexAttribBase(const VertexAttribute &attrib, ...@@ -390,6 +390,15 @@ void QueryVertexAttribBase(const VertexAttribute &attrib,
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
*params = ConvertFromGLboolean<ParamType>(attrib.pureInteger); *params = ConvertFromGLboolean<ParamType>(attrib.pureInteger);
break; break;
case GL_VERTEX_ATTRIB_BINDING:
*params = ConvertFromGLuint<ParamType>(attrib.bindingIndex);
break;
case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
// attrib.relativeOffset should not be negative or greater than max GLint
ASSERT(attrib.relativeOffset >= 0 &&
attrib.relativeOffset <= std::numeric_limits<GLint>::max());
*params = ConvertFromGLint<ParamType>(static_cast<GLint>(attrib.relativeOffset));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -1227,6 +1227,8 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons ...@@ -1227,6 +1227,8 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
// Vertex Attribute Bindings are emulated on D3D11. // Vertex Attribute Bindings are emulated on D3D11.
caps->maxVertexAttribBindings = caps->maxVertexAttributes; caps->maxVertexAttribBindings = caps->maxVertexAttributes;
// Experimental testing confirmed there is no explicit limit on maximum buffer offset in D3D11.
caps->maxVertexAttribRelativeOffset = std::numeric_limits<GLint>::max();
// Experimental testing confirmed 2048 is the maximum stride that D3D11 can support on all // Experimental testing confirmed 2048 is the maximum stride that D3D11 can support on all
// platforms. // platforms.
caps->maxVertexAttribStride = 2048; caps->maxVertexAttribStride = 2048;
......
...@@ -66,11 +66,11 @@ VertexArrayGL::~VertexArrayGL() ...@@ -66,11 +66,11 @@ VertexArrayGL::~VertexArrayGL()
mStateManager->deleteBuffer(mStreamingElementArrayBuffer); mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
mStreamingElementArrayBufferSize = 0; mStreamingElementArrayBufferSize = 0;
mStreamingElementArrayBuffer = 0; mStreamingElementArrayBuffer = 0;
mStateManager->deleteBuffer(mStreamingArrayBuffer); mStateManager->deleteBuffer(mStreamingArrayBuffer);
mStreamingArrayBufferSize = 0; mStreamingArrayBufferSize = 0;
mStreamingArrayBuffer = 0; mStreamingArrayBuffer = 0;
mAppliedElementArrayBuffer.set(nullptr); mAppliedElementArrayBuffer.set(nullptr);
for (auto &binding : mAppliedBindings) for (auto &binding : mAppliedBindings)
...@@ -125,10 +125,12 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute ...@@ -125,10 +125,12 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute
{ {
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID()); mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
// Check if any attributes need to be streamed, determines if the index range needs to be computed // Check if any attributes need to be streamed, determines if the index range needs to be
// computed
bool attributesNeedStreaming = mAttributesNeedStreaming.any(); bool attributesNeedStreaming = mAttributesNeedStreaming.any();
// Determine if an index buffer needs to be streamed and the range of vertices that need to be copied // Determine if an index buffer needs to be streamed and the range of vertices that need to be
// copied
IndexRange indexRange; IndexRange indexRange;
if (type != GL_NONE) if (type != GL_NONE)
{ {
...@@ -143,7 +145,7 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute ...@@ -143,7 +145,7 @@ gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttribute
{ {
// Not an indexed call, set the range to [first, first + count - 1] // Not an indexed call, set the range to [first, first + count - 1]
indexRange.start = first; indexRange.start = first;
indexRange.end = first + count - 1; indexRange.end = first + count - 1;
} }
if (attributesNeedStreaming) if (attributesNeedStreaming)
...@@ -184,7 +186,7 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count, ...@@ -184,7 +186,7 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count,
if (attributesNeedStreaming) if (attributesNeedStreaming)
{ {
ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices); ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Error error = mData.getElementArrayBuffer()->getIndexRange( Error error = mData.getElementArrayBuffer()->getIndexRange(
type, elementArrayBufferOffset, count, primitiveRestartEnabled, outIndexRange); type, elementArrayBufferOffset, count, primitiveRestartEnabled, outIndexRange);
if (error.isError()) if (error.isError())
{ {
...@@ -192,7 +194,8 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count, ...@@ -192,7 +194,8 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count,
} }
} }
// Indices serves as an offset into the index buffer in this case, use the same value for the draw call // Indices serves as an offset into the index buffer in this case, use the same value for
// the draw call
*outIndices = indices; *outIndices = indices;
} }
else else
...@@ -222,16 +225,19 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count, ...@@ -222,16 +225,19 @@ gl::Error VertexArrayGL::syncIndexData(GLsizei count,
if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize) if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
{ {
// Copy the indices in while resizing the buffer // Copy the indices in while resizing the buffer
mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW); mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
GL_DYNAMIC_DRAW);
mStreamingElementArrayBufferSize = requiredStreamingBufferSize; mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
} }
else else
{ {
// Put the indices at the beginning of the buffer // Put the indices at the beginning of the buffer
mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices); mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
indices);
} }
// Set the index offset for the draw call to zero since the supplied index pointer is to client data // Set the index offset for the draw call to zero since the supplied index pointer is to
// client data
*outIndices = nullptr; *outIndices = nullptr;
} }
...@@ -249,11 +255,11 @@ void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &act ...@@ -249,11 +255,11 @@ void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &act
ASSERT(mAttributesNeedStreaming.any()); ASSERT(mAttributesNeedStreaming.any());
const auto &attribs = mData.getVertexAttributes(); const auto &attribs = mData.getVertexAttributes();
const auto &bindings = mData.getVertexBindings(); const auto &bindings = mData.getVertexBindings();
for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask)) for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
{ {
const auto &attrib = attribs[idx]; const auto &attrib = attribs[idx];
const auto &binding = bindings[attrib.bindingIndex]; const auto &binding = bindings[attrib.bindingIndex];
ASSERT(AttributeNeedsStreaming(attrib, binding)); ASSERT(AttributeNeedsStreaming(attrib, binding));
...@@ -289,9 +295,9 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib ...@@ -289,9 +295,9 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
mStreamingArrayBufferSize = 0; mStreamingArrayBufferSize = 0;
} }
// If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
// the same 'first' argument can be passed into the draw call. // so that the same 'first' argument can be passed into the draw call.
const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start; const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace; const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer); mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
...@@ -302,9 +308,9 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib ...@@ -302,9 +308,9 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
} }
// Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
// somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY // somehow (such as by a screen change), retry writing the data a few times and return
// if that fails. // OUT_OF_MEMORY if that fails.
GLboolean unmapResult = GL_FALSE; GLboolean unmapResult = GL_FALSE;
size_t unmapRetryAttempts = 5; size_t unmapRetryAttempts = 5;
while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0) while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
{ {
...@@ -312,11 +318,11 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib ...@@ -312,11 +318,11 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
requiredBufferSize, GL_MAP_WRITE_BIT); requiredBufferSize, GL_MAP_WRITE_BIT);
size_t curBufferOffset = bufferEmptySpace; size_t curBufferOffset = bufferEmptySpace;
const auto &attribs = mData.getVertexAttributes(); const auto &attribs = mData.getVertexAttributes();
const auto &bindings = mData.getVertexBindings(); const auto &bindings = mData.getVertexBindings();
for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask)) for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
{ {
const auto &attrib = attribs[idx]; const auto &attrib = attribs[idx];
const auto &binding = bindings[attrib.bindingIndex]; const auto &binding = bindings[attrib.bindingIndex];
ASSERT(AttributeNeedsStreaming(attrib, binding)); ASSERT(AttributeNeedsStreaming(attrib, binding));
...@@ -347,7 +353,7 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib ...@@ -347,7 +353,7 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
// Copy each vertex individually // Copy each vertex individually
for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++) for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
{ {
uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx); uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex); const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
memcpy(out, in, destStride); memcpy(out, in, destStride);
} }
......
...@@ -1111,7 +1111,18 @@ bool ValidateGetVertexAttribBase(Context *context, ...@@ -1111,7 +1111,18 @@ bool ValidateGetVertexAttribBase(Context *context,
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
if (context->getClientMajorVersion() < 3) if (context->getClientMajorVersion() < 3)
{ {
context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0.")); context->handleError(Error(
GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
return false;
}
break;
case GL_VERTEX_ATTRIB_BINDING:
case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
if (context->getClientVersion() < ES_3_1)
{
context->handleError(
Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
return false; return false;
} }
break; break;
...@@ -5735,4 +5746,94 @@ bool ValidateGetInternalFormativRobustANGLE(Context *context, ...@@ -5735,4 +5746,94 @@ bool ValidateGetInternalFormativRobustANGLE(Context *context,
return true; return true;
} }
bool ValidateVertexFormatBase(ValidationContext *context,
GLuint attribIndex,
GLint size,
GLenum type,
GLboolean pureInteger)
{
const Caps &caps = context->getCaps();
if (attribIndex >= caps.maxVertexAttributes)
{
context->handleError(
Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
return false;
}
if (size < 1 || size > 4)
{
context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
}
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
break;
case GL_INT:
case GL_UNSIGNED_INT:
if (context->getClientMajorVersion() < 3)
{
context->handleError(
Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
return false;
}
break;
case GL_FIXED:
case GL_FLOAT:
if (pureInteger)
{
context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
return false;
}
break;
case GL_HALF_FLOAT:
if (context->getClientMajorVersion() < 3)
{
context->handleError(
Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
return false;
}
if (pureInteger)
{
context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
return false;
}
break;
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;
}
if (pureInteger)
{
context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
return false;
}
if (size != 4)
{
context->handleError(Error(GL_INVALID_OPERATION,
"Type is INT_2_10_10_10_REV or "
"UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
return false;
}
break;
default:
context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
return false;
}
return true;
}
} // namespace gl } // namespace gl
...@@ -602,6 +602,7 @@ bool ValidateGetInternalFormativ(Context *context, ...@@ -602,6 +602,7 @@ bool ValidateGetInternalFormativ(Context *context,
GLenum pname, GLenum pname,
GLsizei bufSize, GLsizei bufSize,
GLint *params); GLint *params);
bool ValidateGetInternalFormativRobustANGLE(Context *context, bool ValidateGetInternalFormativRobustANGLE(Context *context,
GLenum target, GLenum target,
GLenum internalformat, GLenum internalformat,
...@@ -610,6 +611,12 @@ bool ValidateGetInternalFormativRobustANGLE(Context *context, ...@@ -610,6 +611,12 @@ bool ValidateGetInternalFormativRobustANGLE(Context *context,
GLsizei *length, GLsizei *length,
GLint *params); GLint *params);
bool ValidateVertexFormatBase(ValidationContext *context,
GLuint attribIndex,
GLint size,
GLenum type,
GLboolean pureInteger);
// Error messages shared here for use in testing. // Error messages shared here for use in testing.
extern const char *g_ExceedsMaxElementErrorMessage; extern const char *g_ExceedsMaxElementErrorMessage;
} // namespace gl } // namespace gl
......
...@@ -3935,56 +3935,33 @@ bool ValidateVertexAttribPointer(ValidationContext *context, ...@@ -3935,56 +3935,33 @@ bool ValidateVertexAttribPointer(ValidationContext *context,
GLsizei stride, GLsizei stride,
const GLvoid *ptr) const GLvoid *ptr)
{ {
if (index >= MAX_VERTEX_ATTRIBS) if (!ValidateVertexFormatBase(context, index, size, type, false))
{ {
context->handleError(Error(GL_INVALID_VALUE, "Invalid index value."));
return false; return false;
} }
if (size < 1 || size > 4) if (stride < 0)
{ {
context->handleError(Error(GL_INVALID_VALUE, "Invalide size value.")); context->handleError(Error(GL_INVALID_VALUE, "stride cannot be negative."));
return false; return false;
} }
switch (type) const Caps &caps = context->getCaps();
if (context->getClientVersion() >= ES_3_1)
{ {
case GL_BYTE: if (stride > caps.maxVertexAttribStride)
case GL_UNSIGNED_BYTE: {
case GL_SHORT: context->handleError(
case GL_UNSIGNED_SHORT: Error(GL_INVALID_VALUE, "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."));
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; 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) if (index >= caps.maxVertexAttribBindings)
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Invalid size for a sized vertex type.")); context->handleError(
return false; Error(GL_INVALID_VALUE, "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
return false;
}
} }
// [OpenGL ES 3.0.2] Section 2.8 page 24: // [OpenGL ES 3.0.2] Section 2.8 page 24:
...@@ -3993,11 +3970,11 @@ bool ValidateVertexAttribPointer(ValidationContext *context, ...@@ -3993,11 +3970,11 @@ bool ValidateVertexAttribPointer(ValidationContext *context,
// and the pointer argument is not NULL. // and the pointer argument is not NULL.
bool nullBufferAllowed = context->getGLState().areClientArraysEnabled() && bool nullBufferAllowed = context->getGLState().areClientArraysEnabled() &&
context->getGLState().getVertexArray()->id() == 0; context->getGLState().getVertexArray()->id() == 0;
if (!nullBufferAllowed && context->getGLState().getArrayBufferId() == 0 && ptr != NULL) if (!nullBufferAllowed && context->getGLState().getArrayBufferId() == 0 && ptr != nullptr)
{ {
context->handleError( context->handleError(
Error(GL_INVALID_OPERATION, Error(GL_INVALID_OPERATION,
"Pointer is null with a non-zero VAO bound and zero bound to GL_ARRAY_BUFFER.")); "Client data cannot be used with a non-default vertex array object."));
return false; return false;
} }
......
...@@ -1986,6 +1986,7 @@ bool ValidateIndexedStateQuery(ValidationContext *context, ...@@ -1986,6 +1986,7 @@ bool ValidateIndexedStateQuery(ValidationContext *context,
return false; return false;
} }
break; break;
case GL_MAX_COMPUTE_WORK_GROUP_SIZE: case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
case GL_MAX_COMPUTE_WORK_GROUP_COUNT: case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
if (index >= 3u) if (index >= 3u)
...@@ -1994,6 +1995,7 @@ bool ValidateIndexedStateQuery(ValidationContext *context, ...@@ -1994,6 +1995,7 @@ bool ValidateIndexedStateQuery(ValidationContext *context,
return false; return false;
} }
break; break;
case GL_ATOMIC_COUNTER_BUFFER_START: case GL_ATOMIC_COUNTER_BUFFER_START:
case GL_ATOMIC_COUNTER_BUFFER_SIZE: case GL_ATOMIC_COUNTER_BUFFER_SIZE:
case GL_ATOMIC_COUNTER_BUFFER_BINDING: case GL_ATOMIC_COUNTER_BUFFER_BINDING:
...@@ -2012,6 +2014,27 @@ bool ValidateIndexedStateQuery(ValidationContext *context, ...@@ -2012,6 +2014,27 @@ bool ValidateIndexedStateQuery(ValidationContext *context,
return false; return false;
} }
break; break;
case GL_VERTEX_BINDING_BUFFER:
case GL_VERTEX_BINDING_DIVISOR:
case GL_VERTEX_BINDING_OFFSET:
case GL_VERTEX_BINDING_STRIDE:
if (context->getClientVersion() < ES_3_1)
{
context->handleError(
Error(GL_INVALID_ENUM,
"Vertex Attrib Bindings are not supported in this version of GL"));
return false;
}
if (index >= caps.maxVertexAttribBindings)
{
context->handleError(
Error(GL_INVALID_VALUE,
"bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
return false;
}
break;
default: default:
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
return false; return false;
...@@ -2291,43 +2314,41 @@ bool ValidateVertexAttribIPointer(ValidationContext *context, ...@@ -2291,43 +2314,41 @@ bool ValidateVertexAttribIPointer(ValidationContext *context,
{ {
if (context->getClientMajorVersion() < 3) if (context->getClientMajorVersion() < 3)
{ {
context->handleError(Error(GL_INVALID_OPERATION, context->handleError(
"glVertexAttribIPointer requires OpenGL ES 3.0 or higher.")); Error(GL_INVALID_OPERATION, "VertexAttribIPointer requires OpenGL ES 3.0 or higher."));
return false; return false;
} }
if (index >= MAX_VERTEX_ATTRIBS) if (!ValidateVertexFormatBase(context, index, size, type, true))
{ {
context->handleError(
Error(GL_INVALID_VALUE, "Index must be less than MAX_VERTEX_ATTRIBS."));
return false; return false;
} }
if (size < 1 || size > 4) if (stride < 0)
{ {
context->handleError(Error(GL_INVALID_VALUE, "Size must be between 1 and 4.")); context->handleError(Error(GL_INVALID_VALUE, "stride cannot be negative."));
return false; return false;
} }
switch (type) const Caps &caps = context->getCaps();
if (context->getClientVersion() >= ES_3_1)
{ {
case GL_BYTE: if (stride > caps.maxVertexAttribStride)
case GL_UNSIGNED_BYTE: {
case GL_SHORT: context->handleError(
case GL_UNSIGNED_SHORT: Error(GL_INVALID_VALUE, "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."));
case GL_INT:
case GL_UNSIGNED_INT:
break;
default:
context->handleError(Error(GL_INVALID_ENUM, "Unknown vertex attribute type."));
return false; return false;
} }
if (stride < 0) // [OpenGL ES 3.1] Section 10.3.1 page 245:
{ // glVertexAttribBinding is part of the equivalent code of VertexAttribIPointer, so its
context->handleError(Error(GL_INVALID_VALUE, "Stride cannot be negative.")); // validation should be inherited.
return false; if (index >= caps.maxVertexAttribBindings)
{
context->handleError(
Error(GL_INVALID_VALUE, "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
return false;
}
} }
// [OpenGL ES 3.0.2] Section 2.8 page 24: // [OpenGL ES 3.0.2] Section 2.8 page 24:
......
...@@ -550,6 +550,153 @@ bool ValidateGetProgramResourceIndex(Context *context, ...@@ -550,6 +550,153 @@ bool ValidateGetProgramResourceIndex(Context *context,
Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface)); Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface));
return false; return false;
} }
return true;
}
bool ValidateBindVertexBuffer(ValidationContext *context,
GLuint bindingIndex,
GLuint buffer,
GLintptr offset,
GLsizei stride)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
return false;
}
if (!context->isBufferGenerated(buffer))
{
context->handleError(Error(GL_INVALID_OPERATION, "Buffer is not generated."));
return false;
}
const Caps &caps = context->getCaps();
if (bindingIndex >= caps.maxVertexAttribBindings)
{
context->handleError(Error(
GL_INVALID_VALUE, "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
return false;
}
if (offset < 0)
{
context->handleError(Error(GL_INVALID_VALUE, "offset cannot be negative."));
return false;
}
if (stride < 0 || stride > caps.maxVertexAttribStride)
{
context->handleError(
Error(GL_INVALID_VALUE, "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE."));
return false;
}
// [OpenGL ES 3.1] Section 10.3.1 page 244:
// An INVALID_OPERATION error is generated if the default vertex array object is bound.
if (context->getGLState().getVertexArrayId() == 0)
{
context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array buffer is bound."));
return false;
}
return true;
}
bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
return false;
}
const Caps &caps = context->getCaps();
if (bindingIndex >= caps.maxVertexAttribBindings)
{
context->handleError(Error(
GL_INVALID_VALUE, "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
return false;
}
// [OpenGL ES 3.1] Section 10.3.1 page 243:
// An INVALID_OPERATION error is generated if the default vertex array object is bound.
if (context->getGLState().getVertexArrayId() == 0)
{
context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
return false;
}
return true;
}
bool ValidateVertexAttribFormat(ValidationContext *context,
GLuint attribIndex,
GLint size,
GLenum type,
GLuint relativeOffset,
GLboolean pureInteger)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
return false;
}
const Caps &caps = context->getCaps();
if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
{
context->handleError(
Error(GL_INVALID_VALUE,
"relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET."));
return false;
}
// [OpenGL ES 3.1] Section 10.3.1 page 243:
// An INVALID_OPERATION error is generated if the default vertex array object is bound.
if (context->getGLState().getVertexArrayId() == 0)
{
context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
return false;
}
return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
}
bool ValidateVertexAttribBinding(ValidationContext *context,
GLuint attribIndex,
GLuint bindingIndex)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
return false;
}
// [OpenGL ES 3.1] Section 10.3.1 page 243:
// An INVALID_OPERATION error is generated if the default vertex array object is bound.
if (context->getGLState().getVertexArrayId() == 0)
{
context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
return false;
}
const Caps &caps = context->getCaps();
if (attribIndex >= caps.maxVertexAttributes)
{
context->handleError(
Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
return false;
}
if (bindingIndex >= caps.maxVertexAttribBindings)
{
context->handleError(Error(GL_INVALID_VALUE,
"bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS"));
return false;
}
return true; return true;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
namespace gl namespace gl
{ {
class Context; class Context;
class ValidationContext;
bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data); bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data);
bool ValidateGetBooleani_vRobustANGLE(Context *context, bool ValidateGetBooleani_vRobustANGLE(Context *context,
...@@ -61,6 +62,22 @@ bool ValidateGetProgramResourceIndex(Context *context, ...@@ -61,6 +62,22 @@ bool ValidateGetProgramResourceIndex(Context *context,
GLenum programInterface, GLenum programInterface,
const GLchar *name); const GLchar *name);
bool ValidateBindVertexBuffer(ValidationContext *context,
GLuint bindingIndex,
GLuint buffer,
GLintptr offset,
GLsizei stride);
bool ValidateVertexAttribFormat(ValidationContext *context,
GLuint attribIndex,
GLint size,
GLenum type,
GLuint relativeOffset,
GLboolean pureInteger);
bool ValidateVertexAttribBinding(ValidationContext *context,
GLuint attribIndex,
GLuint bindingIndex);
bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES31_H_ #endif // LIBANGLE_VALIDATION_ES31_H_
...@@ -1119,11 +1119,13 @@ void GL_APIENTRY BindVertexBuffer(GLuint bindingindex, ...@@ -1119,11 +1119,13 @@ void GL_APIENTRY BindVertexBuffer(GLuint bindingindex,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateBindVertexBuffer(context, bindingindex, buffer, offset, stride))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return;
} }
UNIMPLEMENTED();
context->bindVertexBuffer(bindingindex, buffer, offset, stride);
} }
} }
...@@ -1140,11 +1142,13 @@ void GL_APIENTRY VertexAttribFormat(GLuint attribindex, ...@@ -1140,11 +1142,13 @@ void GL_APIENTRY VertexAttribFormat(GLuint attribindex,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateVertexAttribFormat(context, attribindex, size, type, relativeoffset, false))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return;
} }
UNIMPLEMENTED();
context->vertexAttribFormat(attribindex, size, type, normalized, relativeoffset);
} }
} }
...@@ -1160,11 +1164,13 @@ void GL_APIENTRY VertexAttribIFormat(GLuint attribindex, ...@@ -1160,11 +1164,13 @@ void GL_APIENTRY VertexAttribIFormat(GLuint attribindex,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateVertexAttribFormat(context, attribindex, size, type, relativeoffset, true))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return;
} }
UNIMPLEMENTED();
context->vertexAttribIFormat(attribindex, size, type, relativeoffset);
} }
} }
...@@ -1174,11 +1180,13 @@ void GL_APIENTRY VertexAttribBinding(GLuint attribindex, GLuint bindingindex) ...@@ -1174,11 +1180,13 @@ void GL_APIENTRY VertexAttribBinding(GLuint attribindex, GLuint bindingindex)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateVertexAttribBinding(context, attribindex, bindingindex))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return;
} }
UNIMPLEMENTED();
context->vertexAttribBinding(attribindex, bindingindex);
} }
} }
...@@ -1188,11 +1196,13 @@ void GL_APIENTRY VertexBindingDivisor(GLuint bindingindex, GLuint divisor) ...@@ -1188,11 +1196,13 @@ void GL_APIENTRY VertexBindingDivisor(GLuint bindingindex, GLuint divisor)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateVertexBindingDivisor(context, bindingindex, divisor))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return;
} }
UNIMPLEMENTED();
context->setVertexBindingDivisor(bindingindex, divisor);
} }
} }
} // namespace gl } // namespace gl
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.array_size.vertex_fragment.default_block_struct_member = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.array_size.vertex_fragment.default_block_struct_member = SKIP
1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.name_length.vertex_fragment.default_block_struct_member = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.name_length.vertex_fragment.default_block_struct_member = SKIP
1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.type.vertex_fragment.struct.* = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.type.vertex_fragment.struct.* = SKIP
1442 OPENGL D3D11 : dEQP-GLES31.functional.vertex_attribute_binding.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.stencil_texturing.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.stencil_texturing.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.state_query.shader.sampler_type = SKIP 1442 D3D11 : dEQP-GLES31.functional.state_query.shader.sampler_type = SKIP
...@@ -108,9 +109,6 @@ ...@@ -108,9 +109,6 @@
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_color_texture_samples_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_color_texture_samples_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_depth_texture_samples_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_depth_texture_samples_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_integer_samples_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_integer_samples_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_relative_offset_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_bindings_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_vertex_attrib_stride_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_sample_mask_words_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_sample_mask_words_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_framebuffer_width_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_framebuffer_width_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_framebuffer_height_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_framebuffer_height_* = FAIL
...@@ -1360,7 +1358,6 @@ ...@@ -1360,7 +1358,6 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.texture_2d_multisample.* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.texture_2d_multisample.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.partial_query.num_sample_counts = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.partial_query.num_sample_counts = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.partial_query.samples = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.internal_format.partial_query.samples = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.vertex_attribute_binding.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.program_separable_get_programiv = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.program_separable_get_programiv = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.compute_work_group_size_get_programiv = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.compute_work_group_size_get_programiv = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.active_atomic_counter_buffers_get_programiv = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.active_atomic_counter_buffers_get_programiv = FAIL
...@@ -1370,7 +1367,6 @@ ...@@ -1370,7 +1367,6 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_linked_input_type = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_linked_input_type = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_linked_output_type = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_linked_output_type = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_shader_invocations = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.geometry_shader_invocations = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.vertex_attribute_binding.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.separate_shader.* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.separate_shader.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.uniform_location.nested_array.* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.uniform_location.nested_array.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.error_filters.case_11 = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.error_filters.case_11 = FAIL
...@@ -1408,8 +1404,6 @@ ...@@ -1408,8 +1404,6 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.texture.compressedtexsubimage3d = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.texture.compressedtexsubimage3d = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.texture.compressedtexsubimage3d_invalid_buffer_target = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.texture.compressedtexsubimage3d_invalid_buffer_target = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.shader.compile_compute_shader = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.shader.compile_compute_shader = SKIP
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.vertex_attrib_format = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.vertex_attrib_i_format = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.draw_range_elements = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.draw_range_elements = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.draw_range_elements_incomplete_primitive = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.vertex_array.draw_range_elements_incomplete_primitive = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.shader_directive.primitive_bounding_box = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.shader_directive.primitive_bounding_box = FAIL
......
...@@ -642,7 +642,7 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3 ...@@ -642,7 +642,7 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3
static_cast<GLsizeiptr>(quadVertices.size() * sizeof(quadVertices[0])); static_cast<GLsizeiptr>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer); glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer); glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, nullptr, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, quadVerticesSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data()); glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position"); GLint positionLocation = glGetAttribLocation(mProgram, "position");
...@@ -684,6 +684,17 @@ TEST_P(VertexAttributeTestES31, MaxVertexAttribStride) ...@@ -684,6 +684,17 @@ TEST_P(VertexAttributeTestES31, MaxVertexAttribStride)
EXPECT_GE(maxStride, 2048); EXPECT_GE(maxStride, 2048);
} }
// Verify that GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET is no less than the minimum required value
// (2047) in ES3.1.
TEST_P(VertexAttributeTestES31, MaxVertexAttribRelativeOffset)
{
GLint maxRelativeOffset;
glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
ASSERT_GL_NO_ERROR();
EXPECT_GE(maxRelativeOffset, 2047);
}
// Verify using MAX_VERTEX_ATTRIB_STRIDE as stride doesn't mess up the draw. // Verify using MAX_VERTEX_ATTRIB_STRIDE as stride doesn't mess up the draw.
// Use default value if the value of MAX_VERTEX_ATTRIB_STRIDE is too large for this test. // Use default value if the value of MAX_VERTEX_ATTRIB_STRIDE is too large for this test.
TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride) TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride)
......
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