Commit 1c654d54 by Le Hoang Quyen Committed by Commit Bot

Metal: Fix handling of vertex attrib offset not multiple of 4

Metal requires the vertex attribute offset to be multiples of 4, and its stride must not be less than attribute's size. This should fix the WebGL's test: conformance/attribs/gl-vertexattribpointer-offsets.html Bug: angleproject:4846 Bug: angleproject:2634 Change-Id: I0784a8ccaedd5e6c58a266243bfa94ba36e53e11 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2374829 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 5c56f228
......@@ -421,6 +421,8 @@ angle::Result VertexArrayMtl::syncDirtyAttrib(const gl::Context *glContext,
bool needConversion =
format.actualFormatId != format.intendedFormatId ||
(binding.getOffset() % format.actualAngleFormat().pixelBytes) != 0 ||
(binding.getOffset() % mtl::kVertexAttribBufferStrideAlignment) != 0 ||
(binding.getStride() < format.actualAngleFormat().pixelBytes) ||
(binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0;
if (needConversion)
......
......@@ -1264,6 +1264,309 @@ TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
EXPECT_GL_NO_ERROR();
}
// Verify that using an unaligned offset doesn't mess up the draw.
TEST_P(VertexAttributeTest, DrawArraysWithUnalignedBufferOffset)
{
// anglebug.com/4258
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
// anglebug.com/4163
ANGLE_SKIP_TEST_IF(IsD3D11() && IsNVIDIA() && IsWindows7());
// TODO(jmadill): Diagnose this failure.
ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
// TODO(geofflang): Figure out why this is broken on AMD OpenGL
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
// TODO(cnorthrop): Test this again on more recent drivers. http://anglebug.com/3951
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// TODO(https://anglebug.com/4269): Test is flaky on OpenGL and Metal on Mac NVIDIA.
ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
initBasicProgram();
glUseProgram(mProgram);
std::array<GLfloat, kVertexCount> inputData;
std::array<GLfloat, kVertexCount> expectedData;
InitTestData(inputData, expectedData);
auto quadVertices = GetQuadVertices();
GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// Unaligned buffer offset (3)
GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT) + 3;
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 3, dataSize - 3, inputData.data());
glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(3));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
// Verify that using an unaligned offset & GL_SHORT vertex attribute doesn't mess up the draw.
// In Metal backend, GL_SHORTx3 is coverted to GL_SHORTx4 if offset is unaligned.
TEST_P(VertexAttributeTest, DrawArraysWithUnalignedShortBufferOffset)
{
// anglebug.com/4258
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
// anglebug.com/4163
ANGLE_SKIP_TEST_IF(IsD3D11() && IsNVIDIA() && IsWindows7());
// TODO(jmadill): Diagnose this failure.
ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
// TODO(geofflang): Figure out why this is broken on AMD OpenGL
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
// TODO(cnorthrop): Test this again on more recent drivers. http://anglebug.com/3951
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// TODO(https://anglebug.com/4269): Test is flaky on OpenGL and Metal on Mac NVIDIA.
ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
initBasicProgram();
glUseProgram(mProgram);
// input data is GL_SHORTx3 (6 bytes) but stride=8
std::array<GLshort, 4 * kVertexCount> inputData;
std::array<GLfloat, 3 * kVertexCount> expectedData;
for (size_t i = 0; i < kVertexCount; ++i)
{
inputData[4 * i] = 3 * i;
inputData[4 * i + 1] = 3 * i + 1;
inputData[4 * i + 2] = 3 * i + 2;
expectedData[3 * i] = 3 * i;
expectedData[3 * i + 1] = 3 * i + 1;
expectedData[3 * i + 2] = 3 * i + 2;
}
auto quadVertices = GetQuadVertices();
GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// Unaligned buffer offset (8)
GLsizei dataSize = 3 * kVertexCount * TypeStride(GL_SHORT) + 8;
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 8, dataSize - 8, inputData.data());
glVertexAttribPointer(mTestAttrib, 3, GL_SHORT, GL_FALSE, /* stride */ 8,
reinterpret_cast<void *>(8));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
// Verify that using an aligned but non-multiples of 4 offset vertex attribute doesn't mess up the
// draw.
TEST_P(VertexAttributeTest, DrawArraysWithShortBufferOffsetNotMultipleOf4)
{
// anglebug.com/4258
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
// anglebug.com/4163
ANGLE_SKIP_TEST_IF(IsD3D11() && IsNVIDIA() && IsWindows7());
// TODO(jmadill): Diagnose this failure.
ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
// TODO(geofflang): Figure out why this is broken on AMD OpenGL
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
// TODO(cnorthrop): Test this again on more recent drivers. http://anglebug.com/3951
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// TODO(https://anglebug.com/4269): Test is flaky on OpenGL and Metal on Mac NVIDIA.
ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
initBasicProgram();
glUseProgram(mProgram);
// input data is GL_SHORTx3 (6 bytes) but stride=8
std::array<GLshort, 4 * kVertexCount> inputData;
std::array<GLfloat, 3 * kVertexCount> expectedData;
for (size_t i = 0; i < kVertexCount; ++i)
{
inputData[4 * i] = 3 * i;
inputData[4 * i + 1] = 3 * i + 1;
inputData[4 * i + 2] = 3 * i + 2;
expectedData[3 * i] = 3 * i;
expectedData[3 * i + 1] = 3 * i + 1;
expectedData[3 * i + 2] = 3 * i + 2;
}
auto quadVertices = GetQuadVertices();
GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// Aligned but not multiples of 4 buffer offset (18)
GLsizei dataSize = 4 * kVertexCount * TypeStride(GL_SHORT) + 8;
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 18, dataSize - 18, inputData.data());
glVertexAttribPointer(mTestAttrib, 3, GL_SHORT, GL_FALSE, /* stride */ 8,
reinterpret_cast<void *>(18));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 3, GL_FLOAT, GL_FALSE, 0, expectedData.data());
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
// Verify that using both aligned and unaligned offsets doesn't mess up the draw.
TEST_P(VertexAttributeTest, DrawArraysWithAlignedAndUnalignedBufferOffset)
{
// anglebug.com/4258
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && IsOSX());
// anglebug.com/4163
ANGLE_SKIP_TEST_IF(IsD3D11() && IsNVIDIA() && IsWindows7());
// TODO(jmadill): Diagnose this failure.
ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
// TODO(geofflang): Figure out why this is broken on AMD OpenGL
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
// TODO(cnorthrop): Test this again on more recent drivers. http://anglebug.com/3951
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// TODO(https://anglebug.com/4269): Test is flaky on OpenGL and Metal on Mac NVIDIA.
ANGLE_SKIP_TEST_IF(IsOSX() && IsNVIDIA());
initBasicProgram();
glUseProgram(mProgram);
std::array<GLfloat, kVertexCount> inputData;
std::array<GLfloat, kVertexCount> expectedData;
InitTestData(inputData, expectedData);
auto quadVertices = GetQuadVertices();
GLsizei quadVerticesSize = static_cast<GLsizei>(quadVertices.size() * sizeof(quadVertices[0]));
glGenBuffers(1, &mQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerticesSize + sizeof(Vector3), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, quadVerticesSize, quadVertices.data());
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
// ----------- Aligned buffer offset (4) -------------
GLsizei dataSize = kVertexCount * TypeStride(GL_FLOAT) + 4;
GLBuffer alignedBufer;
glBindBuffer(GL_ARRAY_BUFFER, alignedBufer);
glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 4, dataSize - 4, inputData.data());
glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(4));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
// ----------- Unaligned buffer offset (3) -------------
glClear(GL_COLOR_BUFFER_BIT);
dataSize = kVertexCount * TypeStride(GL_FLOAT) + 3;
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 3, dataSize - 3, inputData.data());
glVertexAttribPointer(mTestAttrib, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void *>(3));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(mExpectedAttrib, 1, GL_FLOAT, GL_FALSE, 0, expectedData.data());
glEnableVertexAttribArray(mExpectedAttrib);
// Vertex draw with no start vertex offset (second argument is zero).
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Draw offset by one vertex.
glDrawArrays(GL_TRIANGLES, 1, 6);
checkPixels();
EXPECT_GL_NO_ERROR();
}
// Verify that when we pass a client memory pointer to a disabled attribute the draw is still
// correct.
TEST_P(VertexAttributeTest, DrawArraysWithDisabledAttribute)
......
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