blob: f00333a0182ae7febd3ea8f9fc2bb953750453bc [file] [log] [blame]
//
// 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<angle::PlatformParameters, ShaderWritePipeline, WriteResource, NoopOp, NoopOp>;
void ParseMemoryBarrierVariationsTestParams(const MemoryBarrierVariationsTestParams &params,
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<MemoryBarrierVariationsTestParams> &paramsInfo)
{
const MemoryBarrierVariationsTestParams &params = 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<float, 4> &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<float, 4> &data);
void noopOp(NoopOp op);
template <typename T>
void verifyBufferContents(const std::array<T, 4> &expected);
void verifyImageContents(GLuint texture, const std::array<float, 4> &expected);
template <typename T>
void verifyFramebufferAndBufferContents(ShaderWritePipeline writePipeline,
const std::array<T, 4> &expected);
void verifyFramebufferAndImageContents(ShaderWritePipeline writePipeline,
WriteResource writeResource,
GLuint texture,
const std::array<float, 4> &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<float, 4> &initialData)
{
const std::array<uint8_t, 4> initialDataAsUnorm = {
static_cast<uint8_t>(initialData[0] * 255),
static_cast<uint8_t>(initialData[1] * 255),
static_cast<uint8_t>(initialData[2] * 255),
static_cast<uint8_t>(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<Vector3, 6> 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<float, 4> &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 <typename T>
void MemoryBarrierTestBase::verifyBufferContents(const std::array<T, 4> &expected)
{
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T *bufferContents = static_cast<T *>(
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<float, 4> &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 <typename T>
void MemoryBarrierTestBase::verifyFramebufferAndBufferContents(ShaderWritePipeline writePipeline,
const std::array<T, 4> &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<float, 4> &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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, vertexBuffer, vertexTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, indexBuffer, indexTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<uint32_t, 4> kWriteData = {0, 1, 2, 3};
const std::array<float, 4> kWriteDataAsFloat = {
*reinterpret_cast<const float *>(&kWriteData[0]),
*reinterpret_cast<const float *>(&kWriteData[1]),
*reinterpret_cast<const float *>(&kWriteData[2]),
*reinterpret_cast<const float *>(&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<uint32_t, 4> 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<float, 4> 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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, uniformBuffer, uniformTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, indirectBuffer, indirectTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<uint32_t, 4> kWriteData = {4, 1, 0, 0};
const std::array<float, 4> kWriteDataAsFloat = {
*reinterpret_cast<const float *>(&kWriteData[0]),
*reinterpret_cast<const float *>(&kWriteData[1]),
*reinterpret_cast<const float *>(&kWriteData[2]),
*reinterpret_cast<const float *>(&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<uint32_t, 4> 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<float, 4> 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<float, 4> kInitData = {1.5, 3.75, 5.0, 12.125};
createStorageBuffer(writeResource, packBuffer, packTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<float, 4> 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<uint32_t, 4> kExpectedData = {
writePipeline == ShaderWritePipeline::Graphics ? 0xFFFFFF00u : 0xFF00FF00u,
*reinterpret_cast<const uint32_t *>(&kWriteData[1]),
*reinterpret_cast<const uint32_t *>(&kWriteData[2]),
*reinterpret_cast<const uint32_t *>(&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<float, 4> kInitData = {1.5, 3.75, 5.0, 12.125};
createStorageBuffer(writeResource, unpackBuffer, unpackTextureBuffer, sizeof(kInitData),
kInitData.data());
const std::array<float, 4> kWriteData = {*reinterpret_cast<const float *>(&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<float, 4> 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<float, 4> 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<float, 4> kInitData = {*reinterpret_cast<const float *>(&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<float, 4> 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<float, 4> 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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<std::string> &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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, xfbBuffer, xfbTextureBuffer, sizeof(kInitData) * 6,
kInitData.data());
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<uint32_t, 4> kInitData = {0x12345678u, 0x9ABCDEF0u, 0x13579BDFu,
0x2468ACE0u};
createStorageBuffer(writeResource, atomicCounterBuffer, atomicCounterTextureBuffer,
sizeof(kInitData), kInitData.data());
constexpr std::array<uint32_t, 4> kWriteData = {10, 20, 30, 40};
const std::array<float, 4> kWriteDataAsFloat = {
*reinterpret_cast<const float *>(&kWriteData[0]),
*reinterpret_cast<const float *>(&kWriteData[1]),
*reinterpret_cast<const float *>(&kWriteData[2]),
*reinterpret_cast<const float *>(&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<uint32_t, 4> 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<uint32_t, 4> 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<float, 4> 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<float, 4> kInitData = {12.34, 5.6, 78.91, 123.456};
createStorageBuffer(writeResource, writeBuffer, writeTextureBuffer, sizeof(kInitData),
kInitData.data());
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<uint32_t, 4> 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<uint32_t, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> kInitData = {0.65, 0.92, 0.11, 0.54};
createStorageImage(writeResource, textureBufferStorage, texture, kInitData);
constexpr std::array<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<uint32_t, 4> 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<float, 4> 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<uint32_t, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<float, 4> 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<MemoryBarrierVariationsTestParams>
{
protected:
MemoryBarrierBufferTest()
{
setWindowWidth(16);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
class MemoryBarrierImageTest : public MemoryBarrierTestBase,
public ANGLETestWithParam<MemoryBarrierVariationsTestParams>
{
protected:
MemoryBarrierImageTest()
{
setWindowWidth(16);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
class MemoryBarrierImageBufferOnlyTest
: public MemoryBarrierTestBase,
public ANGLETestWithParam<MemoryBarrierVariationsTestParams>
{
protected:
MemoryBarrierImageBufferOnlyTest()
{
setWindowWidth(16);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
class MemoryBarrierImageOnlyTest : public MemoryBarrierTestBase,
public ANGLETestWithParam<MemoryBarrierVariationsTestParams>
{
protected:
MemoryBarrierImageOnlyTest()
{
setWindowWidth(16);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
class MemoryBarrierBufferOnlyTest : public MemoryBarrierTestBase,
public ANGLETestWithParam<MemoryBarrierVariationsTestParams>
{
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