BufferDataTest: Add more coherent buffer storage tests.

Add UniformBufferMapped and VertexBufferMapped in BufferStorageTestES3.
Add a test that writes to a mapped coherent bufferstorage from multiple
threads.

Test: angle_end2end_tests --gtest_filter="BufferStorageTestES3.*"
Bug: angleproject:5857
Change-Id: I434c2462fb7217ab77667a6ec038f21835beb0b7
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3275764
Reviewed-by: Cody Northrop <cnorthrop@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
This commit is contained in:
Lubosz Sarnecki 2021-11-05 13:14:35 +01:00 коммит произвёл Angle LUCI CQ
Родитель 9df048efc2
Коммит c56f29a2a5
1 изменённых файлов: 317 добавлений и 0 удалений

Просмотреть файл

@ -10,6 +10,7 @@
#include "util/random_utils.h" #include "util/random_utils.h"
#include <stdint.h> #include <stdint.h>
#include <thread>
using namespace angle; using namespace angle;
@ -1218,11 +1219,35 @@ TEST_P(BufferStorageTestES3, DrawElementsElementArrayBufferMapped)
mappedPtr[5] = 3; mappedPtr[5] = 3;
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
} }
// Test that maps a coherent buffer storage and does not call glUnmapBuffer.
TEST_P(BufferStorageTestES3, NoUnmap)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
GLsizei size = sizeof(GLfloat) * 128;
GLBuffer buffer;
glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
glBufferStorageEXT(GL_ARRAY_BUFFER, size, nullptr,
GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT |
GL_MAP_COHERENT_BIT_EXT);
GLshort *mappedPtr = (GLshort *)glMapBufferRange(
GL_ARRAY_BUFFER, 0, size,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
ASSERT_NE(nullptr, mappedPtr);
ASSERT_GL_NO_ERROR();
}
// Test that we are able to perform glTex*D calls while a pixel unpack buffer is bound // Test that we are able to perform glTex*D calls while a pixel unpack buffer is bound
// and persistently mapped. // and persistently mapped.
TEST_P(BufferStorageTestES3, TexImage2DPixelUnpackBufferMappedPersistently) TEST_P(BufferStorageTestES3, TexImage2DPixelUnpackBufferMappedPersistently)
@ -1294,6 +1319,295 @@ TEST_P(BufferStorageTestES3, StorageBufferSubDataMapped)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Verify that persistently mapped coherent buffers can be used as uniform buffers,
// and written to by using the pointer from glMapBufferRange.
TEST_P(BufferStorageTestES3, UniformBufferMapped)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
const char *mkFS = R"(#version 300 es
precision highp float;
uniform uni { vec4 color; };
out vec4 fragColor;
void main()
{
fragColor = color;
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), mkFS);
ASSERT_NE(program, 0u);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
ASSERT_NE(uniformBufferIndex, -1);
GLBuffer uniformBuffer;
ASSERT_GL_NO_ERROR();
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer.get());
glBufferStorageEXT(GL_UNIFORM_BUFFER, sizeof(float) * 4, nullptr,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
float *mapPtr = static_cast<float *>(
glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4,
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_PERSISTENT_BIT_EXT |
GL_MAP_COHERENT_BIT_EXT));
ASSERT_NE(mapPtr, nullptr);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniformBuffer.get());
glUniformBlockBinding(program, uniformBufferIndex, 0);
mapPtr[0] = 0.5f;
mapPtr[1] = 0.75f;
mapPtr[2] = 0.25f;
mapPtr[3] = 1.0f;
drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
glUnmapBuffer(GL_UNIFORM_BUFFER);
glDeleteProgram(program);
ASSERT_GL_NO_ERROR();
}
// Verify that persistently mapped coherent buffers can be used as vertex array buffers,
// and written to by using the pointer from glMapBufferRange.
TEST_P(BufferStorageTestES3, VertexBufferMapped)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
ASSERT_NE(program, 0u);
glUseProgram(program);
auto quadVertices = GetQuadVertices();
size_t bufferSize = sizeof(GLfloat) * quadVertices.size() * 3;
GLBuffer positionBuffer;
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer.get());
glBufferStorageEXT(GL_ARRAY_BUFFER, bufferSize, nullptr,
GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT |
GL_MAP_COHERENT_BIT_EXT);
GLint positionLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
ASSERT_NE(-1, positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
void *mappedPtr =
glMapBufferRange(GL_ARRAY_BUFFER, 0, bufferSize,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
ASSERT_NE(nullptr, mappedPtr);
memcpy(mappedPtr, reinterpret_cast<void *>(quadVertices.data()), bufferSize);
glDrawArrays(GL_TRIANGLES, 0, quadVertices.size());
EXPECT_PIXEL_COLOR_EQ(8, 8, GLColor::red);
glUnmapBuffer(GL_ARRAY_BUFFER);
glDeleteProgram(program);
EXPECT_GL_NO_ERROR();
}
class BufferStorageTestES3Threaded : public ANGLETest
{
protected:
BufferStorageTestES3Threaded()
{
setWindowWidth(16);
setWindowHeight(16);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
mProgram = 0;
}
void testSetUp() override
{
constexpr char kVS[] = R"(#version 300 es
in vec4 position;
in vec4 color;
out vec4 out_color;
void main()
{
out_color = color;
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
in vec4 out_color;
out vec4 fragColor;
void main()
{
fragColor = vec4(out_color);
})";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(mProgram, 0U);
glClearColor(0, 0, 0, 0);
glClearDepthf(0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
ASSERT_GL_NO_ERROR();
}
void testTearDown() override { glDeleteProgram(mProgram); }
void updateColors(int i, int offset, const GLColor &color)
{
Vector4 colorVec = color.toNormalizedVector();
mMappedPtr[offset + i * 4 + 0] = colorVec.x();
mMappedPtr[offset + i * 4 + 1] = colorVec.y();
mMappedPtr[offset + i * 4 + 2] = colorVec.z();
mMappedPtr[offset + i * 4 + 3] = colorVec.w();
}
void updateThreadedAndDraw(int offset, const GLColor &color)
{
std::mutex mutex;
std::vector<std::thread> threads(4);
for (size_t i = 0; i < 4; i++)
{
threads[i] = std::thread([&, i]() {
std::lock_guard<decltype(mutex)> lock(mutex);
updateColors(i, offset, color);
});
}
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
for (std::thread &thread : threads)
{
thread.join();
}
}
GLuint mProgram;
GLfloat *mMappedPtr = nullptr;
};
// Test using a large buffer storage for a color vertex array buffer, which is
// off set every iteration step via glVertexAttribPointer.
// Write to the buffer storage map pointer from multiple threads for the next iteration,
// while drawing the current one.
TEST_P(BufferStorageTestES3Threaded, VertexBuffer)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 ||
!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
auto vertices = GetIndexedQuadVertices();
// Set up position buffer
GLBuffer positionBuffer;
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer.get());
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
GL_STATIC_DRAW);
GLint positionLoc = glGetAttribLocation(mProgram, "position");
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(positionLoc);
// Set up color buffer
GLBuffer colorBuffer;
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer.get());
// Let's create a big buffer which fills 10 pages at pagesize 4096
GLint bufferSize = sizeof(GLfloat) * 1024 * 10;
GLint offsetFloats = 0;
glBufferStorageEXT(GL_ARRAY_BUFFER, bufferSize, nullptr,
GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT |
GL_MAP_COHERENT_BIT_EXT);
GLint colorLoc = glGetAttribLocation(mProgram, "color");
glEnableVertexAttribArray(colorLoc);
auto indices = GetQuadIndices();
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
glUseProgram(mProgram);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
mMappedPtr = (GLfloat *)glMapBufferRange(
GL_ARRAY_BUFFER, 0, bufferSize,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
ASSERT_NE(nullptr, mMappedPtr);
ASSERT_GL_NO_ERROR();
// Initial color
for (int i = 0; i < 4; i++)
{
updateColors(i, offsetFloats, GLColor::black);
}
std::vector<GLColor> colors = {GLColor::red, GLColor::green, GLColor::blue};
// 4 vertices, 4 floats
GLint contentSize = 4 * 4;
// Update and draw last
int i = 0;
while (bufferSize > (int)((offsetFloats + contentSize) * sizeof(GLfloat)))
{
glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
reinterpret_cast<const GLvoid *>(offsetFloats * sizeof(GLfloat)));
offsetFloats += contentSize;
GLColor color = colors[i % colors.size()];
updateThreadedAndDraw(offsetFloats, color);
if (i > 0)
{
GLColor lastColor = colors[(i - 1) % colors.size()];
EXPECT_PIXEL_COLOR_EQ(0, 0, lastColor);
}
ASSERT_GL_NO_ERROR();
i++;
}
// Last draw
glVertexAttribPointer(colorLoc, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
reinterpret_cast<const GLvoid *>(offsetFloats * sizeof(GLfloat)));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glUnmapBuffer(GL_ARRAY_BUFFER);
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest); ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferDataTestES3); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferDataTestES3);
@ -1305,6 +1619,9 @@ ANGLE_INSTANTIATE_TEST_ES3(BufferStorageTestES3);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IndexedBufferCopyTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IndexedBufferCopyTest);
ANGLE_INSTANTIATE_TEST_ES3(IndexedBufferCopyTest); ANGLE_INSTANTIATE_TEST_ES3(IndexedBufferCopyTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferStorageTestES3Threaded);
ANGLE_INSTANTIATE_TEST_ES3(BufferStorageTestES3Threaded);
#ifdef _WIN64 #ifdef _WIN64
// Test a bug where an integer overflow bug could trigger a crash in D3D. // Test a bug where an integer overflow bug could trigger a crash in D3D.