// // Copyright 2021 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // MemoryBarrierTest: // Ensure that implementation of glMemoryBarrier is correct both in terms of memory barriers // issued and potential reordering of commands. // // The barrier bits accepted by glMemoryBarrier are used for synchronization as such: // // VERTEX_ATTRIB_ARRAY_BARRIER_BIT: shader write -> vertex read // ELEMENT_ARRAY_BARRIER_BIT: shader write -> index read // UNIFORM_BARRIER_BIT: shader write -> uniform read // TEXTURE_FETCH_BARRIER_BIT: shader write -> texture sample // SHADER_IMAGE_ACCESS_BARRIER_BIT: shader write -> image access // any access -> image write // COMMAND_BARRIER_BIT: shader write -> indirect buffer read // PIXEL_BUFFER_BARRIER_BIT: shader write -> pbo access // TEXTURE_UPDATE_BARRIER_BIT: shader write -> texture data upload // BUFFER_UPDATE_BARRIER_BIT: shader write -> buffer data upload/map // FRAMEBUFFER_BARRIER_BIT: shader write -> access through framebuffer // TRANSFORM_FEEDBACK_BARRIER_BIT: shader write -> transform feedback write // ATOMIC_COUNTER_BARRIER_BIT: shader write -> atomic counter access // SHADER_STORAGE_BARRIER_BIT: shader write -> buffer access // any access -> buffer write // // In summary, every bit defines a memory barrier for some access after a shader write. // Additionally, SHADER_IMAGE_ACCESS_BARRIER_BIT and SHADER_STORAGE_BARRIER_BIT bits are used to // define a memory barrier for shader writes after other accesses. #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" #include "util/random_utils.h" using namespace angle; namespace { enum class ShaderWritePipeline { Graphics, Compute, }; enum class WriteResource { Image, ImageBuffer, Buffer, }; enum class NoopOp { None, Draw, Dispatch, }; // Variations corresponding to enums above. using MemoryBarrierVariationsTestParams = std::tuple; void ParseMemoryBarrierVariationsTestParams(const MemoryBarrierVariationsTestParams ¶ms, ShaderWritePipeline *writePipelineOut, WriteResource *writeResourceOut, NoopOp *preBarrierOpOut, NoopOp *postBarrierOpOut) { *writePipelineOut = std::get<1>(params); *writeResourceOut = std::get<2>(params); *preBarrierOpOut = std::get<3>(params); *postBarrierOpOut = std::get<4>(params); } std::string MemoryBarrierVariationsTestPrint( const ::testing::TestParamInfo ¶msInfo) { const MemoryBarrierVariationsTestParams ¶ms = paramsInfo.param; std::ostringstream out; out << std::get<0>(params); ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(params, &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); out << "_"; if (writePipeline == ShaderWritePipeline::Graphics) { out << "_graphics"; } else { out << "_compute"; } switch (writeResource) { case WriteResource::Image: out << "_image"; break; case WriteResource::Buffer: out << "_buffer"; break; case WriteResource::ImageBuffer: out << "_imagebuffer"; break; } if (preBarrierOp == NoopOp::Draw) { out << "_prebarrierNoopDraw"; } else if (preBarrierOp == NoopOp::Dispatch) { out << "_prebarrierNoopDispatch"; } if (postBarrierOp == NoopOp::Draw) { out << "_postbarrierNoopDraw"; } else if (postBarrierOp == NoopOp::Dispatch) { out << "_postbarrierNoopDispatch"; } return out.str(); } class MemoryBarrierTestBase { protected: bool hasExtensions(WriteResource writeResource); // Helper functions void createFramebuffer(GLuint color, GLuint fbo, GLColor initialColor); void createStorageBuffer(WriteResource writeResource, GLuint buffer, GLuint textureBuffer, size_t size, const void *initialData); void createStorageImage(WriteResource writeResource, GLuint bufferStorage, GLuint texture, const std::array &initialData); void createProgram(ShaderWritePipeline writePipeline, WriteResource writeResource, GLProgram *programOut); void createNoopGraphicsProgram(GLProgram *programOut); void createNoopComputeProgram(GLProgram *programOut); void createQuadVertexArray(GLuint positionBuffer); void setupVertexArray(ShaderWritePipeline writePipeline, GLuint program); void setUniformData(GLuint program, const std::array &data); void noopOp(NoopOp op); template void verifyBufferContents(const std::array &expected); void verifyImageContents(GLuint texture, const std::array &expected); template void verifyFramebufferAndBufferContents(ShaderWritePipeline writePipeline, const std::array &expected); void verifyFramebufferAndImageContents(ShaderWritePipeline writePipeline, WriteResource writeResource, GLuint texture, const std::array &expected); // Barrier bits affecting only buffers and imageBuffers void createVertexVerifyProgram(GLuint vertexBuffer, GLProgram *programOut); void vertexAttribArrayBitBufferWriteThenVertexRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void vertexAttribArrayBitVertexReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createIndexVerifyProgram(GLuint indexBuffer, GLProgram *programOut); void elementArrayBitBufferWriteThenIndexRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void elementArrayBitIndexReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createUBOVerifyProgram(GLuint buffer, GLProgram *programOut); void uniformBitBufferWriteThenUBORead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void uniformBitUBOReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createIndirectVerifyProgram(GLuint buffer, GLProgram *programOut); void commandBitBufferWriteThenIndirectRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void commandBitIndirectReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void pixelBufferBitBufferWriteThenPack(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void pixelBufferBitBufferWriteThenUnpack(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void pixelBufferBitPackThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void pixelBufferBitUnpackThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void bufferUpdateBitBufferWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void bufferUpdateBitCopyThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createXfbVerifyProgram(GLuint buffer, GLProgram *programOut); void transformFeedbackBitBufferWriteThenCapture(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void transformFeedbackBitCaptureThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createAtomicCounterVerifyProgram(GLuint buffer, GLProgram *programOut); void atomicCounterBitBufferWriteThenAtomic(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void atomicCounterBitAtomicThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createSsboVerifyProgram(WriteResource writeResourcee, GLProgram *programOut); void shaderStorageBitBufferWriteThenBufferRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void shaderStorageBitBufferReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); // Barrier bits affecting only images and imageBuffers void createTextureVerifyProgram(WriteResource writeResource, GLuint texture, GLProgram *programOut); void textureFetchBitImageWriteThenSamplerRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void textureFetchBitSamplerReadThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void createImageVerifyProgram(WriteResource writeResource, GLuint texture, GLProgram *programOut); void shaderImageAccessBitImageWriteThenImageRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void shaderImageAccessBitImageReadThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); // Barrier bits affecting only images void textureUpdateBitImageWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void textureUpdateBitCopyThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void framebufferBitImageWriteThenDraw(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void framebufferBitImageWriteThenReadPixels(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void framebufferBitImageWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void framebufferBitImageWriteThenBlit(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp); void framebufferBitDrawThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void framebufferBitReadPixelsThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void framebufferBitCopyThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); void framebufferBitBlitThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit); static constexpr int kTextureSize = 1; static constexpr char kUniformName[] = "uniformData"; }; // Can be removed with C++17 constexpr char MemoryBarrierTestBase::kUniformName[]; bool MemoryBarrierTestBase::hasExtensions(WriteResource writeResource) { return writeResource != WriteResource::ImageBuffer || IsGLExtensionEnabled("GL_OES_texture_buffer"); } void MemoryBarrierTestBase::createFramebuffer(GLuint color, GLuint fbo, GLColor initialColor) { glBindTexture(GL_TEXTURE_2D, color); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureSize, kTextureSize); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, &initialColor); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); EXPECT_GL_NO_ERROR(); // Ensure all staged data is flushed. EXPECT_PIXEL_COLOR_EQ(0, 0, initialColor); } void MemoryBarrierTestBase::createStorageBuffer(WriteResource writeResource, GLuint buffer, GLuint textureBuffer, size_t size, const void *initialData) { glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); glBufferData(GL_SHADER_STORAGE_BUFFER, size, initialData, GL_STATIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer); EXPECT_GL_NO_ERROR(); if (writeResource == WriteResource::ImageBuffer) { glBindTexture(GL_TEXTURE_BUFFER, textureBuffer); glTexBufferEXT(GL_TEXTURE_BUFFER, GL_RGBA32F, buffer); glBindImageTexture(0, textureBuffer, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); EXPECT_GL_NO_ERROR(); } } void MemoryBarrierTestBase::createStorageImage(WriteResource writeResource, GLuint bufferStorage, GLuint texture, const std::array &initialData) { const std::array initialDataAsUnorm = { static_cast(initialData[0] * 255), static_cast(initialData[1] * 255), static_cast(initialData[2] * 255), static_cast(initialData[3] * 255), }; if (writeResource == WriteResource::ImageBuffer) { glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferStorage); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(initialData), initialData.data(), GL_STATIC_DRAW); EXPECT_GL_NO_ERROR(); glBindTexture(GL_TEXTURE_BUFFER, texture); glTexBufferEXT(GL_TEXTURE_BUFFER, GL_RGBA32F, bufferStorage); glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); EXPECT_GL_NO_ERROR(); } else { glBindTexture(GL_TEXTURE_2D, texture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureSize, kTextureSize); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, initialDataAsUnorm.data()); glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); } } void MemoryBarrierTestBase::createProgram(ShaderWritePipeline writePipeline, WriteResource writeResource, GLProgram *programOut) { constexpr char kGraphicsImageFS[] = R"(#version 310 es precision mediump float; layout(rgba8, binding = 0) uniform highp writeonly image2D dst; uniform vec4 uniformData; out vec4 colorOut; void main() { colorOut = vec4(0, 0, 1.0, 1.0); imageStore(dst, ivec2(gl_FragCoord.xy), uniformData); })"; constexpr char kGraphicsBufferFS[] = R"(#version 310 es precision mediump float; uniform vec4 uniformData; layout(std430, binding = 0) buffer block { vec4 data; } outBlock; out vec4 colorOut; void main() { colorOut = vec4(0, 0, 1.0, 1.0); outBlock.data = uniformData; } )"; constexpr char kGraphicsImageBufferFS[] = R"(#version 310 es #extension GL_OES_texture_buffer : require precision mediump float; layout(rgba32f, binding = 0) uniform highp writeonly imageBuffer dst; uniform vec4 uniformData; out vec4 colorOut; void main() { colorOut = vec4(0, 0, 1.0, 1.0); imageStore(dst, int(gl_FragCoord.x), uniformData); })"; constexpr char kComputeImage[] = R"(#version 310 es layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(rgba8, binding = 0) uniform highp writeonly image2D dst; uniform vec4 uniformData; void main() { imageStore(dst, ivec2(gl_GlobalInvocationID.xy), uniformData); })"; constexpr char kComputeBuffer[] = R"(#version 310 es layout(local_size_x=1, local_size_y=1, local_size_z=1) in; uniform vec4 uniformData; layout(std430, binding = 0) buffer block { vec4 data; } outBlock; void main() { outBlock.data = uniformData; } )"; constexpr char kComputeImageBuffer[] = R"(#version 310 es #extension GL_OES_texture_buffer : require layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(rgba32f, binding = 0) uniform highp writeonly imageBuffer dst; uniform vec4 uniformData; void main() { imageStore(dst, int(gl_GlobalInvocationID.x), uniformData); })"; if (writePipeline == ShaderWritePipeline::Graphics) { const char *fs = ""; switch (writeResource) { case WriteResource::Image: fs = kGraphicsImageFS; break; case WriteResource::Buffer: fs = kGraphicsBufferFS; break; case WriteResource::ImageBuffer: fs = kGraphicsImageBufferFS; break; } programOut->makeRaster(essl31_shaders::vs::Simple(), fs); } else { const char *cs = ""; switch (writeResource) { case WriteResource::Image: cs = kComputeImage; break; case WriteResource::Buffer: cs = kComputeBuffer; break; case WriteResource::ImageBuffer: cs = kComputeImageBuffer; break; } programOut->makeCompute(cs); } ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); } void MemoryBarrierTestBase::createNoopGraphicsProgram(GLProgram *programOut) { programOut->makeRaster(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ASSERT_TRUE(programOut->valid()); } void MemoryBarrierTestBase::createNoopComputeProgram(GLProgram *programOut) { constexpr char kCS[] = R"(#version 310 es layout(local_size_x=1, local_size_y=1, local_size_z=1) in; void main() { })"; programOut->makeCompute(kCS); ASSERT_TRUE(programOut->valid()); } void MemoryBarrierTestBase::createQuadVertexArray(GLuint positionBuffer) { const std::array kQuadVertices = {{ Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f), Vector3(1.0f, -1.0f, 0.5f), Vector3(-1.0f, 1.0f, 0.5f), Vector3(1.0f, -1.0f, 0.5f), Vector3(1.0f, 1.0f, 0.5f), }}; const size_t bufferSize = kQuadVertices.size() * sizeof(Vector3); glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); glBufferData(GL_ARRAY_BUFFER, bufferSize, kQuadVertices.data(), GL_STATIC_DRAW); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::setupVertexArray(ShaderWritePipeline writePipeline, GLuint program) { if (writePipeline == ShaderWritePipeline::Compute) { return; } GLint positionLoc = glGetAttribLocation(program, essl31_shaders::PositionAttrib()); ASSERT_NE(-1, positionLoc); glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); glEnableVertexAttribArray(positionLoc); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::setUniformData(GLuint program, const std::array &data) { GLint uniformLocation = glGetUniformLocation(program, kUniformName); ASSERT_NE(uniformLocation, -1); glUniform4f(uniformLocation, data[0], data[1], data[2], data[3]); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::noopOp(NoopOp op) { if (op == NoopOp::None) { return; } GLProgram noopProgram; if (op == NoopOp::Draw) { createNoopGraphicsProgram(&noopProgram); glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_ONE); glUseProgram(noopProgram); glDrawArrays(GL_TRIANGLES, 0, 3); glDisable(GL_BLEND); } else { createNoopComputeProgram(&noopProgram); glUseProgram(noopProgram); glDispatchCompute(1, 1, 1); } EXPECT_GL_NO_ERROR(); } template void MemoryBarrierTestBase::verifyBufferContents(const std::array &expected) { glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); T *bufferContents = static_cast( glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(expected), GL_MAP_READ_BIT)); EXPECT_GL_NO_ERROR(); EXPECT_EQ(bufferContents[0], expected[0]); EXPECT_EQ(bufferContents[1], expected[1]); EXPECT_EQ(bufferContents[2], expected[2]); EXPECT_EQ(bufferContents[3], expected[3]); glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); } void MemoryBarrierTestBase::verifyImageContents(GLuint texture, const std::array &expected) { glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); glBindTexture(GL_TEXTURE_2D, texture); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); EXPECT_GL_NO_ERROR(); const GLColor kExpected(expected[0] * 255, expected[1] * 255, expected[2] * 255, expected[3] * 255); EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1); } template void MemoryBarrierTestBase::verifyFramebufferAndBufferContents(ShaderWritePipeline writePipeline, const std::array &expected) { // Verify the result of the verify shader const GLColor kExpected = writePipeline == ShaderWritePipeline::Graphics ? GLColor::cyan : GLColor::green; EXPECT_PIXEL_COLOR_EQ(0, 0, kExpected); // Verify the contents of the buffer verifyBufferContents(expected); } void MemoryBarrierTestBase::verifyFramebufferAndImageContents(ShaderWritePipeline writePipeline, WriteResource writeResource, GLuint texture, const std::array &expected) { // Verify the result of the verify shader const GLColor kExpected = writePipeline == ShaderWritePipeline::Graphics ? GLColor::cyan : GLColor::green; EXPECT_PIXEL_COLOR_EQ(0, 0, kExpected); if (writeResource == WriteResource::ImageBuffer) { // Verify the contents of the buffer verifyBufferContents(expected); } else { // Verify the contents of the image verifyImageContents(texture, expected); } } void MemoryBarrierTestBase::createVertexVerifyProgram(GLuint vertexBuffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es in float attribIn; out float v; void main() { v = attribIn; // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; in float v; out vec4 colorOut; void main() { if (v == 2.0) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); GLint attribLoc = glGetAttribLocation(*programOut, "attribIn"); ASSERT_NE(-1, attribLoc); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glVertexAttribPointer(attribLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr); glEnableVertexAttribArray(attribLoc); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::vertexAttribArrayBitBufferWriteThenVertexRead( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer vertexBuffer; GLTexture vertexTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, vertexBuffer, vertexTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {2.0, 2.0, 2.0, 2.0}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createVertexVerifyProgram(vertexBuffer, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); // Verify the vertex data was read correctly const GLColor kExpected = writePipeline == ShaderWritePipeline::Graphics ? GLColor::cyan : GLColor::green; EXPECT_PIXEL_COLOR_EQ(0, 0, kExpected); // Verify the contents of the buffer verifyBufferContents(kWriteData); } void MemoryBarrierTestBase::vertexAttribArrayBitVertexReadThenBufferWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer vertexBuffer; GLTexture vertexTextureBuffer; constexpr std::array kInitData = {2.0, 2.0, 2.0, 2.0}; createStorageBuffer(writeResource, vertexBuffer, vertexTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createVertexVerifyProgram(vertexBuffer, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); GLint attribLoc = glGetAttribLocation(readProgram, "attribIn"); glDisableVertexAttribArray(attribLoc); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createIndexVerifyProgram(GLuint indexBuffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; out vec4 colorOut; void main() { colorOut = vec4(0, 1.0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::elementArrayBitBufferWriteThenIndexRead( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer indexBuffer; GLTexture indexTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, indexBuffer, indexTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {0, 1, 2, 3}; const std::array kWriteDataAsFloat = { *reinterpret_cast(&kWriteData[0]), *reinterpret_cast(&kWriteData[1]), *reinterpret_cast(&kWriteData[2]), *reinterpret_cast(&kWriteData[3]), }; setUniformData(writeProgram, kWriteDataAsFloat); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_ELEMENT_ARRAY_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createIndexVerifyProgram(indexBuffer, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0); EXPECT_GL_NO_ERROR(); verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::elementArrayBitIndexReadThenBufferWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer indexBuffer; GLTexture indexTextureBuffer; constexpr std::array kInitData = {0, 1, 2, 3}; createStorageBuffer(writeResource, indexBuffer, indexTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createIndexVerifyProgram(indexBuffer, &readProgram); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createUBOVerifyProgram(GLuint buffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; layout(binding = 0) uniform block { vec4 data; } ubo; out vec4 colorOut; void main() { if (ubo.data == vec4(1.5, 3.75, 5.0, 12.125)) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindBuffer(GL_UNIFORM_BUFFER, buffer); glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::uniformBitBufferWriteThenUBORead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer uniformBuffer; GLTexture uniformTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, uniformBuffer, uniformTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_UNIFORM_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createUBOVerifyProgram(uniformBuffer, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::uniformBitUBOReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer uniformBuffer; GLTexture uniformTextureBuffer; constexpr std::array kInitData = {1.5, 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, uniformBuffer, uniformTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createUBOVerifyProgram(uniformBuffer, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createIndirectVerifyProgram(GLuint buffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; out vec4 colorOut; void main() { colorOut = vec4(0, 1.0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::commandBitBufferWriteThenIndirectRead(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer indirectBuffer; GLTexture indirectTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, indirectBuffer, indirectTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {4, 1, 0, 0}; const std::array kWriteDataAsFloat = { *reinterpret_cast(&kWriteData[0]), *reinterpret_cast(&kWriteData[1]), *reinterpret_cast(&kWriteData[2]), *reinterpret_cast(&kWriteData[3]), }; setUniformData(writeProgram, kWriteDataAsFloat); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_COMMAND_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createIndirectVerifyProgram(indirectBuffer, &readProgram); GLVertexArray vao; glBindVertexArray(vao); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArraysIndirect(GL_TRIANGLE_STRIP, nullptr); EXPECT_GL_NO_ERROR(); verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::commandBitIndirectReadThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer indirectBuffer; GLTexture indirectTextureBuffer; constexpr std::array kInitData = {4, 1, 0, 0}; createStorageBuffer(writeResource, indirectBuffer, indirectTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createIndirectVerifyProgram(indirectBuffer, &readProgram); GLVertexArray vao; glBindVertexArray(vao); glDrawArraysIndirect(GL_TRIANGLE_STRIP, nullptr); EXPECT_GL_NO_ERROR(); glBindVertexArray(0); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::pixelBufferBitBufferWriteThenPack(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer packBuffer; GLTexture packTextureBuffer; constexpr std::array kInitData = {1.5, 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, packBuffer, packTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); glReadPixels(0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); const std::array kExpectedData = { writePipeline == ShaderWritePipeline::Graphics ? 0xFFFFFF00u : 0xFF00FF00u, *reinterpret_cast(&kWriteData[1]), *reinterpret_cast(&kWriteData[2]), *reinterpret_cast(&kWriteData[3]), }; verifyFramebufferAndBufferContents(writePipeline, kExpectedData); } void MemoryBarrierTestBase::pixelBufferBitBufferWriteThenUnpack(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer unpackBuffer; GLTexture unpackTextureBuffer; constexpr std::array kInitData = {1.5, 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, unpackBuffer, unpackTextureBuffer, sizeof(kInitData), kInitData.data()); const std::array kWriteData = {*reinterpret_cast(&GLColor::green), 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); // Verify the result of the unpack operation EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); // Verify the contents of the buffer verifyBufferContents(kWriteData); } void MemoryBarrierTestBase::pixelBufferBitPackThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer packBuffer; GLTexture packTextureBuffer; constexpr std::array kInitData = {1.5, 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, packBuffer, packTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); glReadPixels(0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::pixelBufferBitUnpackThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer unpackBuffer; GLTexture unpackTextureBuffer; const std::array kInitData = {*reinterpret_cast(&GLColor::green), 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, unpackBuffer, unpackTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::bufferUpdateBitBufferWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLBuffer srcBuffer; GLTexture srcTextureBuffer; constexpr std::array kSrcInitData = {9.3, 3.7, 11.34, 0.65}; createStorageBuffer(WriteResource::Buffer, srcBuffer, srcTextureBuffer, sizeof(kSrcInitData), kSrcInitData.data()); GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer writeBuffer; GLTexture writeTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); noopOp(postBarrierOp); // Copy from src buffer over the buffer glBindBuffer(GL_UNIFORM_BUFFER, srcBuffer); glCopyBufferSubData(GL_UNIFORM_BUFFER, GL_SHADER_STORAGE_BUFFER, 0, 0, sizeof(kInitData)); verifyFramebufferAndBufferContents(writePipeline, kSrcInitData); // Verify the src buffer is unaffected glBindBuffer(GL_SHADER_STORAGE_BUFFER, srcBuffer); verifyBufferContents(kSrcInitData); } void MemoryBarrierTestBase::bufferUpdateBitCopyThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLBuffer srcBuffer; GLTexture srcTextureBuffer; constexpr std::array kSrcInitData = {9.3, 3.7, 11.34, 0.65}; createStorageBuffer(WriteResource::Buffer, srcBuffer, srcTextureBuffer, sizeof(kSrcInitData), kSrcInitData.data()); GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer writeBuffer; GLTexture writeTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData), kInitData.data()); // Copy from src buffer over the buffer glBindBuffer(GL_UNIFORM_BUFFER, srcBuffer); glCopyBufferSubData(GL_UNIFORM_BUFFER, GL_SHADER_STORAGE_BUFFER, 0, 0, sizeof(kInitData)); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); // Verify the src buffer is unaffected glBindBuffer(GL_SHADER_STORAGE_BUFFER, srcBuffer); verifyBufferContents(kSrcInitData); } void MemoryBarrierTestBase::createXfbVerifyProgram(GLuint buffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 (000) -1 -1 // 1 (001) 1 -1 // 2 (010) -1 1 // 3 (011) 1 1 // 4 (100) -1 1 // 5 (101) 1 -1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID < 4 ? gl_VertexID >> 1 & 1 : ~bit0 & 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; out vec4 colorOut; void main() { colorOut = vec4(0, 1.0, 0, 1.0); })"; const std::vector &tfVaryings = {"gl_Position"}; programOut->makeRasterWithTransformFeedback(kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::transformFeedbackBitBufferWriteThenCapture( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer xfbBuffer; GLTexture xfbTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, xfbBuffer, xfbTextureBuffer, sizeof(kInitData) * 6, kInitData.data()); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_TRANSFORM_FEEDBACK_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram xfbProgram; createXfbVerifyProgram(xfbBuffer, &xfbProgram); glBeginTransformFeedback(GL_TRIANGLES); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glEndTransformFeedback(); EXPECT_GL_NO_ERROR(); const std::array kExpectedData = {-1.0, -1.0, 0.0, 1.0}; verifyFramebufferAndBufferContents(writePipeline, kExpectedData); } void MemoryBarrierTestBase::transformFeedbackBitCaptureThenBufferWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer xfbBuffer; GLTexture xfbTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, xfbBuffer, xfbTextureBuffer, sizeof(kInitData) * 6, kInitData.data()); // Use the buffer GLProgram xfbProgram; createXfbVerifyProgram(xfbBuffer, &xfbProgram); glBeginTransformFeedback(GL_TRIANGLES); glDrawArrays(GL_TRIANGLES, 0, 6); glEndTransformFeedback(); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createAtomicCounterVerifyProgram(GLuint buffer, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; layout(binding = 0, offset = 0) uniform atomic_uint ac[4]; out vec4 colorOut; void main() { uvec4 acValue = uvec4(atomicCounterIncrement(ac[0]), atomicCounterIncrement(ac[1]), atomicCounterIncrement(ac[2]), atomicCounterIncrement(ac[3])); if (all(equal(acValue, uvec4(10, 20, 30, 40)))) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer); glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffer); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::atomicCounterBitBufferWriteThenAtomic(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer atomicCounterBuffer; GLTexture atomicCounterTextureBuffer; constexpr std::array kInitData = {0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u}; createStorageBuffer(writeResource, atomicCounterBuffer, atomicCounterTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {10, 20, 30, 40}; const std::array kWriteDataAsFloat = { *reinterpret_cast(&kWriteData[0]), *reinterpret_cast(&kWriteData[1]), *reinterpret_cast(&kWriteData[2]), *reinterpret_cast(&kWriteData[3]), }; setUniformData(writeProgram, kWriteDataAsFloat); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createAtomicCounterVerifyProgram(atomicCounterBuffer, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); constexpr std::array kExpectedData = {11, 21, 31, 41}; verifyFramebufferAndBufferContents(writePipeline, kExpectedData); } void MemoryBarrierTestBase::atomicCounterBitAtomicThenBufferWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer atomicCounterBuffer; GLTexture atomicCounterTextureBuffer; constexpr std::array kInitData = {10, 20, 30, 40}; createStorageBuffer(writeResource, atomicCounterBuffer, atomicCounterTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createAtomicCounterVerifyProgram(atomicCounterBuffer, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the buffer createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createSsboVerifyProgram(WriteResource writeResource, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; layout(std430, binding = 0) buffer block { vec4 data; } inBlock; out vec4 colorOut; void main() { if (all(lessThan(abs(inBlock.data - vec4(1.5, 3.75, 5.0, 12.125)), vec4(0.01)))) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, kFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); } void MemoryBarrierTestBase::shaderStorageBitBufferWriteThenBufferRead( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer writeBuffer; GLTexture writeTextureBuffer; constexpr std::array kInitData = {12.34, 5.6, 78.91, 123.456}; createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData), kInitData.data()); constexpr std::array kWriteData = {1.5, 3.75, 5.0, 12.125}; setUniformData(writeProgram, kWriteData); // Fill the buffer if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); noopOp(postBarrierOp); // Use the buffer GLProgram readProgram; createSsboVerifyProgram(writeResource, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::shaderStorageBitBufferReadThenBufferWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer writeBuffer; GLTexture writeTextureBuffer; constexpr std::array kInitData = {1.5, 3.75, 5.0, 12.125}; createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData), kInitData.data()); // Use the buffer GLProgram readProgram; createSsboVerifyProgram(writeResource, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {12.34, 5.6, 78.91, 123.456}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndBufferContents(writePipeline, kWriteData); } void MemoryBarrierTestBase::createTextureVerifyProgram(WriteResource writeResource, GLuint texture, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kImageFS[] = R"(#version 310 es precision mediump float; uniform sampler2D s; out vec4 colorOut; void main() { if (all(lessThan(abs(texelFetch(s, ivec2(0, 0), 0)- vec4(0.125, 0.25, 0.5, 0.75)), vec4(0.01)))) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; constexpr char kImageBufferFS[] = R"(#version 310 es #extension GL_OES_texture_buffer : require precision mediump float; uniform highp samplerBuffer s; out vec4 colorOut; void main() { if (texelFetch(s, 0) == vec4(0.125, 0.25, 0.5, 0.75)) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, writeResource == WriteResource::ImageBuffer ? kImageBufferFS : kImageFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); glBindTexture(writeResource == WriteResource::ImageBuffer ? GL_TEXTURE_BUFFER : GL_TEXTURE_2D, texture); EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::textureFetchBitImageWriteThenSamplerRead( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); noopOp(postBarrierOp); // Use the image GLProgram readProgram; createTextureVerifyProgram(writeResource, texture, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::textureFetchBitSamplerReadThenImageWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.125, 0.25, 0.5, 0.75}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Use the image GLProgram readProgram; createTextureVerifyProgram(writeResource, texture, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.65, 0.20, 0.40, 0.95}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::createImageVerifyProgram(WriteResource writeResource, GLuint texture, GLProgram *programOut) { constexpr char kVS[] = R"(#version 310 es void main() { // gl_VertexID x y // 0 -1 -1 // 1 1 -1 // 2 -1 1 // 3 1 1 int bit0 = gl_VertexID & 1; int bit1 = gl_VertexID >> 1; gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1); })"; constexpr char kImageFS[] = R"(#version 310 es precision mediump float; layout(rgba8, binding = 0) uniform highp readonly image2D img; out vec4 colorOut; void main() { if (all(lessThan(abs(imageLoad(img, ivec2(0, 0))- vec4(0.125, 0.25, 0.5, 0.75)), vec4(0.01)))) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; constexpr char kImageBufferFS[] = R"(#version 310 es #extension GL_OES_texture_buffer : require precision mediump float; layout(rgba32f, binding = 0) uniform highp readonly imageBuffer img; out vec4 colorOut; void main() { if (imageLoad(img, 0) == vec4(0.125, 0.25, 0.5, 0.75)) colorOut = vec4(0, 1.0, 0, 1.0); else colorOut = vec4(1.0, 0, 0, 1.0); })"; programOut->makeRaster(kVS, writeResource == WriteResource::ImageBuffer ? kImageBufferFS : kImageFS); ASSERT_TRUE(programOut->valid()); glUseProgram(*programOut); if (writeResource == WriteResource::ImageBuffer) { glBindTexture(GL_TEXTURE_BUFFER, texture); glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); } else { glBindTexture(GL_TEXTURE_2D, texture); glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8); } EXPECT_GL_NO_ERROR(); } void MemoryBarrierTestBase::shaderImageAccessBitImageWriteThenImageRead( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); noopOp(postBarrierOp); // Use the image GLProgram readProgram; createImageVerifyProgram(writeResource, texture, &readProgram); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::shaderImageAccessBitImageReadThenImageWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::black); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.125, 0.25, 0.5, 0.75}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Use the image GLProgram readProgram; createImageVerifyProgram(writeResource, texture, &readProgram); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.65, 0.20, 0.40, 0.95}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::textureUpdateBitImageWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT); noopOp(postBarrierOp); // Copy from framebuffer over the texture glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTextureSize, kTextureSize); const std::array kExpectedData = { 0, 1.0f, writePipeline == ShaderWritePipeline::Graphics ? 1.0f : 0, 1.0f}; verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kExpectedData); } void MemoryBarrierTestBase::textureUpdateBitCopyThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Copy from framebuffer over the texture glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTextureSize, kTextureSize); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::framebufferBitImageWriteThenDraw(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Draw to image via framebuffer ANGLE_GL_PROGRAM(verifyProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); glUseProgram(verifyProgram); GLint colorUniformLocation = glGetUniformLocation(verifyProgram, angle::essl1_shaders::ColorUniform()); ASSERT_NE(colorUniformLocation, -1); setupVertexArray(ShaderWritePipeline::Graphics, verifyProgram); GLFramebuffer drawFbo; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFbo); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER); constexpr std::array kBlendData = {0.125, 0.25, 0.5, 0.25}; glUniform4fv(colorUniformLocation, 1, kBlendData.data()); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); EXPECT_GL_NO_ERROR(); const std::array kExpectedData = { kWriteData[0] + kBlendData[0], kWriteData[1] + kBlendData[1], kWriteData[2] + kBlendData[2], kWriteData[3] + kBlendData[3], }; verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kExpectedData); } void MemoryBarrierTestBase::framebufferBitImageWriteThenReadPixels( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {1.0, 1.0, 0.0, 1.0}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Read from image via framebuffer GLBuffer packBuffer; glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); constexpr std::array kPBOInitData = {0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u}; glBufferData(GL_PIXEL_PACK_BUFFER, sizeof(kInitData), kPBOInitData.data(), GL_STATIC_DRAW); EXPECT_GL_NO_ERROR(); GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); glReadPixels(0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); EXPECT_GL_NO_ERROR(); verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the PBO for completeness glBindBuffer(GL_SHADER_STORAGE_BUFFER, packBuffer); constexpr std::array kExpectedData = { 0xFF00FFFFu, kPBOInitData[1], kPBOInitData[2], kPBOInitData[3], }; verifyBufferContents(kExpectedData); } void MemoryBarrierTestBase::framebufferBitImageWriteThenCopy(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {1.0, 1.0, 0.0, 1.0}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Copy from framebuffer to another texture GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); GLTexture copyTexture; glBindTexture(GL_TEXTURE_2D, copyTexture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureSize, kTextureSize); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTextureSize, kTextureSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); EXPECT_GL_NO_ERROR(); verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the copy texture for completeness verifyImageContents(copyTexture, kWriteData); } void MemoryBarrierTestBase::framebufferBitImageWriteThenBlit(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp) { GLTexture blitColor; GLFramebuffer blitFbo; createFramebuffer(blitColor, blitFbo, GLColor::black); GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); constexpr std::array kWriteData = {1.0, 1.0, 0.0, 1.0}; setUniformData(writeProgram, kWriteData); // Fill the image if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); glDisable(GL_BLEND); } else { glDispatchCompute(1, 1, 1); } noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); noopOp(postBarrierOp); // Blit from framebuffer to another framebuffer GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, blitFbo); glBlitFramebuffer(0, 0, kTextureSize, kTextureSize, 0, 0, kTextureSize, kTextureSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); EXPECT_GL_NO_ERROR(); verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the blit fbo for completeness glBindFramebuffer(GL_READ_FRAMEBUFFER, blitFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); } void MemoryBarrierTestBase::framebufferBitDrawThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {0.65, 0.92, 0.11, 0.54}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Draw to image via framebuffer ANGLE_GL_PROGRAM(verifyProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); glUseProgram(verifyProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(ShaderWritePipeline::Graphics, verifyProgram); GLFramebuffer drawFbo; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFbo); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER); glDrawArrays(GL_TRIANGLES, 0, 6); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); } void MemoryBarrierTestBase::framebufferBitReadPixelsThenImageWrite( ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {1.0, 1.0, 0.0, 1.0}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Read from image via framebuffer GLBuffer packBuffer; glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer); constexpr std::array kPBOInitData = {0x12345678u, 0x9ABCDEF0u, 0x13579BDFu, 0x2468ACE0u}; glBufferData(GL_PIXEL_PACK_BUFFER, sizeof(kInitData), kPBOInitData.data(), GL_STATIC_DRAW); EXPECT_GL_NO_ERROR(); GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); glReadPixels(0, 0, kTextureSize, kTextureSize, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the PBO for completeness glBindBuffer(GL_SHADER_STORAGE_BUFFER, packBuffer); constexpr std::array kExpectedData = { 0xFF00FFFFu, kPBOInitData[1], kPBOInitData[2], kPBOInitData[3], }; verifyBufferContents(kExpectedData); } void MemoryBarrierTestBase::framebufferBitCopyThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {1.0, 1.0, 0.0, 1.0}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Copy from framebuffer to another texture GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); GLTexture copyTexture; glBindTexture(GL_TEXTURE_2D, copyTexture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureSize, kTextureSize); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTextureSize, kTextureSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the copy texture for completeness verifyImageContents(copyTexture, kInitData); } void MemoryBarrierTestBase::framebufferBitBlitThenImageWrite(ShaderWritePipeline writePipeline, WriteResource writeResource, NoopOp preBarrierOp, NoopOp postBarrierOp, GLbitfield barrierBit) { GLTexture blitColor; GLFramebuffer blitFbo; createFramebuffer(blitColor, blitFbo, GLColor::black); GLTexture color; GLFramebuffer fbo; GLProgram writeProgram; createFramebuffer(color, fbo, GLColor::green); GLBuffer textureBufferStorage; GLTexture texture; constexpr std::array kInitData = {1.0, 1.0, 0.0, 1.0}; createStorageImage(writeResource, textureBufferStorage, texture, kInitData); // Blit from framebuffer to another framebuffer GLFramebuffer readFbo; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, blitFbo); glBlitFramebuffer(0, 0, kTextureSize, kTextureSize, 0, 0, kTextureSize, kTextureSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, fbo); EXPECT_GL_NO_ERROR(); noopOp(preBarrierOp); // Issue the appropriate memory barrier glMemoryBarrier(barrierBit); noopOp(postBarrierOp); // Fill the image createProgram(writePipeline, writeResource, &writeProgram); GLBuffer positionBuffer; createQuadVertexArray(positionBuffer); setupVertexArray(writePipeline, writeProgram); constexpr std::array kWriteData = {0.125, 0.25, 0.5, 0.75}; setUniformData(writeProgram, kWriteData); if (writePipeline == ShaderWritePipeline::Graphics) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDrawArrays(GL_TRIANGLES, 0, 6); } else { glDispatchCompute(1, 1, 1); } verifyFramebufferAndImageContents(writePipeline, writeResource, texture, kWriteData); // Verify the blit fbo for completeness glBindFramebuffer(GL_READ_FRAMEBUFFER, blitFbo); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow); } class MemoryBarrierBufferTest : public MemoryBarrierTestBase, public ANGLETestWithParam { protected: MemoryBarrierBufferTest() { setWindowWidth(16); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; class MemoryBarrierImageTest : public MemoryBarrierTestBase, public ANGLETestWithParam { protected: MemoryBarrierImageTest() { setWindowWidth(16); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; class MemoryBarrierImageBufferOnlyTest : public MemoryBarrierTestBase, public ANGLETestWithParam { protected: MemoryBarrierImageBufferOnlyTest() { setWindowWidth(16); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; class MemoryBarrierImageOnlyTest : public MemoryBarrierTestBase, public ANGLETestWithParam { protected: MemoryBarrierImageOnlyTest() { setWindowWidth(16); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; class MemoryBarrierBufferOnlyTest : public MemoryBarrierTestBase, public ANGLETestWithParam { protected: MemoryBarrierBufferOnlyTest() { setWindowWidth(16); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; // Test GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; shader write -> vertex read TEST_P(MemoryBarrierBufferTest, VertexAtrribArrayBitWriteThenVertexRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); vertexAttribArrayBitBufferWriteThenVertexRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_ELEMENT_ARRAY_BARRIER_BIT; shader write -> index read TEST_P(MemoryBarrierBufferTest, ElementArrayBitWriteThenIndexRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); elementArrayBitBufferWriteThenIndexRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_UNIFORM_BARRIER_BIT; shader write -> ubo read TEST_P(MemoryBarrierBufferTest, UniformBitWriteThenUBORead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); uniformBitBufferWriteThenUBORead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_TEXTURE_FETCH_BARRIER_BIT; shader write -> sampler read TEST_P(MemoryBarrierImageTest, TextureFetchBitWriteThenSamplerRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); textureFetchBitImageWriteThenSamplerRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; shader write -> image read TEST_P(MemoryBarrierImageTest, ShaderImageAccessBitWriteThenImageRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); shaderImageAccessBitImageWriteThenImageRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; image read -> shader write TEST_P(MemoryBarrierImageTest, ShaderImageAccessBitImageReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); // Looks like the implementation is missing this line from the spec: // // > Additionally, image stores issued after the barrier will not execute until all memory // > accesses (e.g., loads, stores, texture fetches, vertex fetches) initiated prior to the // > barrier complete. // // http://anglebug.com/5650 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA() && writeResource == WriteResource::Image); shaderImageAccessBitImageReadThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; vertex read -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitVertexReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); vertexAttribArrayBitVertexReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; index read -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitIndexReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); elementArrayBitIndexReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; ubo read -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitUBOReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); uniformBitUBOReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; sampler read -> shader write TEST_P(MemoryBarrierImageTest, ShaderImageAccessBitSamplerReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); textureFetchBitSamplerReadThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; indirect read -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitIndirectReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); commandBitIndirectReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; pixel pack -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitPackThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitPackThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; pixel unpack -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitUnpackThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitUnpackThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; texture copy -> shader write TEST_P(MemoryBarrierImageOnlyTest, ShaderImageAccessBitCopyThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); textureUpdateBitCopyThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; buffer copy -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitCopyThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); bufferUpdateBitCopyThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; draw -> shader write TEST_P(MemoryBarrierImageOnlyTest, ShaderImageAccessBitDrawThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitDrawThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; read pixels -> shader write TEST_P(MemoryBarrierImageOnlyTest, ShaderImageAccessBitReadPixelsThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitReadPixelsThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; fbo copy -> shader write TEST_P(MemoryBarrierImageOnlyTest, ShaderImageAccessBitFBOCopyThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitCopyThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; blit -> shader write TEST_P(MemoryBarrierImageOnlyTest, ShaderImageAccessBitBlitThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitBlitThenImageWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; xfb capture -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitCaptureThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); transformFeedbackBitCaptureThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; atomic write -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitAtomicThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); atomicCounterBitAtomicThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; buffer read -> shader write TEST_P(MemoryBarrierImageBufferOnlyTest, ShaderImageAccessBitBufferReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); shaderStorageBitBufferReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); } // Test GL_COMMAND_BARRIER_BIT; shader write -> indirect read TEST_P(MemoryBarrierBufferTest, CommandBitWriteThenIndirectRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); commandBitBufferWriteThenIndirectRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_PIXEL_BUFFER_BARRIER_BIT; shader write -> pixel pack TEST_P(MemoryBarrierBufferTest, PixelBufferBitWriteThenPack) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitBufferWriteThenPack(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_PIXEL_BUFFER_BARRIER_BIT; shader write -> pixel unpack TEST_P(MemoryBarrierBufferTest, PixelBufferBitWriteThenUnpack) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitBufferWriteThenUnpack(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_TEXTURE_UPDATE_BARRIER_BIT; shader write -> texture copy TEST_P(MemoryBarrierImageOnlyTest, TextureUpdateBitWriteThenCopy) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); textureUpdateBitImageWriteThenCopy(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_BUFFER_UPDATE_BARRIER_BIT; shader write -> buffer copy TEST_P(MemoryBarrierBufferTest, BufferUpdateBitWriteThenCopy) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); bufferUpdateBitBufferWriteThenCopy(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_FRAMEBUFFER_BARRIER_BIT; shader write -> draw TEST_P(MemoryBarrierImageOnlyTest, FramebufferBitWriteThenDraw) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitImageWriteThenDraw(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_FRAMEBUFFER_BARRIER_BIT; shader write -> read pixels TEST_P(MemoryBarrierImageOnlyTest, FramebufferBitWriteThenReadPixels) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitImageWriteThenReadPixels(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_FRAMEBUFFER_BARRIER_BIT; shader write -> copy TEST_P(MemoryBarrierImageOnlyTest, FramebufferBitWriteThenCopy) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitImageWriteThenCopy(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_FRAMEBUFFER_BARRIER_BIT; shader write -> blit TEST_P(MemoryBarrierImageOnlyTest, FramebufferBitWriteThenBlit) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); framebufferBitImageWriteThenBlit(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_TRANSFORM_FEEDBACK_BARRIER_BIT; shader write -> xfb capture TEST_P(MemoryBarrierBufferTest, TransformFeedbackBitWriteThenCapture) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); transformFeedbackBitBufferWriteThenCapture(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_ATOMIC_COUNTER_BARRIER_BIT; shader write -> atomic write TEST_P(MemoryBarrierBufferTest, AtomicCounterBitWriteThenAtomic) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); atomicCounterBitBufferWriteThenAtomic(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_SHADER_STORAGE_BARRIER_BIT; shader write -> shader read TEST_P(MemoryBarrierBufferTest, ShaderStorageBitWriteThenRead) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); shaderStorageBitBufferWriteThenBufferRead(writePipeline, writeResource, preBarrierOp, postBarrierOp); } // Test GL_SHADER_STORAGE_BARRIER_BIT; shader read -> buffer write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); shaderStorageBitBufferReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; vertex read -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitVertexReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); vertexAttribArrayBitVertexReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; index read -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitIndexReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); elementArrayBitIndexReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; ubo read -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitUBOReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); uniformBitUBOReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; indirect read -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitIndirectReadThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); commandBitIndirectReadThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; pixel pack -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitPackThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitPackThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; pixel unpack -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitUnpackThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); pixelBufferBitUnpackThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; buffer copy -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitCopyThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); bufferUpdateBitCopyThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; xfb capture -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitCaptureThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); transformFeedbackBitCaptureThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } // Test GL_SHADER_STORAGE_BARRIER_BIT; atomic write -> shader write TEST_P(MemoryBarrierBufferOnlyTest, ShaderStorageBitAtomicThenWrite) { ShaderWritePipeline writePipeline; WriteResource writeResource; NoopOp preBarrierOp; NoopOp postBarrierOp; ParseMemoryBarrierVariationsTestParams(GetParam(), &writePipeline, &writeResource, &preBarrierOp, &postBarrierOp); ANGLE_SKIP_TEST_IF(!hasExtensions(writeResource)); atomicCounterBitAtomicThenBufferWrite(writePipeline, writeResource, preBarrierOp, postBarrierOp, GL_SHADER_STORAGE_BARRIER_BIT); } constexpr ShaderWritePipeline kWritePipelines[] = { ShaderWritePipeline::Graphics, ShaderWritePipeline::Compute, }; constexpr WriteResource kBufferWriteResources[] = { WriteResource::Buffer, WriteResource::ImageBuffer, }; constexpr WriteResource kImageWriteResources[] = { WriteResource::Image, WriteResource::ImageBuffer, }; constexpr WriteResource kImageBufferOnlyWriteResources[] = { WriteResource::ImageBuffer, }; constexpr WriteResource kImageOnlyWriteResources[] = { WriteResource::Image, }; constexpr WriteResource kBufferOnlyWriteResources[] = { WriteResource::Buffer, }; constexpr NoopOp kNoopOps[] = { NoopOp::None, NoopOp::Draw, NoopOp::Dispatch, }; // Note: due to large number of tests, these are only run on Vulkan and a single configuration // (swiftshader). GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryBarrierBufferTest); ANGLE_INSTANTIATE_TEST_COMBINE_4(MemoryBarrierBufferTest, MemoryBarrierVariationsTestPrint, testing::ValuesIn(kWritePipelines), testing::ValuesIn(kBufferWriteResources), testing::ValuesIn(kNoopOps), testing::ValuesIn(kNoopOps), ES31_VULKAN_SWIFTSHADER()); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryBarrierImageTest); ANGLE_INSTANTIATE_TEST_COMBINE_4(MemoryBarrierImageTest, MemoryBarrierVariationsTestPrint, testing::ValuesIn(kWritePipelines), testing::ValuesIn(kImageWriteResources), testing::ValuesIn(kNoopOps), testing::ValuesIn(kNoopOps), ES31_VULKAN_SWIFTSHADER()); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryBarrierImageBufferOnlyTest); ANGLE_INSTANTIATE_TEST_COMBINE_4(MemoryBarrierImageBufferOnlyTest, MemoryBarrierVariationsTestPrint, testing::ValuesIn(kWritePipelines), testing::ValuesIn(kImageBufferOnlyWriteResources), testing::ValuesIn(kNoopOps), testing::ValuesIn(kNoopOps), ES31_VULKAN_SWIFTSHADER()); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryBarrierImageOnlyTest); ANGLE_INSTANTIATE_TEST_COMBINE_4(MemoryBarrierImageOnlyTest, MemoryBarrierVariationsTestPrint, testing::ValuesIn(kWritePipelines), testing::ValuesIn(kImageOnlyWriteResources), testing::ValuesIn(kNoopOps), testing::ValuesIn(kNoopOps), ES31_VULKAN_SWIFTSHADER()); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryBarrierBufferOnlyTest); ANGLE_INSTANTIATE_TEST_COMBINE_4(MemoryBarrierBufferOnlyTest, MemoryBarrierVariationsTestPrint, testing::ValuesIn(kWritePipelines), testing::ValuesIn(kBufferOnlyWriteResources), testing::ValuesIn(kNoopOps), testing::ValuesIn(kNoopOps), ES31_VULKAN_SWIFTSHADER()); } // anonymous namespace