Commit 6a5d98c4 by Jiawei Shao Committed by Commit Bot

ES31: Implement Vertex Attrib Binding on D3D11

This patch implements Vertex Attrib Binding on D3D11 and enables all the test cases related to Vertex Attrib Binding on D3D11 back-ends. On D3D11 back-ends the information in both GL vertex attributes and bindings should be updated together. When a binding is dirty, we need to find out and update all the attributes that are using this binding. To speed up this process, this patch adds a map from each binding to all the attrib indexes that are using this binding. This map may be updated when VertexAttribBinding is implicitly or explicitly called. With this map we can easily get all the attributes that should be updated with the current dirty binding. This patch also removes some unused variables in VertexArray11.cpp. BUG=angleproject:2700 TEST=dEQP-GLES31.functional.vertex_attribute_binding.* angle_end2end_tests Change-Id: I9a28ec357fd3aba835812cecc410cfa4e3734f0c Reviewed-on: https://chromium-review.googlesource.com/1048980 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent c16f518e
...@@ -24,6 +24,7 @@ VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings) ...@@ -24,6 +24,7 @@ VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings)
for (size_t i = 0; i < maxAttribs; i++) for (size_t i = 0; i < maxAttribs; i++)
{ {
mVertexAttributes.emplace_back(static_cast<GLuint>(i)); mVertexAttributes.emplace_back(static_cast<GLuint>(i));
mBindingToAttributeMasks[i].set(i);
} }
} }
...@@ -41,6 +42,31 @@ bool VertexArrayState::hasEnabledNullPointerClientArray() const ...@@ -41,6 +42,31 @@ bool VertexArrayState::hasEnabledNullPointerClientArray() const
return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any(); return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any();
} }
AttributesMask VertexArrayState::getBindingToAttributeMasks(GLuint bindingIndex) const
{
ASSERT(bindingIndex < MAX_VERTEX_ATTRIB_BINDINGS);
return mBindingToAttributeMasks[bindingIndex];
}
// Set an attribute using a new binding.
void VertexArrayState::setAttribBinding(size_t attribIndex, GLuint newBindingIndex)
{
ASSERT(attribIndex < MAX_VERTEX_ATTRIBS && newBindingIndex < MAX_VERTEX_ATTRIB_BINDINGS);
// Update the binding-attribute map.
const GLuint oldBindingIndex = mVertexAttributes[attribIndex].bindingIndex;
ASSERT(oldBindingIndex != newBindingIndex);
ASSERT(mBindingToAttributeMasks[oldBindingIndex].test(attribIndex) &&
!mBindingToAttributeMasks[newBindingIndex].test(attribIndex));
mBindingToAttributeMasks[oldBindingIndex].reset(attribIndex);
mBindingToAttributeMasks[newBindingIndex].set(attribIndex);
// Set the attribute using the new binding.
mVertexAttributes[attribIndex].bindingIndex = newBindingIndex;
}
// VertexArray implementation. // VertexArray implementation.
VertexArray::VertexArray(rx::GLImplFactory *factory, VertexArray::VertexArray(rx::GLImplFactory *factory,
GLuint id, GLuint id,
...@@ -185,11 +211,11 @@ void VertexArray::setVertexAttribBinding(const Context *context, ...@@ -185,11 +211,11 @@ void VertexArray::setVertexAttribBinding(const Context *context,
{ {
// In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable. // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
ASSERT(context->getClientVersion() >= ES_3_1); ASSERT(context->getClientVersion() >= ES_3_1);
mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex;
mState.setAttribBinding(attribIndex, bindingIndex);
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
} }
mState.mVertexAttributes[attribIndex].bindingIndex = static_cast<GLuint>(bindingIndex);
} }
void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
......
...@@ -63,12 +63,17 @@ class VertexArrayState final : angle::NonCopyable ...@@ -63,12 +63,17 @@ class VertexArrayState final : angle::NonCopyable
return mVertexAttributes[attribIndex].bindingIndex; return mVertexAttributes[attribIndex].bindingIndex;
} }
void setAttribBinding(size_t attribIndex, GLuint newBindingIndex);
// Combines mClientMemoryAttribsMask with mEnabledAttributesMask. // Combines mClientMemoryAttribsMask with mEnabledAttributesMask.
gl::AttributesMask getEnabledClientMemoryAttribsMask() const; gl::AttributesMask getEnabledClientMemoryAttribsMask() const;
// Extra validation performed on the Vertex Array. // Extra validation performed on the Vertex Array.
bool hasEnabledNullPointerClientArray() const; bool hasEnabledNullPointerClientArray() const;
// Get all the attributes in an AttributesMask that are using the given binding.
AttributesMask getBindingToAttributeMasks(GLuint bindingIndex) const;
private: private:
friend class VertexArray; friend class VertexArray;
std::string mLabel; std::string mLabel;
...@@ -84,6 +89,11 @@ class VertexArrayState final : angle::NonCopyable ...@@ -84,6 +89,11 @@ class VertexArrayState final : angle::NonCopyable
// attribs. // attribs.
gl::AttributesMask mClientMemoryAttribsMask; gl::AttributesMask mClientMemoryAttribsMask;
gl::AttributesMask mNullPointerClientMemoryAttribsMask; gl::AttributesMask mNullPointerClientMemoryAttribsMask;
// Records the mappings from each binding to all of the attributes that are using that binding.
// It is used to label all the relevant attributes dirty when we are updating a dirty binding in
// VertexArray11::syncStates().
std::array<AttributesMask, MAX_VERTEX_ATTRIB_BINDINGS> mBindingToAttributeMasks;
}; };
class VertexArray final : public angle::ObserverInterface, public LabeledObject class VertexArray final : public angle::ObserverInterface, public LabeledObject
......
...@@ -37,18 +37,25 @@ void VertexArray11::destroy(const gl::Context *context) ...@@ -37,18 +37,25 @@ void VertexArray11::destroy(const gl::Context *context)
{ {
} }
#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \ // As VertexAttribPointer can modify both attribute and binding, we should also set other attributes
case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \ // that are also using this binding dirty.
ASSERT(INDEX == mState.getBindingIndexFromAttribIndex(INDEX)); \ #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \
updateVertexAttribStorage(stateManager, dirtyBit, INDEX); \ case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
invalidateVertexBuffer = true; \ if (attribBits[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \
{ \
attributesToUpdate |= mState.getBindingToAttributeMasks(INDEX); \
} \
else \
{ \
attributesToUpdate.set(INDEX); \
} \
invalidateVertexBuffer = true; \
break; break;
#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \ #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
ASSERT(INDEX == mState.getBindingIndexFromAttribIndex(INDEX)); \ attributesToUpdate |= mState.getBindingToAttributeMasks(INDEX); \
updateVertexAttribStorage(stateManager, dirtyBit, INDEX); \ invalidateVertexBuffer = true; \
invalidateVertexBuffer = true; \
break; break;
#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \ #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \
...@@ -76,6 +83,8 @@ gl::Error VertexArray11::syncState(const gl::Context *context, ...@@ -76,6 +83,8 @@ gl::Error VertexArray11::syncState(const gl::Context *context,
bool invalidateVertexBuffer = false; bool invalidateVertexBuffer = false;
gl::AttributesMask attributesToUpdate;
// Make sure we trigger re-translation for static index or vertex data. // Make sure we trigger re-translation for static index or vertex data.
for (size_t dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyBits)
{ {
...@@ -101,6 +110,11 @@ gl::Error VertexArray11::syncState(const gl::Context *context, ...@@ -101,6 +110,11 @@ gl::Error VertexArray11::syncState(const gl::Context *context,
} }
} }
for (size_t attribIndex : attributesToUpdate)
{
updateVertexAttribStorage(stateManager, attribIndex);
}
if (invalidateVertexBuffer) if (invalidateVertexBuffer)
{ {
// TODO(jmadill): Individual attribute invalidation. // TODO(jmadill): Individual attribute invalidation.
...@@ -188,16 +202,10 @@ gl::Error VertexArray11::updateElementArrayStorage(const gl::Context *context, ...@@ -188,16 +202,10 @@ gl::Error VertexArray11::updateElementArrayStorage(const gl::Context *context,
ClassifyIndexStorage(context->getGLState(), mState.getElementArrayBuffer().get(), ClassifyIndexStorage(context->getGLState(), mState.getElementArrayBuffer().get(),
drawCallParams.type(), mCachedDestinationIndexType, offset); drawCallParams.type(), mCachedDestinationIndexType, offset);
// Mark non-static buffers as irrelevant.
bool isStatic = (mCurrentElementArrayStorage == IndexStorageType::Static);
mRelevantDirtyBitsMask.set(gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA, isStatic);
return gl::NoError(); return gl::NoError();
} }
void VertexArray11::updateVertexAttribStorage(StateManager11 *stateManager, void VertexArray11::updateVertexAttribStorage(StateManager11 *stateManager, size_t attribIndex)
size_t dirtyBit,
size_t attribIndex)
{ {
const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex); const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
const gl::VertexBinding &binding = mState.getBindingFromAttribIndex(attribIndex); const gl::VertexBinding &binding = mState.getBindingFromAttribIndex(attribIndex);
...@@ -213,10 +221,6 @@ void VertexArray11::updateVertexAttribStorage(StateManager11 *stateManager, ...@@ -213,10 +221,6 @@ void VertexArray11::updateVertexAttribStorage(StateManager11 *stateManager,
mAttributeStorageTypes[attribIndex] = newStorageType; mAttributeStorageTypes[attribIndex] = newStorageType;
mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC); mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC);
// Mark non-static buffers as irrelevant.
size_t bufferDataDirtyBit = (gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + attribIndex);
mRelevantDirtyBitsMask.set(bufferDataDirtyBit, newStorageType == VertexStorageType::STATIC);
if (newStorageType == VertexStorageType::CURRENT_VALUE) if (newStorageType == VertexStorageType::CURRENT_VALUE)
{ {
stateManager->invalidateCurrentValueAttrib(attribIndex); stateManager->invalidateCurrentValueAttrib(attribIndex);
......
...@@ -60,7 +60,6 @@ class VertexArray11 : public VertexArrayImpl ...@@ -60,7 +60,6 @@ class VertexArray11 : public VertexArrayImpl
private: private:
void updateVertexAttribStorage(StateManager11 *stateManager, void updateVertexAttribStorage(StateManager11 *stateManager,
size_t dirtyBit,
size_t attribIndex); size_t attribIndex);
gl::Error updateDirtyAttribs(const gl::Context *context, gl::Error updateDirtyAttribs(const gl::Context *context,
const gl::AttributesMask &activeDirtyAttribs); const gl::AttributesMask &activeDirtyAttribs);
...@@ -75,9 +74,6 @@ class VertexArray11 : public VertexArrayImpl ...@@ -75,9 +74,6 @@ class VertexArray11 : public VertexArrayImpl
// The mask of attributes marked as dynamic. // The mask of attributes marked as dynamic.
gl::AttributesMask mDynamicAttribsMask; gl::AttributesMask mDynamicAttribsMask;
// Mask applied to dirty bits on syncState. If a bit is on, it is relevant.
gl::VertexArray::DirtyBits mRelevantDirtyBitsMask;
// A set of attributes we know are dirty, and need to be re-translated. // A set of attributes we know are dirty, and need to be re-translated.
gl::AttributesMask mAttribsToTranslate; gl::AttributesMask mAttribsToTranslate;
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
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 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.texture.gather.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.texture.gather.* = SKIP
// TODO(xinghua.cao@intel.com): FAIL expectation instead of SKIP should be sufficient for OpenGL, but the // TODO(xinghua.cao@intel.com): FAIL expectation instead of SKIP should be sufficient for OpenGL, but the
......
...@@ -533,6 +533,4 @@ ANGLE_INSTANTIATE_TEST(InstancingTestNo9_3, ES2_D3D9(), ES2_D3D11()); ...@@ -533,6 +533,4 @@ ANGLE_INSTANTIATE_TEST(InstancingTestNo9_3, ES2_D3D9(), ES2_D3D11());
ANGLE_INSTANTIATE_TEST(InstancingTestPoints, ES2_D3D11(), ES2_D3D11_FL9_3()); ANGLE_INSTANTIATE_TEST(InstancingTestPoints, ES2_D3D11(), ES2_D3D11_FL9_3());
// TODO(jiawei.shao@intel.com): Add D3D11 when Vertex Attrib Binding is supported on D3D11 ANGLE_INSTANTIATE_TEST(InstancingTestES31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
// back-ends.
ANGLE_INSTANTIATE_TEST(InstancingTestES31, ES31_OPENGL(), ES31_OPENGLES());
...@@ -1011,29 +1011,29 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3 ...@@ -1011,29 +1011,29 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3
glDeleteVertexArrays(1, &mVAO); glDeleteVertexArrays(1, &mVAO);
} }
void drawArraysWithStrideAndOffset(GLint stride, GLsizeiptr offset) void drawArraysWithStrideAndRelativeOffset(GLint stride, GLuint relativeOffset)
{ {
initTest(); initTest();
GLint floatStride = stride ? (stride / kFloatStride) : 1; GLint floatStride = std::max(stride / kFloatStride, 1);
GLsizeiptr floatOffset = offset / kFloatStride; GLuint floatRelativeOffset = relativeOffset / kFloatStride;
size_t floatCount = static_cast<size_t>(floatOffset) + kVertexCount * floatStride; size_t floatCount = static_cast<size_t>(floatRelativeOffset) + kVertexCount * floatStride;
GLsizeiptr inputSize = static_cast<GLsizeiptr>(floatCount) * kFloatStride; GLsizeiptr inputSize = static_cast<GLsizeiptr>(floatCount) * kFloatStride;
std::vector<GLfloat> inputData(floatCount); std::vector<GLfloat> inputData(floatCount);
for (size_t count = 0; count < kVertexCount; ++count) for (size_t count = 0; count < kVertexCount; ++count)
{ {
inputData[floatOffset + count * floatStride] = static_cast<GLfloat>(count); inputData[floatRelativeOffset + count * floatStride] = static_cast<GLfloat>(count);
} }
// Ensure inputSize, inputStride and inputOffset are multiples of TypeStride(GL_FLOAT). // Ensure inputSize, inputStride and inputOffset are multiples of TypeStride(GL_FLOAT).
GLsizei inputStride = stride ? floatStride * kFloatStride : 0; GLsizei inputStride = floatStride * kFloatStride;
GLsizeiptr inputOffset = floatOffset * kFloatStride; GLsizeiptr inputRelativeOffset = floatRelativeOffset * kFloatStride;
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, inputSize, nullptr, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, inputSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, inputSize, inputData.data()); glBufferSubData(GL_ARRAY_BUFFER, 0, inputSize, inputData.data());
glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, inputStride, glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, inputRelativeOffset);
reinterpret_cast<const void *>(inputOffset)); glBindVertexBuffer(mTestAttrib, mBuffer, 0, inputStride);
glEnableVertexAttribArray(mTestAttrib); glEnableVertexAttribArray(mTestAttrib);
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
...@@ -1042,13 +1042,54 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3 ...@@ -1042,13 +1042,54 @@ class VertexAttributeTestES31 : public VertexAttributeTestES3
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
void initOnlyUpdateBindingTest(GLint bindingToUpdate)
{
initTest();
constexpr GLuint kTestFloatOffset1 = kVertexCount;
std::array<GLfloat, kTestFloatOffset1 + kVertexCount> inputData1 = {};
for (size_t count = 0; count < kVertexCount; ++count)
{
GLfloat value = static_cast<GLfloat>(count);
inputData1[kTestFloatOffset1 + count] = value;
}
GLBuffer testBuffer1;
glBindBuffer(GL_ARRAY_BUFFER, testBuffer1);
glBufferData(GL_ARRAY_BUFFER, inputData1.size() * kFloatStride, inputData1.data(),
GL_STATIC_DRAW);
ASSERT_NE(bindingToUpdate, mTestAttrib);
ASSERT_NE(bindingToUpdate, mExpectedAttrib);
// Set mTestAttrib using the binding bindingToUpdate.
glVertexAttribFormat(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0);
glBindVertexBuffer(bindingToUpdate, testBuffer1, kTestFloatOffset1 * kFloatStride,
kFloatStride);
glVertexAttribBinding(mTestAttrib, bindingToUpdate);
glEnableVertexAttribArray(mTestAttrib);
// In the first draw the current VAO states are set to driver.
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
// We need the second draw to ensure all VAO dirty bits are reset.
// e.g. On D3D11 back-ends, Buffer11::resize is called in the first draw, where the related
// binding is set to dirty again.
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
GLuint mVAO; GLuint mVAO;
GLuint mExpectedBuffer; GLuint mExpectedBuffer;
const GLsizei kFloatStride = TypeStride(GL_FLOAT); const GLsizei kFloatStride = TypeStride(GL_FLOAT);
// Set the maximum value for stride if the stride is too large. // Set the maximum value for stride and relativeOffset in case they are too large.
static constexpr GLint MAX_STRIDE_FOR_TEST = 4095; const GLint MAX_STRIDE_FOR_TEST = 4095;
const GLint MAX_RELATIVE_OFFSET_FOR_TEST = 4095;
}; };
// Verify that MAX_VERTEX_ATTRIB_STRIDE is no less than the minimum required value (2048) in ES3.1. // Verify that MAX_VERTEX_ATTRIB_STRIDE is no less than the minimum required value (2048) in ES3.1.
...@@ -1080,20 +1121,24 @@ TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride) ...@@ -1080,20 +1121,24 @@ TEST_P(VertexAttributeTestES31, DrawArraysWithLargeStride)
glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride); glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
GLint largeStride = (maxStride < MAX_STRIDE_FOR_TEST) ? maxStride : MAX_STRIDE_FOR_TEST; GLint largeStride = std::min(maxStride, MAX_STRIDE_FOR_TEST);
drawArraysWithStrideAndOffset(largeStride, 0); drawArraysWithStrideAndRelativeOffset(largeStride, 0);
} }
// TODO(jiawei.shao@intel.com): Merge it into VertexAttributeTestES31 when Vertex Attrib // Verify using MAX_VERTEX_ATTRIB_RELATIVE_OFFSET as relativeOffset doesn't mess up the draw.
// Binding is supported on D3D11 back-ends. // Use default value if the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSSET is too large for this test.
class VertexAttributeTestES31_OpenGL : public VertexAttributeTestES31 TEST_P(VertexAttributeTestES31, DrawArraysWithLargeRelativeOffset)
{ {
protected: GLint maxRelativeOffset;
VertexAttributeTestES31_OpenGL() {} glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxRelativeOffset);
}; ASSERT_GL_NO_ERROR();
GLint largeRelativeOffset = std::min(maxRelativeOffset, MAX_RELATIVE_OFFSET_FOR_TEST);
drawArraysWithStrideAndRelativeOffset(0, largeRelativeOffset);
}
// Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw. // Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribBindingAfterVertexAttribPointer) TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer)
{ {
initTest(); initTest();
...@@ -1143,7 +1188,7 @@ TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribBindingAfterVertexAttribPoint ...@@ -1143,7 +1188,7 @@ TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribBindingAfterVertexAttribPoint
} }
// Verify that using VertexAttribFormat after VertexAttribPointer won't mess up the draw. // Verify that using VertexAttribFormat after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribFormatAfterVertexAttribPointer) TEST_P(VertexAttributeTestES31, ChangeAttribFormatAfterVertexAttribPointer)
{ {
initTest(); initTest();
...@@ -1171,6 +1216,81 @@ TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribFormatAfterVertexAttribPointe ...@@ -1171,6 +1216,81 @@ TEST_P(VertexAttributeTestES31_OpenGL, ChangeAttribFormatAfterVertexAttribPointe
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByBindVertexBuffer)
{
// Default binding index for test
constexpr GLint kTestBinding = 10;
initOnlyUpdateBindingTest(kTestBinding);
constexpr GLuint kTestFloatOffset2 = kVertexCount * 2;
std::array<GLfloat, kVertexCount> expectedData2 = {};
std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
for (size_t count = 0; count < kVertexCount; ++count)
{
GLfloat value2 = static_cast<GLfloat>(count) * 2;
expectedData2[count] = value2;
inputData2[count + kTestFloatOffset2] = value2;
}
// Set another set of data for mExpectedAttrib.
GLBuffer expectedBuffer2;
glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
GLBuffer testBuffer2;
glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
GL_STATIC_DRAW);
// Only update the binding kTestBinding in the second draw by BindVertexBuffer.
glBindVertexBuffer(kTestBinding, testBuffer2, kTestFloatOffset2 * kFloatStride, kFloatStride);
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
// Verify that only updating a binding without updating the bound format won't mess up this draw.
TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByVertexAttribPointer)
{
// Default binding index for test
constexpr GLint kTestBinding = 10;
initOnlyUpdateBindingTest(kTestBinding);
constexpr GLuint kTestFloatOffset2 = kVertexCount * 3;
std::array<GLfloat, kVertexCount> expectedData2 = {};
std::array<GLfloat, kTestFloatOffset2 + kVertexCount> inputData2 = {};
for (size_t count = 0; count < kVertexCount; ++count)
{
GLfloat value2 = static_cast<GLfloat>(count) * 3;
expectedData2[count] = value2;
inputData2[count + kTestFloatOffset2] = value2;
}
// Set another set of data for mExpectedAttrib.
GLBuffer expectedBuffer2;
glBindBuffer(GL_ARRAY_BUFFER, expectedBuffer2);
glBufferData(GL_ARRAY_BUFFER, expectedData2.size() * kFloatStride, expectedData2.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
GLBuffer testBuffer2;
glBindBuffer(GL_ARRAY_BUFFER, testBuffer2);
glBufferData(GL_ARRAY_BUFFER, inputData2.size() * kFloatStride, inputData2.data(),
GL_STATIC_DRAW);
// Only update the binding kTestBinding in the second draw by VertexAttribPointer.
glVertexAttribPointer(kTestBinding, 1, GL_FLOAT, GL_FALSE, 0,
reinterpret_cast<const void *>(kTestFloatOffset2 * kFloatStride));
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
class VertexAttributeCachingTest : public VertexAttributeTest class VertexAttributeCachingTest : public VertexAttributeTest
{ {
protected: protected:
...@@ -1521,8 +1641,6 @@ ANGLE_INSTANTIATE_TEST(VertexAttributeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OP ...@@ -1521,8 +1641,6 @@ ANGLE_INSTANTIATE_TEST(VertexAttributeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OP
ANGLE_INSTANTIATE_TEST(VertexAttributeTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES()); ANGLE_INSTANTIATE_TEST(VertexAttributeTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(VertexAttributeTestES31_OpenGL, ES31_OPENGL(), ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(VertexAttributeCachingTest, ANGLE_INSTANTIATE_TEST(VertexAttributeCachingTest,
ES2_D3D9(), ES2_D3D9(),
ES2_D3D11(), ES2_D3D11(),
......
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