Commit 8922ac23 by Enrico Galli Committed by Commit Bot

ES31: Enable glBindBufferRange on SSBOs in the D3D renderer

This patch enables binding a subset of a buffer with glBindBufferRange on the D3D renderer. Bug: angleproject:2990 Test: angle_end2end_tests Change-Id: Ib15b6257891191e28801f52c539b8b2daa80fa68 Reviewed-on: https://chromium-review.googlesource.com/c/1409880Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 0f073667
......@@ -177,7 +177,10 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
angle::Result getSRVForFormat(const gl::Context *context,
DXGI_FORMAT srvFormat,
const d3d11::ShaderResourceView **srvOut);
angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut);
angle::Result getRawUAV(const gl::Context *context,
unsigned int offset,
unsigned int size,
d3d11::UnorderedAccessView **uavOut);
private:
static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
......@@ -185,11 +188,12 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
BufferUsage usage,
unsigned int bufferSize);
void clearSRVs();
void clearUAVs();
d3d11::Buffer mBuffer;
const angle::Subject *mOnStorageChanged;
std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews;
d3d11::UnorderedAccessView mBufferRawUAV;
std::map<std::pair<unsigned int, unsigned int>, d3d11::UnorderedAccessView> mBufferRawUAVs;
};
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
......@@ -692,7 +696,10 @@ angle::Result Buffer11::getConstantBufferRange(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result Buffer11::getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut)
angle::Result Buffer11::getRawUAVRange(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
d3d11::UnorderedAccessView **uavOut)
{
NativeStorage *nativeStorage = nullptr;
ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage));
......@@ -705,7 +712,8 @@ angle::Result Buffer11::getRawUAV(const gl::Context *context, d3d11::UnorderedAc
onStorageUpdate(nativeStorage);
}
return nativeStorage->getRawUAV(context, uavOut);
return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset),
static_cast<unsigned int>(size), uavOut);
}
angle::Result Buffer11::getSRV(const gl::Context *context,
......@@ -1006,6 +1014,7 @@ Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
Buffer11::NativeStorage::~NativeStorage()
{
clearSRVs();
clearUAVs();
}
bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
......@@ -1133,6 +1142,9 @@ angle::Result Buffer11::NativeStorage::resize(const gl::Context *context,
// Free the SRVs.
clearSRVs();
// Free the UAVs.
clearUAVs();
// Notify that the storage has changed.
if (mOnStorageChanged)
{
......@@ -1273,26 +1285,33 @@ angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *contex
}
angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context,
unsigned int offset,
unsigned int size,
d3d11::UnorderedAccessView **uavOut)
{
if (mBufferRawUAV.get())
ASSERT(offset + size <= mBufferSize);
auto bufferRawUAV = mBufferRawUAVs.find({offset, size});
if (bufferRawUAV != mBufferRawUAVs.end())
{
*uavOut = &mBufferRawUAV;
*uavOut = &bufferRawUAV->second;
return angle::Result::Continue;
}
D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc;
bufferUAVDesc.Buffer.FirstElement = 0;
bufferUAVDesc.Buffer.NumElements = mBufferSize / 4;
// DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element
constexpr int kBytesToElement = 4;
bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement;
bufferUAVDesc.Buffer.NumElements = size / kBytesToElement;
bufferUAVDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS,
// when creating Raw Unordered Access View
bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc,
mBuffer.get(), &mBufferRawUAV));
*uavOut = &mBufferRawUAV;
mBuffer.get(), &mBufferRawUAVs[{offset, size}]));
*uavOut = &mBufferRawUAVs[{offset, size}];
return angle::Result::Continue;
}
......@@ -1301,6 +1320,11 @@ void Buffer11::NativeStorage::clearSRVs()
mBufferResourceViews.clear();
}
void Buffer11::NativeStorage::clearUAVs()
{
mBufferRawUAVs.clear();
}
// Buffer11::EmulatedIndexStorage implementation
Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
......
......@@ -70,7 +70,11 @@ class Buffer11 : public BufferD3D
angle::Result getSRV(const gl::Context *context,
DXGI_FORMAT srvFormat,
const d3d11::ShaderResourceView **srvOut);
angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut);
angle::Result getRawUAVRange(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
d3d11::UnorderedAccessView **uavOut);
bool isMapped() const { return mMappedStorage != nullptr; }
angle::Result packPixels(const gl::Context *context,
const gl::FramebufferAttachment &readAttachment,
......@@ -132,6 +136,9 @@ class Buffer11 : public BufferD3D
size_t sourceOffset,
size_t storageSize);
angle::Result getNativeStorageForUAV(const gl::Context *context,
Buffer11::NativeStorage **storageOut);
template <typename StorageOutT>
angle::Result getBufferStorage(const gl::Context *context,
BufferUsage usage,
......
......@@ -3585,6 +3585,7 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex
{
const gl::State &glState = context->getState();
const gl::Program *program = glState.getProgram();
angle::FixedVector<Buffer11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> previouslyBound;
for (size_t blockIndex = 0; blockIndex < program->getActiveShaderStorageBlockCount();
blockIndex++)
{
......@@ -3595,10 +3596,31 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex
continue;
}
Buffer11 *bufferStorage = GetImplAs<Buffer11>(shaderStorageBuffer.get());
Buffer11 *bufferStorage = GetImplAs<Buffer11>(shaderStorageBuffer.get());
if (std::find(previouslyBound.begin(), previouslyBound.end(), bufferStorage) !=
previouslyBound.end())
{
// D3D11 doesn't support binding a buffer multiple times
// http://anglebug.com/3032
ERR() << "Writing to multiple blocks on the same buffer is not allowed.";
return angle::Result::Stop;
}
previouslyBound.push_back(bufferStorage);
d3d11::UnorderedAccessView *uavPtr = nullptr;
// TODO(jiajia.qin@intel.com): add buffer offset support. http://anglebug.com/1951
ANGLE_TRY(bufferStorage->getRawUAV(context, &uavPtr));
GLsizeiptr viewSize = 0;
// Bindings only have a valid size if bound using glBindBufferRange
if (shaderStorageBuffer.getSize() > 0)
{
viewSize = shaderStorageBuffer.getSize();
}
// We use the buffer size for glBindBufferBase
else
{
viewSize = bufferStorage->getSize();
}
ANGLE_TRY(bufferStorage->getRawUAVRange(context, shaderStorageBuffer.getOffset(), viewSize,
&uavPtr));
// We need to make sure that resource being set to UnorderedAccessView slot |registerIndex|
// is not bound on SRV.
......
......@@ -404,6 +404,82 @@ void main()
EXPECT_GL_NO_ERROR();
}
// Tests reading and writing to a shader storage buffer bound at an offset.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteOffset)
{
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(std140, binding = 0) buffer block0 {
uint data[2];
} instance0;
void main()
{
instance0.data[0] = 3u;
instance0.data[1] = 4u;
}
)";
ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
glUseProgram(program);
constexpr unsigned int kElementCount = 2;
// The array stride are rounded up to the base alignment of a vec4 for std140 layout.
constexpr unsigned int kArrayStride = 16;
// Create shader storage buffer
GLBuffer shaderStorageBuffer;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
int bufferAlignOffset;
glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bufferAlignOffset);
constexpr int kBufferSize = kElementCount * kArrayStride;
const int kBufferOffset = kBufferSize + (kBufferSize % bufferAlignOffset);
glBufferData(GL_SHADER_STORAGE_BUFFER, kBufferOffset + kBufferSize, nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer at an offset
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer, kBufferOffset, kBufferSize);
EXPECT_GL_NO_ERROR();
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
// Bind the buffer at a separate location
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer, 0, kBufferSize);
EXPECT_GL_NO_ERROR();
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
// Read back shader storage buffer
constexpr unsigned int kExpectedValues[2] = {3u, 4u};
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT);
for (unsigned int idx = 0; idx < kElementCount; idx++)
{
EXPECT_EQ(kExpectedValues[idx],
*(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
idx * kArrayStride)));
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, kBufferOffset, kBufferSize, GL_MAP_READ_BIT);
for (unsigned int idx = 0; idx < kElementCount; idx++)
{
EXPECT_EQ(kExpectedValues[idx],
*(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
idx * kArrayStride)));
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
EXPECT_GL_NO_ERROR();
}
// Test that access/write to vector data in shader storage buffer.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferVector)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment