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>
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index 011242e..8d306fd 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp
@@ -266,6 +266,7 @@ mState = State::Alive; DAWN_TRY_ASSIGN(mEmptyBindGroupLayout, CreateEmptyBindGroupLayout()); + DAWN_TRY_ASSIGN(mEmptyPipelineLayout, CreateEmptyPipelineLayout()); // If placeholder fragment shader module is needed, initialize it if (IsToggleEnabled(Toggle::UsePlaceholderFragmentInVertexOnlyPipeline)) { @@ -481,6 +482,7 @@ // Destroy() via APIGetQueue. mDynamicUploader = nullptr; mEmptyBindGroupLayout = nullptr; + mEmptyPipelineLayout = nullptr; mInternalPipelineStore = nullptr; mExternalTexturePlaceholderView = nullptr; @@ -850,11 +852,24 @@ return GetOrCreateBindGroupLayout(&desc); } +ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreateEmptyPipelineLayout() { + PipelineLayoutDescriptor desc = {}; + desc.bindGroupLayoutCount = 0; + desc.bindGroupLayouts = nullptr; + + return GetOrCreatePipelineLayout(&desc); +} + BindGroupLayoutBase* DeviceBase::GetEmptyBindGroupLayout() { ASSERT(mEmptyBindGroupLayout != nullptr); return mEmptyBindGroupLayout.Get(); } +PipelineLayoutBase* DeviceBase::GetEmptyPipelineLayout() { + ASSERT(mEmptyPipelineLayout != nullptr); + return mEmptyPipelineLayout.Get(); +} + Ref<ComputePipelineBase> DeviceBase::GetCachedComputePipeline( ComputePipelineBase* uninitializedComputePipeline) { Ref<ComputePipelineBase> cachedPipeline;
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h index e7c8bb5..3643566 100644 --- a/src/dawn/native/Device.h +++ b/src/dawn/native/Device.h
@@ -197,6 +197,7 @@ void UncacheBindGroupLayout(BindGroupLayoutBase* obj); BindGroupLayoutBase* GetEmptyBindGroupLayout(); + PipelineLayoutBase* GetEmptyPipelineLayout(); void UncacheComputePipeline(ComputePipelineBase* obj); @@ -506,6 +507,7 @@ void FlushCallbackTaskQueue(); ResultOrError<Ref<BindGroupLayoutBase>> CreateEmptyBindGroupLayout(); + ResultOrError<Ref<PipelineLayoutBase>> CreateEmptyPipelineLayout(); Ref<ComputePipelineBase> GetCachedComputePipeline( ComputePipelineBase* uninitializedComputePipeline); @@ -588,6 +590,7 @@ std::unique_ptr<Caches> mCaches; Ref<BindGroupLayoutBase> mEmptyBindGroupLayout; + Ref<PipelineLayoutBase> mEmptyPipelineLayout; Ref<TextureViewBase> mExternalTexturePlaceholderView;
diff --git a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp index d7be5c0..879e5ae 100644 --- a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp +++ b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
@@ -14,6 +14,9 @@ #include "dawn/native/d3d11/BindGroupTrackerD3D11.h" +#include <utility> +#include <vector> + #include "dawn/common/Assert.h" #include "dawn/native/Format.h" #include "dawn/native/d3d/D3DError.h" @@ -68,23 +71,64 @@ ASSERT(sampler == nullptr); } - // Check UAV slots + // Check UAV slots for compute for (UINT slot = 0; slot < D3D11_1_UAV_SLOT_COUNT; ++slot) { ID3D11UnorderedAccessView* uav = nullptr; deviceContext1->CSGetUnorderedAccessViews(slot, 1, &uav); 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; } +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 -BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext) - : mCommandContext(commandContext) {} +BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass) + : mCommandContext(commandContext), + mIsRenderPass(isRenderPass), + mVisibleStages(isRenderPass ? wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment + : wgpu::ShaderStage::Compute) { + mLastAppliedPipelineLayout = commandContext->GetDevice()->GetEmptyPipelineLayout(); +} BindGroupTracker::~BindGroupTracker() { - if (mLastAppliedPipelineLayout) { + if (mIsRenderPass) { + ResetAllRenderSlots(mCommandContext); + } else { for (BindGroupIndex index : IterateBitSet(mLastAppliedPipelineLayout->GetBindGroupLayoutsMask())) { UnApplyBindGroup(index); @@ -97,15 +141,93 @@ MaybeError BindGroupTracker::Apply() { BeforeApply(); - // A resource cannot be bound as both input resource and UAV at the same time, so to avoid this - // conflict, we need to unbind groups which are not used by the new pipeline. and unbind groups - // which are not inherited by the new pipeline. - if (mLastAppliedPipelineLayout) { - BindGroupLayoutMask lastGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask(); - BindGroupLayoutMask currentGroups = mPipelineLayout->GetBindGroupLayoutsMask(); - BindGroupLayoutMask unApplyGroups = (mDirtyBindGroups | ~currentGroups) & lastGroups; - // Unset bind groups which are not used by the new pipeline and are not inherited. - for (BindGroupIndex index : IterateBitSet(unApplyGroups)) { + if (mIsRenderPass) { + // As D3d11 requires to bind all UAVs slots at the same time for pixel shaders, we record + // all UAV slot assignments in the bind groups, and then bind them all together. + const BindGroupLayoutMask uavBindGroups = + ToBackend(mPipelineLayout)->GetUAVBindGroupLayoutsMask(); + std::vector<ComPtr<ID3D11UnorderedAccessView>> d3d11UAVs; + for (BindGroupIndex index : IterateBitSet(uavBindGroups)) { + BindGroupBase* group = mBindGroups[index]; + 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); } } @@ -129,6 +251,7 @@ ++bindingIndex) { const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex); const uint32_t bindingSlot = indices[bindingIndex]; + const auto bindingVisibility = bindingInfo.visibility & mVisibleStages; switch (bindingInfo.bindingType) { case BindingInfoType::Buffer: { @@ -156,15 +279,15 @@ DAWN_ASSERT(offset + numConstants * 16 <= binding.buffer->GetAllocatedSize()); - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, &firstConstant, &numConstants); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, &firstConstant, &numConstants); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer, &firstConstant, &numConstants); } @@ -174,17 +297,12 @@ 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(); - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { - deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( - D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, - bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr); - } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { + ComPtr<ID3D11UnorderedAccessView> d3d11UAV; + DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer) + ->CreateD3D11UnorderedAccessView1( + offset, binding.size)); + ToBackend(binding.buffer)->MarkMutated(); deviceContext1->CSSetUnorderedAccessViews( bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr); } @@ -195,15 +313,15 @@ DAWN_TRY_ASSIGN(d3d11SRV, ToBackend(binding.buffer) ->CreateD3D11ShaderResourceView(offset, binding.size)); - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetShaderResources(bindingSlot, 1, d3d11SRV.GetAddressOf()); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetShaderResources(bindingSlot, 1, d3d11SRV.GetAddressOf()); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetShaderResources(bindingSlot, 1, d3d11SRV.GetAddressOf()); } @@ -218,13 +336,13 @@ case BindingInfoType::Sampler: { Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState(); - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetSamplers(bindingSlot, 1, &d3d11SamplerState); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetSamplers(bindingSlot, 1, &d3d11SamplerState); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetSamplers(bindingSlot, 1, &d3d11SamplerState); } break; @@ -234,13 +352,13 @@ TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex)); ComPtr<ID3D11ShaderResourceView> srv; DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView()); - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetShaderResources(bindingSlot, 1, srv.GetAddressOf()); } break; @@ -248,15 +366,10 @@ 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()); - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { - deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( - D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot, - 1, d3d11UAV.GetAddressOf(), nullptr); - } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { + ComPtr<ID3D11UnorderedAccessView> d3d11UAV; + TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex)); + DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView()); deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr); } @@ -280,21 +393,22 @@ ++bindingIndex) { const BindingInfo& bindingInfo = groupLayout->GetBindingInfo(bindingIndex); const uint32_t bindingSlot = indices[bindingIndex]; + const auto bindingVisibility = bindingInfo.visibility & mVisibleStages; switch (bindingInfo.bindingType) { case BindingInfoType::Buffer: { switch (bindingInfo.buffer.type) { case wgpu::BufferBindingType::Uniform: { ID3D11Buffer* nullBuffer = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, nullptr, nullptr); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, nullptr, nullptr); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &nullBuffer, nullptr, nullptr); } @@ -305,12 +419,12 @@ ASSERT(IsSubset(bindingInfo.visibility, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute)); ID3D11UnorderedAccessView* nullUAV = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot, 1, &nullUAV, nullptr); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, nullptr); } @@ -318,13 +432,13 @@ } case wgpu::BufferBindingType::ReadOnlyStorage: { ID3D11ShaderResourceView* nullSRV = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV); } break; @@ -337,13 +451,13 @@ case BindingInfoType::Sampler: { ID3D11SamplerState* nullSampler = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetSamplers(bindingSlot, 1, &nullSampler); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetSamplers(bindingSlot, 1, &nullSampler); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetSamplers(bindingSlot, 1, &nullSampler); } break; @@ -351,13 +465,13 @@ case BindingInfoType::Texture: { ID3D11ShaderResourceView* nullSRV = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) { + if (bindingVisibility & wgpu::ShaderStage::Vertex) { deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV); } - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV); } break; @@ -366,12 +480,12 @@ case BindingInfoType::StorageTexture: { ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly); ID3D11UnorderedAccessView* nullUAV = nullptr; - if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) { + if (bindingVisibility & wgpu::ShaderStage::Fragment) { deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews( D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot, 1, &nullUAV, nullptr); } - if (bindingInfo.visibility & wgpu::ShaderStage::Compute) { + if (bindingVisibility & wgpu::ShaderStage::Compute) { deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, nullptr); } break;
diff --git a/src/dawn/native/d3d11/BindGroupTrackerD3D11.h b/src/dawn/native/d3d11/BindGroupTrackerD3D11.h index 7e8181b..719249d 100644 --- a/src/dawn/native/d3d11/BindGroupTrackerD3D11.h +++ b/src/dawn/native/d3d11/BindGroupTrackerD3D11.h
@@ -24,9 +24,9 @@ // We need convert WebGPU bind slot to d3d11 bind slot according a map in PipelineLayout, so we // cannot inherit BindGroupTrackerGroups. -class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/false, uint64_t> { +class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/true, uint64_t> { public: - explicit BindGroupTracker(CommandRecordingContext* commandContext); + BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass); ~BindGroupTracker(); MaybeError Apply(); @@ -35,6 +35,8 @@ void UnApplyBindGroup(BindGroupIndex index); CommandRecordingContext* const mCommandContext; + const bool mIsRenderPass; + const wgpu::ShaderStage mVisibleStages; }; } // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp index 82e87cf..ad21732 100644 --- a/src/dawn/native/d3d11/CommandBufferD3D11.cpp +++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
@@ -322,7 +322,7 @@ MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) { ComputePipeline* lastPipeline = nullptr; - BindGroupTracker bindGroupTracker(commandContext); + BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/false); Command type; while (mCommands.NextCommandId(&type)) { @@ -481,7 +481,7 @@ d3d11DeviceContext1->RSSetScissorRects(1, &scissor); RenderPipeline* lastPipeline = nullptr; - BindGroupTracker bindGroupTracker(commandContext); + BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/true); VertexBufferTracker vertexBufferTracker(commandContext); std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f}; uint32_t stencilReference = 0;
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp index a7a3c76..055b2ba 100644 --- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp +++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
@@ -30,6 +30,7 @@ MaybeError CommandRecordingContext::Open(Device* device) { ASSERT(!IsOpen()); ASSERT(device); + mDevice = device; if (!mD3D11DeviceContext4) { ID3D11Device* d3d11Device = device->GetD3D11Device(); @@ -106,11 +107,17 @@ return mUniformBuffer.Get(); } +Device* CommandRecordingContext::GetDevice() const { + ASSERT(mDevice.Get()); + return mDevice.Get(); +} + void CommandRecordingContext::Release() { if (mIsOpen) { mIsOpen = false; mNeedsSubmit = false; mUniformBuffer = nullptr; + mDevice = nullptr; ID3D11Buffer* nullBuffer = nullptr; mD3D11DeviceContext4->VSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1, &nullBuffer);
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h index 4cdc58b..c3d2623 100644 --- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h +++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
@@ -41,6 +41,7 @@ ID3D11DeviceContext4* GetD3D11DeviceContext4() const; ID3DUserDefinedAnnotation* GetD3DUserDefinedAnnotation() const; Buffer* GetUniformBuffer() const; + Device* GetDevice() const; private: bool mIsOpen = false; @@ -50,6 +51,7 @@ ComPtr<ID3DUserDefinedAnnotation> mD3D11UserDefinedAnnotation; // The uniform buffer for built in variables. Ref<Buffer> mUniformBuffer; + Ref<Device> mDevice; }; } // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/DeviceD3D11.cpp b/src/dawn/native/d3d11/DeviceD3D11.cpp index 941002e..d724920 100644 --- a/src/dawn/native/d3d11/DeviceD3D11.cpp +++ b/src/dawn/native/d3d11/DeviceD3D11.cpp
@@ -468,4 +468,8 @@ return {dawnTexture}; } +uint32_t Device::GetUAVSlotCount() const { + return ToBackend(GetPhysicalDevice())->GetUAVSlotCount(); +} + } // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/DeviceD3D11.h b/src/dawn/native/d3d11/DeviceD3D11.h index 0ab13a7..4753d56 100644 --- a/src/dawn/native/d3d11/DeviceD3D11.h +++ b/src/dawn/native/d3d11/DeviceD3D11.h
@@ -83,6 +83,8 @@ ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl( const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override; + uint32_t GetUAVSlotCount() const; + private: using Base = d3d::Device; using Base::Base;
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp index 8903ad8..95e6e4f 100644 --- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp +++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
@@ -147,6 +147,7 @@ uint32_t maxUAVsAllStages = mFeatureLevel == D3D_FEATURE_LEVEL_11_1 ? D3D11_1_UAV_SLOT_COUNT : D3D11_PS_CS_UAV_REGISTER_COUNT; + mUAVSlotCount = maxUAVsAllStages; ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageTexturesPerShaderStage); ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageBuffersPerShaderStage); uint32_t maxUAVsPerStage = maxUAVsAllStages / 2;
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h index 5cadee9..be10f59 100644 --- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h +++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
@@ -37,6 +37,8 @@ const DeviceInfo& GetDeviceInfo() const; ResultOrError<ComPtr<ID3D11Device>> CreateD3D11Device(); + uint32_t GetUAVSlotCount() const { return mUAVSlotCount; } + private: using Base = d3d::PhysicalDevice; @@ -57,6 +59,7 @@ ComPtr<ID3D11Device> mD3d11Device; D3D_FEATURE_LEVEL mFeatureLevel; DeviceInfo mDeviceInfo = {}; + uint32_t mUAVSlotCount; }; } // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp index a8e18c6..f9e9462 100644 --- a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp +++ b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
@@ -37,10 +37,7 @@ // 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 // TODO(dawn:1818): Support testing on both FL11_0 and FL11_1. - uint32_t unorderedAccessViewIndex = - device->GetD3D11Device()->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_1 - ? D3D11_1_UAV_SLOT_COUNT - : D3D11_PS_CS_UAV_REGISTER_COUNT; + uint32_t unorderedAccessViewIndex = device->GetUAVSlotCount(); mTotalUAVBindingCount = unorderedAccessViewIndex; for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) { @@ -58,6 +55,7 @@ case wgpu::BufferBindingType::Storage: case kInternalStorageBufferBinding: mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex; + mUAVBindGroups.set(group); break; case wgpu::BufferBindingType::ReadOnlyStorage: mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++; @@ -78,6 +76,7 @@ case BindingInfoType::StorageTexture: mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex; + mUAVBindGroups.set(group); break; } } @@ -91,4 +90,8 @@ return mIndexInfo; } +const BindGroupLayoutMask& PipelineLayout::GetUAVBindGroupLayoutsMask() const { + return mUAVBindGroups; +} + } // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/PipelineLayoutD3D11.h b/src/dawn/native/d3d11/PipelineLayoutD3D11.h index d25f7fa..6f6349c 100644 --- a/src/dawn/native/d3d11/PipelineLayoutD3D11.h +++ b/src/dawn/native/d3d11/PipelineLayoutD3D11.h
@@ -51,6 +51,9 @@ uint32_t GetUnusedUAVBindingCount() const { return mUnusedUAVBindingCount; } uint32_t GetTotalUAVBindingCount() const { return mTotalUAVBindingCount; } + // Get the bind groups that use one or more UAV slots. + const BindGroupLayoutMask& GetUAVBindGroupLayoutsMask() const; + private: using PipelineLayoutBase::PipelineLayoutBase; @@ -62,6 +65,7 @@ uint32_t mUnusedUAVBindingCount = 0u; uint32_t mTotalUAVBindingCount = 0u; + BindGroupLayoutMask mUAVBindGroups = 0; }; } // namespace dawn::native::d3d11
diff --git a/src/dawn/tests/end2end/BindGroupTests.cpp b/src/dawn/tests/end2end/BindGroupTests.cpp index d01089a..e46da6a 100644 --- a/src/dawn/tests/end2end/BindGroupTests.cpp +++ b/src/dawn/tests/end2end/BindGroupTests.cpp
@@ -705,6 +705,91 @@ 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_P(BindGroupTests, BindGroupsPersistAfterPipelineChange) { utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
diff --git a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp index 53d9d9b..63abeaf 100644 --- a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp +++ b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
@@ -297,6 +297,101 @@ 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_P(DynamicBufferOffsetTests, InheritDynamicOffsetsRenderPipeline) { // Using default pipeline and setting dynamic offsets @@ -576,6 +671,7 @@ } DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, + D3D11Backend(), D3D12Backend(), MetalBackend(), OpenGLBackend(),