d3d11: enable DynamicBufferOffsetTests

This binds UAV slots all together at the same time.

Bug: dawn:1816
Bug: dawn:1705

Change-Id: Iea7af9cf00caf126a3964cc43bbf2162b35f80e0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132600
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
jchen10 2023-05-23 00:54:15 +00:00 committed by Dawn LUCI CQ
parent bfa1d3a870
commit cd1fb68767
15 changed files with 410 additions and 69 deletions

View File

@ -266,6 +266,7 @@ MaybeError DeviceBase::Initialize(Ref<QueueBase> defaultQueue) {
mState = State::Alive; mState = State::Alive;
DAWN_TRY_ASSIGN(mEmptyBindGroupLayout, CreateEmptyBindGroupLayout()); DAWN_TRY_ASSIGN(mEmptyBindGroupLayout, CreateEmptyBindGroupLayout());
DAWN_TRY_ASSIGN(mEmptyPipelineLayout, CreateEmptyPipelineLayout());
// If placeholder fragment shader module is needed, initialize it // If placeholder fragment shader module is needed, initialize it
if (IsToggleEnabled(Toggle::UsePlaceholderFragmentInVertexOnlyPipeline)) { if (IsToggleEnabled(Toggle::UsePlaceholderFragmentInVertexOnlyPipeline)) {
@ -481,6 +482,7 @@ void DeviceBase::Destroy() {
// Destroy() via APIGetQueue. // Destroy() via APIGetQueue.
mDynamicUploader = nullptr; mDynamicUploader = nullptr;
mEmptyBindGroupLayout = nullptr; mEmptyBindGroupLayout = nullptr;
mEmptyPipelineLayout = nullptr;
mInternalPipelineStore = nullptr; mInternalPipelineStore = nullptr;
mExternalTexturePlaceholderView = nullptr; mExternalTexturePlaceholderView = nullptr;
@ -850,11 +852,24 @@ ResultOrError<Ref<BindGroupLayoutBase>> DeviceBase::CreateEmptyBindGroupLayout()
return GetOrCreateBindGroupLayout(&desc); return GetOrCreateBindGroupLayout(&desc);
} }
ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreateEmptyPipelineLayout() {
PipelineLayoutDescriptor desc = {};
desc.bindGroupLayoutCount = 0;
desc.bindGroupLayouts = nullptr;
return GetOrCreatePipelineLayout(&desc);
}
BindGroupLayoutBase* DeviceBase::GetEmptyBindGroupLayout() { BindGroupLayoutBase* DeviceBase::GetEmptyBindGroupLayout() {
ASSERT(mEmptyBindGroupLayout != nullptr); ASSERT(mEmptyBindGroupLayout != nullptr);
return mEmptyBindGroupLayout.Get(); return mEmptyBindGroupLayout.Get();
} }
PipelineLayoutBase* DeviceBase::GetEmptyPipelineLayout() {
ASSERT(mEmptyPipelineLayout != nullptr);
return mEmptyPipelineLayout.Get();
}
Ref<ComputePipelineBase> DeviceBase::GetCachedComputePipeline( Ref<ComputePipelineBase> DeviceBase::GetCachedComputePipeline(
ComputePipelineBase* uninitializedComputePipeline) { ComputePipelineBase* uninitializedComputePipeline) {
Ref<ComputePipelineBase> cachedPipeline; Ref<ComputePipelineBase> cachedPipeline;

View File

@ -197,6 +197,7 @@ class DeviceBase : public RefCountedWithExternalCount {
void UncacheBindGroupLayout(BindGroupLayoutBase* obj); void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
BindGroupLayoutBase* GetEmptyBindGroupLayout(); BindGroupLayoutBase* GetEmptyBindGroupLayout();
PipelineLayoutBase* GetEmptyPipelineLayout();
void UncacheComputePipeline(ComputePipelineBase* obj); void UncacheComputePipeline(ComputePipelineBase* obj);
@ -506,6 +507,7 @@ class DeviceBase : public RefCountedWithExternalCount {
void FlushCallbackTaskQueue(); void FlushCallbackTaskQueue();
ResultOrError<Ref<BindGroupLayoutBase>> CreateEmptyBindGroupLayout(); ResultOrError<Ref<BindGroupLayoutBase>> CreateEmptyBindGroupLayout();
ResultOrError<Ref<PipelineLayoutBase>> CreateEmptyPipelineLayout();
Ref<ComputePipelineBase> GetCachedComputePipeline( Ref<ComputePipelineBase> GetCachedComputePipeline(
ComputePipelineBase* uninitializedComputePipeline); ComputePipelineBase* uninitializedComputePipeline);
@ -588,6 +590,7 @@ class DeviceBase : public RefCountedWithExternalCount {
std::unique_ptr<Caches> mCaches; std::unique_ptr<Caches> mCaches;
Ref<BindGroupLayoutBase> mEmptyBindGroupLayout; Ref<BindGroupLayoutBase> mEmptyBindGroupLayout;
Ref<PipelineLayoutBase> mEmptyPipelineLayout;
Ref<TextureViewBase> mExternalTexturePlaceholderView; Ref<TextureViewBase> mExternalTexturePlaceholderView;

View File

@ -14,6 +14,9 @@
#include "dawn/native/d3d11/BindGroupTrackerD3D11.h" #include "dawn/native/d3d11/BindGroupTrackerD3D11.h"
#include <utility>
#include <vector>
#include "dawn/common/Assert.h" #include "dawn/common/Assert.h"
#include "dawn/native/Format.h" #include "dawn/native/Format.h"
#include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d/D3DError.h"
@ -68,23 +71,64 @@ bool CheckAllSlotsAreEmpty(CommandRecordingContext* commandContext) {
ASSERT(sampler == nullptr); ASSERT(sampler == nullptr);
} }
// Check UAV slots // Check UAV slots for compute
for (UINT slot = 0; slot < D3D11_1_UAV_SLOT_COUNT; ++slot) { for (UINT slot = 0; slot < D3D11_1_UAV_SLOT_COUNT; ++slot) {
ID3D11UnorderedAccessView* uav = nullptr; ID3D11UnorderedAccessView* uav = nullptr;
deviceContext1->CSGetUnorderedAccessViews(slot, 1, &uav); deviceContext1->CSGetUnorderedAccessViews(slot, 1, &uav);
ASSERT(uav == nullptr); ASSERT(uav == nullptr);
} }
// Check UAV slots for render
for (UINT slot = 0; slot < commandContext->GetDevice()->GetUAVSlotCount(); ++slot) {
ID3D11UnorderedAccessView* uav = nullptr;
deviceContext1->OMGetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, slot, 1,
&uav);
ASSERT(uav == nullptr);
}
return true; return true;
} }
void ResetAllRenderSlots(CommandRecordingContext* commandContext) {
ID3D11DeviceContext1* deviceContext1 = commandContext->GetD3D11DeviceContext1();
// Reserve one slot for builtin constants.
constexpr uint32_t kReservedCBVSlots = 1;
ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {};
uint32_t num = D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - kReservedCBVSlots;
deviceContext1->VSSetConstantBuffers1(0, num, d3d11Buffers, nullptr, nullptr);
deviceContext1->PSSetConstantBuffers1(0, num, d3d11Buffers, nullptr, nullptr);
ID3D11ShaderResourceView* d3d11SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {};
num = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
deviceContext1->VSSetShaderResources(0, num, d3d11SRVs);
deviceContext1->PSSetShaderResources(0, num, d3d11SRVs);
ID3D11SamplerState* d3d11Samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {};
num = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
deviceContext1->VSSetSamplers(0, num, d3d11Samplers);
deviceContext1->PSSetSamplers(0, num, d3d11Samplers);
ID3D11UnorderedAccessView* d3d11UAVs[D3D11_1_UAV_SLOT_COUNT] = {};
num = commandContext->GetDevice()->GetUAVSlotCount();
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 0, num, d3d11UAVs, nullptr);
}
} // namespace } // namespace
BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext) BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass)
: mCommandContext(commandContext) {} : mCommandContext(commandContext),
mIsRenderPass(isRenderPass),
mVisibleStages(isRenderPass ? wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment
: wgpu::ShaderStage::Compute) {
mLastAppliedPipelineLayout = commandContext->GetDevice()->GetEmptyPipelineLayout();
}
BindGroupTracker::~BindGroupTracker() { BindGroupTracker::~BindGroupTracker() {
if (mLastAppliedPipelineLayout) { if (mIsRenderPass) {
ResetAllRenderSlots(mCommandContext);
} else {
for (BindGroupIndex index : for (BindGroupIndex index :
IterateBitSet(mLastAppliedPipelineLayout->GetBindGroupLayoutsMask())) { IterateBitSet(mLastAppliedPipelineLayout->GetBindGroupLayoutsMask())) {
UnApplyBindGroup(index); UnApplyBindGroup(index);
@ -97,15 +141,93 @@ BindGroupTracker::~BindGroupTracker() {
MaybeError BindGroupTracker::Apply() { MaybeError BindGroupTracker::Apply() {
BeforeApply(); BeforeApply();
// A resource cannot be bound as both input resource and UAV at the same time, so to avoid this if (mIsRenderPass) {
// conflict, we need to unbind groups which are not used by the new pipeline. and unbind groups // As D3d11 requires to bind all UAVs slots at the same time for pixel shaders, we record
// which are not inherited by the new pipeline. // all UAV slot assignments in the bind groups, and then bind them all together.
if (mLastAppliedPipelineLayout) { const BindGroupLayoutMask uavBindGroups =
BindGroupLayoutMask lastGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask(); ToBackend(mPipelineLayout)->GetUAVBindGroupLayoutsMask();
BindGroupLayoutMask currentGroups = mPipelineLayout->GetBindGroupLayoutsMask(); std::vector<ComPtr<ID3D11UnorderedAccessView>> d3d11UAVs;
BindGroupLayoutMask unApplyGroups = (mDirtyBindGroups | ~currentGroups) & lastGroups; for (BindGroupIndex index : IterateBitSet(uavBindGroups)) {
// Unset bind groups which are not used by the new pipeline and are not inherited. BindGroupBase* group = mBindGroups[index];
for (BindGroupIndex index : IterateBitSet(unApplyGroups)) { const ityp::vector<BindingIndex, uint64_t>& dynamicOffsets = mDynamicOffsets[index];
for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount();
++bindingIndex) {
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer: {
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
auto offset = binding.offset;
if (bindingInfo.buffer.hasDynamicOffset) {
// Dynamic buffers are packed at the front of BindingIndices.
offset += dynamicOffsets[bindingIndex];
}
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding: {
ASSERT(IsSubset(
bindingInfo.visibility,
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
->CreateD3D11UnorderedAccessView1(
offset, binding.size));
ToBackend(binding.buffer)->MarkMutated();
d3d11UAVs.insert(d3d11UAVs.begin(), std::move(d3d11UAV));
break;
}
case wgpu::BufferBindingType::Uniform:
case wgpu::BufferBindingType::ReadOnlyStorage:
case wgpu::BufferBindingType::Undefined: {
break;
}
}
break;
}
case BindingInfoType::StorageTexture: {
ASSERT(bindingInfo.storageTexture.access ==
wgpu::StorageTextureAccess::WriteOnly);
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView());
d3d11UAVs.insert(d3d11UAVs.begin(), std::move(d3d11UAV));
break;
}
case BindingInfoType::Texture:
case BindingInfoType::ExternalTexture:
case BindingInfoType::Sampler: {
break;
}
}
}
}
uint32_t uavSlotCount = ToBackend(mPipelineLayout->GetDevice())->GetUAVSlotCount();
std::vector<ID3D11UnorderedAccessView*> views;
for (auto& uav : d3d11UAVs) {
views.push_back(uav.Get());
}
mCommandContext->GetD3D11DeviceContext1()->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
uavSlotCount - d3d11UAVs.size(), d3d11UAVs.size(), views.data(), nullptr);
d3d11UAVs.clear();
} else {
BindGroupLayoutMask inheritedGroups =
mPipelineLayout->InheritedGroupsMask(mLastAppliedPipelineLayout);
BindGroupLayoutMask previousGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask();
// To avoid UAV / SRV conflicts with bindings in previously bind groups, we unset the bind
// groups that aren't reused by the current pipeline.
// We also need to unset the inherited bind groups which are dirty as the group may have
// both SRV and UAV, and the same resource may change its binding from UAV to SRV next
// dispatch in the same group.
//
// Note: WebGPU API guarantees that resources are not used both as UAV and SRV in the same
// render pass. So we don't need to do this inside render passes.
BindGroupLayoutMask groupsToUnset = previousGroups & (~inheritedGroups | mDirtyBindGroups);
for (BindGroupIndex index : IterateBitSet(groupsToUnset)) {
UnApplyBindGroup(index); UnApplyBindGroup(index);
} }
} }
@ -129,6 +251,7 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
++bindingIndex) { ++bindingIndex) {
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
const uint32_t bindingSlot = indices[bindingIndex]; const uint32_t bindingSlot = indices[bindingIndex];
const auto bindingVisibility = bindingInfo.visibility & mVisibleStages;
switch (bindingInfo.bindingType) { switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer: { case BindingInfoType::Buffer: {
@ -156,15 +279,15 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
DAWN_ASSERT(offset + numConstants * 16 <= DAWN_ASSERT(offset + numConstants * 16 <=
binding.buffer->GetAllocatedSize()); binding.buffer->GetAllocatedSize());
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
&firstConstant, &numConstants); &firstConstant, &numConstants);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
&firstConstant, &numConstants); &firstConstant, &numConstants);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
&firstConstant, &numConstants); &firstConstant, &numConstants);
} }
@ -174,17 +297,12 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
case kInternalStorageBufferBinding: { case kInternalStorageBufferBinding: {
ASSERT(IsSubset(bindingInfo.visibility, ASSERT(IsSubset(bindingInfo.visibility,
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute)); wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
ComPtr<ID3D11UnorderedAccessView> d3d11UAV; if (bindingVisibility & wgpu::ShaderStage::Compute) {
DAWN_TRY_ASSIGN( ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
d3d11UAV, ToBackend(binding.buffer) DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
->CreateD3D11UnorderedAccessView1(offset, binding.size)); ->CreateD3D11UnorderedAccessView1(
ToBackend(binding.buffer)->MarkMutated(); offset, binding.size));
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { ToBackend(binding.buffer)->MarkMutated();
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr);
}
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetUnorderedAccessViews( deviceContext1->CSSetUnorderedAccessViews(
bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr); bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr);
} }
@ -195,15 +313,15 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
DAWN_TRY_ASSIGN(d3d11SRV, DAWN_TRY_ASSIGN(d3d11SRV,
ToBackend(binding.buffer) ToBackend(binding.buffer)
->CreateD3D11ShaderResourceView(offset, binding.size)); ->CreateD3D11ShaderResourceView(offset, binding.size));
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetShaderResources(bindingSlot, 1, deviceContext1->VSSetShaderResources(bindingSlot, 1,
d3d11SRV.GetAddressOf()); d3d11SRV.GetAddressOf());
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetShaderResources(bindingSlot, 1, deviceContext1->PSSetShaderResources(bindingSlot, 1,
d3d11SRV.GetAddressOf()); d3d11SRV.GetAddressOf());
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetShaderResources(bindingSlot, 1, deviceContext1->CSSetShaderResources(bindingSlot, 1,
d3d11SRV.GetAddressOf()); d3d11SRV.GetAddressOf());
} }
@ -218,13 +336,13 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
case BindingInfoType::Sampler: { case BindingInfoType::Sampler: {
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState(); ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState();
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetSamplers(bindingSlot, 1, &d3d11SamplerState); deviceContext1->VSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetSamplers(bindingSlot, 1, &d3d11SamplerState); deviceContext1->PSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetSamplers(bindingSlot, 1, &d3d11SamplerState); deviceContext1->CSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
} }
break; break;
@ -234,13 +352,13 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex)); TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
ComPtr<ID3D11ShaderResourceView> srv; ComPtr<ID3D11ShaderResourceView> srv;
DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView()); DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); deviceContext1->PSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); deviceContext1->CSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
} }
break; break;
@ -248,15 +366,10 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
case BindingInfoType::StorageTexture: { case BindingInfoType::StorageTexture: {
ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly); ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly);
ComPtr<ID3D11UnorderedAccessView> d3d11UAV; if (bindingVisibility & wgpu::ShaderStage::Compute) {
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex)); ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView()); TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView());
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot,
1, d3d11UAV.GetAddressOf(), nullptr);
}
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1,
d3d11UAV.GetAddressOf(), nullptr); d3d11UAV.GetAddressOf(), nullptr);
} }
@ -280,21 +393,22 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
++bindingIndex) { ++bindingIndex) {
const BindingInfo& bindingInfo = groupLayout->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = groupLayout->GetBindingInfo(bindingIndex);
const uint32_t bindingSlot = indices[bindingIndex]; const uint32_t bindingSlot = indices[bindingIndex];
const auto bindingVisibility = bindingInfo.visibility & mVisibleStages;
switch (bindingInfo.bindingType) { switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer: { case BindingInfoType::Buffer: {
switch (bindingInfo.buffer.type) { switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform: { case wgpu::BufferBindingType::Uniform: {
ID3D11Buffer* nullBuffer = nullptr; ID3D11Buffer* nullBuffer = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
nullptr, nullptr); nullptr, nullptr);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
nullptr, nullptr); nullptr, nullptr);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
nullptr, nullptr); nullptr, nullptr);
} }
@ -305,12 +419,12 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
ASSERT(IsSubset(bindingInfo.visibility, ASSERT(IsSubset(bindingInfo.visibility,
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute)); wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
ID3D11UnorderedAccessView* nullUAV = nullptr; ID3D11UnorderedAccessView* nullUAV = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
bindingSlot, 1, &nullUAV, nullptr); bindingSlot, 1, &nullUAV, nullptr);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV,
nullptr); nullptr);
} }
@ -318,13 +432,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
} }
case wgpu::BufferBindingType::ReadOnlyStorage: { case wgpu::BufferBindingType::ReadOnlyStorage: {
ID3D11ShaderResourceView* nullSRV = nullptr; ID3D11ShaderResourceView* nullSRV = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
break; break;
@ -337,13 +451,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
case BindingInfoType::Sampler: { case BindingInfoType::Sampler: {
ID3D11SamplerState* nullSampler = nullptr; ID3D11SamplerState* nullSampler = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetSamplers(bindingSlot, 1, &nullSampler); deviceContext1->VSSetSamplers(bindingSlot, 1, &nullSampler);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetSamplers(bindingSlot, 1, &nullSampler); deviceContext1->PSSetSamplers(bindingSlot, 1, &nullSampler);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetSamplers(bindingSlot, 1, &nullSampler); deviceContext1->CSSetSamplers(bindingSlot, 1, &nullSampler);
} }
break; break;
@ -351,13 +465,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
case BindingInfoType::Texture: { case BindingInfoType::Texture: {
ID3D11ShaderResourceView* nullSRV = nullptr; ID3D11ShaderResourceView* nullSRV = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV); deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
} }
break; break;
@ -366,12 +480,12 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
case BindingInfoType::StorageTexture: { case BindingInfoType::StorageTexture: {
ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly); ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly);
ID3D11UnorderedAccessView* nullUAV = nullptr; ID3D11UnorderedAccessView* nullUAV = nullptr;
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { if (bindingVisibility & wgpu::ShaderStage::Fragment) {
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot, D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot,
1, &nullUAV, nullptr); 1, &nullUAV, nullptr);
} }
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { if (bindingVisibility & wgpu::ShaderStage::Compute) {
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, nullptr); deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, nullptr);
} }
break; break;

