Dynamic Buffer Offset : OpenGL Backend

In a typical graphics application it is a common usage to update some uniforms once per draw,
and such uniforms include the word positions, orientations, and so on. In the current state of
WebGPU, this means that for each draw call we have to create a new bind group to set the right
uniform values. Bind group creation is expected to be more expensive than
recording draws because a memory allocation is required.

The functionality of dynamic buffer offset is to reduce the number of bind groups that need to
be created.

The patch implements dynamic buffer offset on OpenGL backend using glBindBufferRange and adds
validation to check whether visibility of resources are none.

Bug=dawn:55

Change-Id: I77e10a9677d1737f377301ee89e29d904c91c298
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9540
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
Yan, Shaobo 2019-07-30 01:21:19 +00:00 committed by Commit Bot service account
parent 7dec2d1c56
commit 34f8bd8c48
4 changed files with 51 additions and 7 deletions

View File

@ -42,6 +42,10 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("some binding index was specified more than once");
}
if (binding.visibility == dawn::ShaderStageBit::None) {
return DAWN_VALIDATION_ERROR("Visibility of bindings can't be None");
}
switch (binding.type) {
case dawn::BindingType::UniformBuffer:
case dawn::BindingType::StorageBuffer:

View File

@ -220,9 +220,12 @@ namespace dawn_native { namespace opengl {
uint32_t index,
BindGroupBase* group,
PipelineLayout* pipelineLayout,
PipelineGL* pipeline) {
PipelineGL* pipeline,
uint32_t dynamicOffsetCount,
uint64_t* dynamicOffsets) {
const auto& indices = pipelineLayout->GetBindingIndexInfo()[index];
const auto& layout = group->GetLayout()->GetBindingInfo();
uint32_t currentDynamicIndex = 0;
for (uint32_t bindingIndex : IterateBitSet(layout.mask)) {
switch (layout.types[bindingIndex]) {
@ -230,8 +233,14 @@ namespace dawn_native { namespace opengl {
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint uboIndex = indices[bindingIndex];
GLuint offset = binding.offset;
gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, binding.offset,
if (layout.dynamic[bindingIndex]) {
offset += dynamicOffsets[currentDynamicIndex];
++currentDynamicIndex;
}
gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, offset,
binding.size);
} break;
@ -261,9 +270,15 @@ namespace dawn_native { namespace opengl {
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint ssboIndex = indices[bindingIndex];
GLuint offset = binding.offset;
gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer,
binding.offset, binding.size);
if (layout.dynamic[bindingIndex]) {
offset += dynamicOffsets[currentDynamicIndex];
++currentDynamicIndex;
}
gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer, offset,
binding.size);
} break;
case dawn::BindingType::StorageTexture:
@ -555,8 +570,13 @@ namespace dawn_native { namespace opengl {
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
uint64_t* dynamicOffsets = nullptr;
if (cmd->dynamicOffsetCount > 0) {
dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
}
ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline);
ToBackend(lastPipeline->GetLayout()), lastPipeline,
cmd->dynamicOffsetCount, dynamicOffsets);
} break;
default: { UNREACHABLE(); } break;
@ -830,8 +850,13 @@ namespace dawn_native { namespace opengl {
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
uint64_t* dynamicOffsets = nullptr;
if (cmd->dynamicOffsetCount > 0) {
dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
}
ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline);
ToBackend(lastPipeline->GetLayout()), lastPipeline,
cmd->dynamicOffsetCount, dynamicOffsets);
} break;
case Command::SetIndexBuffer: {

View File

@ -212,4 +212,4 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsComputePipeline) {
kMinDynamicBufferOffsetAlignment, expectedData.size());
}
DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, MetalBackend, VulkanBackend);
DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, MetalBackend, OpenGLBackend, VulkanBackend);

View File

@ -472,6 +472,21 @@ TEST_F(BindGroupLayoutValidationTest, BindGroupLayoutCache) {
ASSERT_EQ(layout1.Get(), layout2.Get());
}
// This test verifies that visibility of bindings in BindGroupLayout can't be none
TEST_F(BindGroupLayoutValidationTest, BindGroupLayoutVisibilityNone) {
utils::MakeBindGroupLayout(
device, {
{0, dawn::ShaderStageBit::Vertex, dawn::BindingType::UniformBuffer},
});
dawn::BindGroupLayoutBinding binding = {0, dawn::ShaderStageBit::None,
dawn::BindingType::UniformBuffer};
dawn::BindGroupLayoutDescriptor descriptor;
descriptor.bindingCount = 1;
descriptor.bindings = &binding;
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor));
}
constexpr uint64_t kBufferSize = 2 * kMinDynamicBufferOffsetAlignment + 8;
constexpr uint32_t kBindingSize = 9;