View File

@ -24,9 +24,9 @@ class CommandRecordingContext;
// We need convert WebGPU bind slot to d3d11 bind slot according a map in PipelineLayout, so we // We need convert WebGPU bind slot to d3d11 bind slot according a map in PipelineLayout, so we
// cannot inherit BindGroupTrackerGroups. // cannot inherit BindGroupTrackerGroups.
class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/false, uint64_t> { class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/true, uint64_t> {
public: public:
explicit BindGroupTracker(CommandRecordingContext* commandContext); BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass);
~BindGroupTracker(); ~BindGroupTracker();
MaybeError Apply(); MaybeError Apply();
@ -35,6 +35,8 @@ class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/fa
void UnApplyBindGroup(BindGroupIndex index); void UnApplyBindGroup(BindGroupIndex index);
CommandRecordingContext* const mCommandContext; CommandRecordingContext* const mCommandContext;
const bool mIsRenderPass;
const wgpu::ShaderStage mVisibleStages;
}; };
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -322,7 +322,7 @@ MaybeError CommandBuffer::Execute() {
MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) { MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) {
ComputePipeline* lastPipeline = nullptr; ComputePipeline* lastPipeline = nullptr;
BindGroupTracker bindGroupTracker(commandContext); BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/false);
Command type; Command type;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
@ -481,7 +481,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
d3d11DeviceContext1->RSSetScissorRects(1, &scissor); d3d11DeviceContext1->RSSetScissorRects(1, &scissor);
RenderPipeline* lastPipeline = nullptr; RenderPipeline* lastPipeline = nullptr;
BindGroupTracker bindGroupTracker(commandContext); BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/true);
VertexBufferTracker vertexBufferTracker(commandContext); VertexBufferTracker vertexBufferTracker(commandContext);
std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f}; std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f};
uint32_t stencilReference = 0; uint32_t stencilReference = 0;

View File

@ -30,6 +30,7 @@ namespace dawn::native::d3d11 {
MaybeError CommandRecordingContext::Open(Device* device) { MaybeError CommandRecordingContext::Open(Device* device) {
ASSERT(!IsOpen()); ASSERT(!IsOpen());
ASSERT(device); ASSERT(device);
mDevice = device;
if (!mD3D11DeviceContext4) { if (!mD3D11DeviceContext4) {
ID3D11Device* d3d11Device = device->GetD3D11Device(); ID3D11Device* d3d11Device = device->GetD3D11Device();
@ -106,11 +107,17 @@ Buffer* CommandRecordingContext::GetUniformBuffer() const {
return mUniformBuffer.Get(); return mUniformBuffer.Get();
} }
Device* CommandRecordingContext::GetDevice() const {
ASSERT(mDevice.Get());
return mDevice.Get();
}
void CommandRecordingContext::Release() { void CommandRecordingContext::Release() {
if (mIsOpen) { if (mIsOpen) {
mIsOpen = false; mIsOpen = false;
mNeedsSubmit = false; mNeedsSubmit = false;
mUniformBuffer = nullptr; mUniformBuffer = nullptr;
mDevice = nullptr;
ID3D11Buffer* nullBuffer = nullptr; ID3D11Buffer* nullBuffer = nullptr;
mD3D11DeviceContext4->VSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1, mD3D11DeviceContext4->VSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1,
&nullBuffer); &nullBuffer);

View File

@ -41,6 +41,7 @@ class CommandRecordingContext {
ID3D11DeviceContext4* GetD3D11DeviceContext4() const; ID3D11DeviceContext4* GetD3D11DeviceContext4() const;
ID3DUserDefinedAnnotation* GetD3DUserDefinedAnnotation() const; ID3DUserDefinedAnnotation* GetD3DUserDefinedAnnotation() const;
Buffer* GetUniformBuffer() const; Buffer* GetUniformBuffer() const;
Device* GetDevice() const;
private: private:
bool mIsOpen = false; bool mIsOpen = false;
@ -50,6 +51,7 @@ class CommandRecordingContext {
ComPtr<ID3DUserDefinedAnnotation> mD3D11UserDefinedAnnotation; ComPtr<ID3DUserDefinedAnnotation> mD3D11UserDefinedAnnotation;
// The uniform buffer for built in variables. // The uniform buffer for built in variables.
Ref<Buffer> mUniformBuffer; Ref<Buffer> mUniformBuffer;
Ref<Device> mDevice;
}; };
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -468,4 +468,8 @@ Ref<TextureBase> Device::CreateD3DExternalTexture(const TextureDescriptor* descr
return {dawnTexture}; return {dawnTexture};
} }
uint32_t Device::GetUAVSlotCount() const {
return ToBackend(GetPhysicalDevice())->GetUAVSlotCount();
}
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -83,6 +83,8 @@ class Device final : public d3d::Device {
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl( ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl(
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override; const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override;
uint32_t GetUAVSlotCount() const;
private: private:
using Base = d3d::Device; using Base = d3d::Device;
using Base::Base; using Base::Base;

View File

@ -147,6 +147,7 @@ MaybeError PhysicalDevice::InitializeSupportedLimitsImpl(CombinedLimits* limits)
uint32_t maxUAVsAllStages = mFeatureLevel == D3D_FEATURE_LEVEL_11_1 uint32_t maxUAVsAllStages = mFeatureLevel == D3D_FEATURE_LEVEL_11_1
? D3D11_1_UAV_SLOT_COUNT ? D3D11_1_UAV_SLOT_COUNT
: D3D11_PS_CS_UAV_REGISTER_COUNT; : D3D11_PS_CS_UAV_REGISTER_COUNT;
mUAVSlotCount = maxUAVsAllStages;
ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageTexturesPerShaderStage); ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageTexturesPerShaderStage);
ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageBuffersPerShaderStage); ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageBuffersPerShaderStage);
uint32_t maxUAVsPerStage = maxUAVsAllStages / 2; uint32_t maxUAVsPerStage = maxUAVsAllStages / 2;

View File

@ -37,6 +37,8 @@ class PhysicalDevice : public d3d::PhysicalDevice {
const DeviceInfo& GetDeviceInfo() const; const DeviceInfo& GetDeviceInfo() const;
ResultOrError<ComPtr<ID3D11Device>> CreateD3D11Device(); ResultOrError<ComPtr<ID3D11Device>> CreateD3D11Device();
uint32_t GetUAVSlotCount() const { return mUAVSlotCount; }
private: private:
using Base = d3d::PhysicalDevice; using Base = d3d::PhysicalDevice;
@ -57,6 +59,7 @@ class PhysicalDevice : public d3d::PhysicalDevice {
ComPtr<ID3D11Device> mD3d11Device; ComPtr<ID3D11Device> mD3d11Device;
D3D_FEATURE_LEVEL mFeatureLevel; D3D_FEATURE_LEVEL mFeatureLevel;
DeviceInfo mDeviceInfo = {}; DeviceInfo mDeviceInfo = {};
uint32_t mUAVSlotCount;
}; };
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -37,10 +37,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
// resource slots when being written out. So we assign UAV binding index decreasingly here. // resource slots when being written out. So we assign UAV binding index decreasingly here.
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-omsetrendertargetsandunorderedaccessviews // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-omsetrendertargetsandunorderedaccessviews
// TODO(dawn:1818): Support testing on both FL11_0 and FL11_1. // TODO(dawn:1818): Support testing on both FL11_0 and FL11_1.
uint32_t unorderedAccessViewIndex = uint32_t unorderedAccessViewIndex = device->GetUAVSlotCount();
device->GetD3D11Device()->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_1
? D3D11_1_UAV_SLOT_COUNT
: D3D11_PS_CS_UAV_REGISTER_COUNT;
mTotalUAVBindingCount = unorderedAccessViewIndex; mTotalUAVBindingCount = unorderedAccessViewIndex;
for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) { for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) {
@ -58,6 +55,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding: case kInternalStorageBufferBinding:
mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex; mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
mUAVBindGroups.set(group);
break; break;
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++; mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++;
@ -78,6 +76,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
case BindingInfoType::StorageTexture: case BindingInfoType::StorageTexture:
mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex; mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
mUAVBindGroups.set(group);
break; break;
} }
} }
@ -91,4 +90,8 @@ const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo() co
return mIndexInfo; return mIndexInfo;
} }
const BindGroupLayoutMask& PipelineLayout::GetUAVBindGroupLayoutsMask() const {
return mUAVBindGroups;
}
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -51,6 +51,9 @@ class PipelineLayout final : public PipelineLayoutBase {
uint32_t GetUnusedUAVBindingCount() const { return mUnusedUAVBindingCount; } uint32_t GetUnusedUAVBindingCount() const { return mUnusedUAVBindingCount; }
uint32_t GetTotalUAVBindingCount() const { return mTotalUAVBindingCount; } uint32_t GetTotalUAVBindingCount() const { return mTotalUAVBindingCount; }
// Get the bind groups that use one or more UAV slots.
const BindGroupLayoutMask& GetUAVBindGroupLayoutsMask() const;
private: private:
using PipelineLayoutBase::PipelineLayoutBase; using PipelineLayoutBase::PipelineLayoutBase;
@ -62,6 +65,7 @@ class PipelineLayout final : public PipelineLayoutBase {
uint32_t mUnusedUAVBindingCount = 0u; uint32_t mUnusedUAVBindingCount = 0u;
uint32_t mTotalUAVBindingCount = 0u; uint32_t mTotalUAVBindingCount = 0u;
BindGroupLayoutMask mUAVBindGroups = 0;
}; };
} // namespace dawn::native::d3d11 } // namespace dawn::native::d3d11

View File

@ -705,6 +705,91 @@ TEST_P(BindGroupTests, SetDynamicBindGroupBeforePipeline) {
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max); EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
} }
// Test that the same renderpass can use 3 more pipelines
TEST_P(BindGroupTests, ThreePipelinesInSameRenderpass) {
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
// Create a bind group layout which uses a single dynamic uniform buffer.
wgpu::BindGroupLayout uniformLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform, true}});
// Pipeline0 uses 2 bind groups, 'bindGroup00' and 'bindGroup01', respectively accommodated with
// 'color00' and 'color01'.
wgpu::RenderPipeline pipeline0 = MakeTestPipeline(
renderPass, {wgpu::BufferBindingType::Uniform, wgpu::BufferBindingType::Uniform},
{uniformLayout, uniformLayout});
// Pipeline1 uses 'bindGroup1', accommodated with 'color1'.
wgpu::RenderPipeline pipeline1 =
MakeTestPipeline(renderPass, {wgpu::BufferBindingType::Uniform}, {uniformLayout});
// Pipeline2 uses 'bindGroup2', accommodated with 'color2'.
wgpu::RenderPipeline pipeline2 =
MakeTestPipeline(renderPass, {wgpu::BufferBindingType::Uniform}, {uniformLayout});
// Sum up to (1, 1, 1, 1)
std::array<float, 4> color00 = {1, 0, 0, 0.5};
std::array<float, 4> color01 = {0, 1, 0, 0.5};
std::array<float, 4> color1 = {0, 0, 0.2, 0};
std::array<float, 4> color2 = {0, 0, 0.8, 0};
std::vector<uint8_t> data(sizeof(color00));
memcpy(data.data(), color00.data(), sizeof(color00));
wgpu::Buffer uniformBuffer00 =
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
wgpu::BindGroup bindGroup00 =
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer00, 0, 4 * sizeof(float)}});
memcpy(data.data(), color01.data(), sizeof(color01));
wgpu::Buffer uniformBuffer01 =
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
wgpu::BindGroup bindGroup01 =
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer01, 0, 4 * sizeof(float)}});
memcpy(data.data(), color1.data(), sizeof(color1));
wgpu::Buffer uniformBuffer1 =
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
wgpu::BindGroup bindGroup1 =
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer1, 0, 4 * sizeof(float)}});
memcpy(data.data(), color2.data(), sizeof(color2));
wgpu::Buffer uniformBuffer2 =
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
wgpu::BindGroup bindGroup2 =
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer2, 0, 4 * sizeof(float)}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
uint32_t dynamicOffset = 0;
pass.SetPipeline(pipeline0);
pass.SetBindGroup(0, bindGroup00, 1, &dynamicOffset);
pass.SetBindGroup(1, bindGroup01, 1, &dynamicOffset);
pass.Draw(3);
pass.SetBindGroup(0, bindGroup1, 1, &dynamicOffset);
pass.SetPipeline(pipeline1);
pass.Draw(3);
pass.SetBindGroup(0, bindGroup2, 1, &dynamicOffset);
pass.SetPipeline(pipeline2);
pass.Draw(3);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
utils::RGBA8 filled(255, 255, 255, 255);
utils::RGBA8 notFilled(0, 0, 0, 0);
uint32_t min = 1, max = kRTSize - 3;
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max);
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
}
// Test that bind groups set for one pipeline are still set when the pipeline changes. // Test that bind groups set for one pipeline are still set when the pipeline changes.
TEST_P(BindGroupTests, BindGroupsPersistAfterPipelineChange) { TEST_P(BindGroupTests, BindGroupsPersistAfterPipelineChange) {
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);

View File

@ -297,6 +297,101 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffsetsComputePipeline) {
mMinUniformBufferOffsetAlignment, expectedData.size()); mMinUniformBufferOffsetAlignment, expectedData.size());
} }
// Test basic inherit on render pipeline
TEST_P(DynamicBufferOffsetTests, BasicInheritRenderPipeline) {
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
@vertex
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4f {
var pos = array(
vec2f(-1.0, 0.0),
vec2f(-1.0, 1.0),
vec2f( 0.0, 1.0));
return vec4f(pos[VertexIndex], 0.0, 1.0);
})");
// Construct fragment shader source
std::ostringstream fs;
fs << R"(
struct Buf {
value : vec2u
}
@group(0) @binding(0) var<uniform> uBufferNotDynamic : Buf;
@group(0) @binding(1) var<storage, read_write> sBufferNotDynamic : Buf;
@group(1) @binding(3) var<uniform> uBuffer : Buf;
@group(1) @binding(4) var<storage, read_write> sBuffer : Buf;
@fragment fn main() -> @location(0) vec4f {
sBufferNotDynamic.value = uBufferNotDynamic.value.xy;
sBuffer.value = uBuffer.value.xy + uBufferNotDynamic.value.xy;
return vec4f(f32(uBuffer.value.x) / 255.0, f32(uBuffer.value.y) / 255.0,
1.0, 1.0);
}
)";
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fs.str().c_str());
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
wgpu::BindGroupLayout bindGroupLayouts[2];
bindGroupLayouts[0] = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
wgpu::BufferBindingType::Uniform},
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
wgpu::BufferBindingType::Storage}});
bindGroupLayouts[1] = utils::MakeBindGroupLayout(
device, {{3, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
wgpu::BufferBindingType::Uniform, true},
{4, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
wgpu::BufferBindingType::Storage, true}});
wgpu::BindGroup bindGroups[2];
bindGroups[0] = utils::MakeBindGroup(device, bindGroupLayouts[0],
{
{0, mUniformBuffers[0], 0, kBindingSize},
{1, mStorageBuffers[0], 0, kBindingSize},
});
bindGroups[1] = utils::MakeBindGroup(
device, bindGroupLayouts[1],
{{3, mUniformBuffers[1], 0, kBindingSize}, {4, mStorageBuffers[1], 0, kBindingSize}});
wgpu::PipelineLayoutDescriptor pipelineLayoutDescriptor;
pipelineLayoutDescriptor.bindGroupLayoutCount = 2;
pipelineLayoutDescriptor.bindGroupLayouts = bindGroupLayouts;
pipelineDescriptor.layout = device.CreatePipelineLayout(&pipelineLayoutDescriptor);
wgpu::RenderPipeline pipeline0 = device.CreateRenderPipeline(&pipelineDescriptor);
wgpu::RenderPipeline pipeline1 = device.CreateRenderPipeline(&pipelineDescriptor);
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
std::array<uint32_t, 2> offsets0 = {0, 0};
std::array<uint32_t, 2> offsets1 = {mMinUniformBufferOffsetAlignment,
mMinUniformBufferOffsetAlignment};
wgpu::RenderPassEncoder renderPassEncoder =
commandEncoder.BeginRenderPass(&renderPass.renderPassInfo);
renderPassEncoder.SetPipeline(pipeline0);
renderPassEncoder.SetBindGroup(0, bindGroups[0]);
renderPassEncoder.SetBindGroup(1, bindGroups[1], offsets0.size(), offsets0.data());
renderPassEncoder.Draw(3);
renderPassEncoder.SetPipeline(pipeline1);
// bind group 0 should be inherited and still available.
renderPassEncoder.SetBindGroup(1, bindGroups[1], offsets1.size(), offsets1.data());
renderPassEncoder.Draw(3);
renderPassEncoder.End();
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
std::vector<uint32_t> expectedData = {6, 8};
EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(5, 6, 255, 255), renderPass.color, 0, 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
mMinUniformBufferOffsetAlignment, expectedData.size());
}
// Test inherit dynamic offsets on render pipeline // Test inherit dynamic offsets on render pipeline
TEST_P(DynamicBufferOffsetTests, InheritDynamicOffsetsRenderPipeline) { TEST_P(DynamicBufferOffsetTests, InheritDynamicOffsetsRenderPipeline) {
// Using default pipeline and setting dynamic offsets // Using default pipeline and setting dynamic offsets
@ -576,6 +671,7 @@ TEST_P(ClampedOOBDynamicBufferOffsetTests, CheckOOBAccess) {
} }
DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests,
D3D11Backend(),
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
OpenGLBackend(), OpenGLBackend(),