diff --git a/AnKi/Gr/Common.h b/AnKi/Gr/Common.h index 1ab9f85b7..944ce2b7f 100644 --- a/AnKi/Gr/Common.h +++ b/AnKi/Gr/Common.h @@ -764,6 +764,7 @@ enum class BufferUsageBit : U64 | kIndirectTraceRays | kTransferSource | kAccelerationStructureBuild | kShaderBindingTable, kAllWrite = kStorageGeometryWrite | kStorageFragmentWrite | kStorageComputeWrite | kStorageTraceRaysWrite | kTexelGeometryWrite | kTexelFragmentWrite | kTexelComputeWrite | kTexelTraceRaysWrite | kTransferDestination | kAccelerationStructureBuildScratch, + kAll = kAllRead | kAllWrite, }; ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit) diff --git a/AnKi/Gr/D3D/D3DBuffer.cpp b/AnKi/Gr/D3D/D3DBuffer.cpp index 69d371d5b..40319c690 100644 --- a/AnKi/Gr/D3D/D3DBuffer.cpp +++ b/AnKi/Gr/D3D/D3DBuffer.cpp @@ -164,4 +164,137 @@ Error BufferImpl::init(const BufferInitInfo& inf) return Error::kNone; } +D3D12_BUFFER_BARRIER BufferImpl::computeBarrier(BufferUsageBit before, BufferUsageBit after) const +{ + ANKI_ASSERT((m_usage & before) == before); + ANKI_ASSERT((m_usage & after) == after); + + const D3D12_BUFFER_BARRIER out = {.SyncBefore = computeSync(before), + .SyncAfter = computeSync(after), + .AccessBefore = computeAccess(before), + .AccessAfter = computeAccess(after), + .pResource = m_resource, + .Offset = 0, + .Size = kMaxU64}; + + return out; +} + +D3D12_BARRIER_SYNC BufferImpl::computeSync(BufferUsageBit usage) const +{ + if(usage == BufferUsageBit::kNone) + { + return D3D12_BARRIER_SYNC_NONE; + } + + const Bool rt = getGrManagerImpl().getDeviceCapabilities().m_rayTracingEnabled; + D3D12_BARRIER_SYNC sync = {}; + + if(!!(usage & BufferUsageBit::kAllIndirect)) + { + sync |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT; + } + + if(!!(usage & (BufferUsageBit::kIndex | BufferUsageBit::kVertex))) + { + sync |= D3D12_BARRIER_SYNC_INDEX_INPUT | D3D12_BARRIER_SYNC_VERTEX_SHADING; + } + + if(!!(usage & BufferUsageBit::kAllGeometry)) + { + sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING; + } + + if(!!(usage & BufferUsageBit::kAllFragment)) + { + sync |= D3D12_BARRIER_SYNC_PIXEL_SHADING; + } + + if(!!(usage & (BufferUsageBit::kAllCompute & ~BufferUsageBit::kIndirectCompute))) + { + sync |= D3D12_BARRIER_SYNC_COMPUTE_SHADING; + } + + if(!!(usage & (BufferUsageBit::kAccelerationStructureBuild | BufferUsageBit::kAccelerationStructureBuildScratch)) && rt) + { + sync |= D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE; + } + + if(!!(usage & (BufferUsageBit::kAllTraceRays & ~BufferUsageBit::kIndirectTraceRays)) && rt) + { + sync |= D3D12_BARRIER_SYNC_RAYTRACING; + } + + if(!!(usage & BufferUsageBit::kAllTransfer)) + { + sync |= D3D12_BARRIER_SYNC_COPY; + } + + ANKI_ASSERT(sync); + return sync; +} + +D3D12_BARRIER_ACCESS BufferImpl::computeAccess(BufferUsageBit usage) const +{ + if(usage == BufferUsageBit::kNone) + { + return D3D12_BARRIER_ACCESS_NO_ACCESS; + } + + D3D12_BARRIER_ACCESS out = {}; + + if(!!(usage & BufferUsageBit::kVertex)) + { + out |= D3D12_BARRIER_ACCESS_VERTEX_BUFFER; + } + + if(!!(usage & BufferUsageBit::kAllUniform)) + { + out |= D3D12_BARRIER_ACCESS_CONSTANT_BUFFER; + } + + if(!!(usage & BufferUsageBit::kIndex)) + { + out |= D3D12_BARRIER_ACCESS_INDEX_BUFFER; + } + + if(!!(usage & ((BufferUsageBit::kAllStorage | BufferUsageBit::kAllTexel) & BufferUsageBit::kAllWrite))) + { + out |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + } + + if(!!(usage & ((BufferUsageBit::kAllStorage | BufferUsageBit::kAllTexel) & BufferUsageBit::kAllRead))) + { + out |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + } + + if(!!(usage & BufferUsageBit::kAllIndirect)) + { + out |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT; + } + + if(!!(usage & BufferUsageBit::kTransferDestination)) + { + out |= D3D12_BARRIER_ACCESS_COPY_DEST; + } + + if(!!(usage & BufferUsageBit::kTransferSource)) + { + out |= D3D12_BARRIER_ACCESS_COPY_SOURCE; + } + + if(!!(usage & (BufferUsageBit::kAccelerationStructureBuild | BufferUsageBit::kAccelerationStructureBuildScratch))) + { + out |= D3D12_BARRIER_ACCESS_COMMON; + } + + if(!!(usage & BufferUsageBit::kShaderBindingTable)) + { + out |= D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ; + } + + ANKI_ASSERT(out); + return out; +} + } // end namespace anki diff --git a/AnKi/Gr/D3D/D3DBuffer.h b/AnKi/Gr/D3D/D3DBuffer.h index 10f9ee895..f2ec6e089 100644 --- a/AnKi/Gr/D3D/D3DBuffer.h +++ b/AnKi/Gr/D3D/D3DBuffer.h @@ -33,12 +33,18 @@ class BufferImpl final : public Buffer return *m_resource; } + D3D12_BUFFER_BARRIER computeBarrier(BufferUsageBit before, BufferUsageBit after) const; + private: ID3D12Resource* m_resource = nullptr; #if ANKI_ASSERTIONS_ENABLED Bool m_mapped = false; #endif + + D3D12_BARRIER_SYNC computeSync(BufferUsageBit usage) const; + + D3D12_BARRIER_ACCESS computeAccess(BufferUsageBit usage) const; }; /// @} diff --git a/AnKi/Gr/D3D/D3DCommandBuffer.cpp b/AnKi/Gr/D3D/D3DCommandBuffer.cpp index a26601287..716d90ed8 100644 --- a/AnKi/Gr/D3D/D3DCommandBuffer.cpp +++ b/AnKi/Gr/D3D/D3DCommandBuffer.cpp @@ -680,41 +680,44 @@ void CommandBuffer::setPipelineBarrier(ConstWeakArray textur ANKI_D3D_SELF(CommandBufferImpl); self.commandCommon(); - DynamicArray> resourceBarriers(self.m_fastPool); + DynamicArray> texBarriers(self.m_fastPool); + DynamicArray> bufferBarriers(self.m_fastPool); for(const TextureBarrierInfo& barrier : textures) { const TextureImpl& impl = static_cast(barrier.m_textureView.getTexture()); + D3D12_TEXTURE_BARRIER& d3dBarrier = *texBarriers.emplaceBack(); + d3dBarrier = impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, barrier.m_textureView.getSubresource()); + } - D3D12_RESOURCE_BARRIER& d3dBarrier = *resourceBarriers.emplaceBack(); - d3dBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - d3dBarrier.Transition.pResource = &impl.getD3DResource(); - - if(barrier.m_textureView.isAllSurfacesOrVolumes() && barrier.m_textureView.getDepthStencilAspect() == impl.getDepthStencilAspect()) - { - d3dBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - } - else - { - d3dBarrier.Transition.Subresource = impl.calcD3DSubresourceIndex(barrier.m_textureView.getSubresource()); - } - - impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, d3dBarrier.Transition.StateBefore, d3dBarrier.Transition.StateAfter); - - if(d3dBarrier.Transition.StateBefore & D3D12_RESOURCE_STATE_UNORDERED_ACCESS - && d3dBarrier.Transition.StateAfter & D3D12_RESOURCE_STATE_UNORDERED_ACCESS) - { - D3D12_RESOURCE_BARRIER& d3dBarrier = *resourceBarriers.emplaceBack(); - d3dBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - d3dBarrier.UAV.pResource = &impl.getD3DResource(); - } + for(const BufferBarrierInfo& barrier : buffers) + { + const BufferImpl& impl = static_cast(barrier.m_bufferView.getBuffer()); + D3D12_BUFFER_BARRIER& d3dBarrier = *bufferBarriers.emplaceBack(); + d3dBarrier = impl.computeBarrier(barrier.m_previousUsage, barrier.m_nextUsage); } - ANKI_ASSERT(buffers.getSize() == 0 && "TODO"); ANKI_ASSERT(accelerationStructures.getSize() == 0 && "TODO"); - ANKI_ASSERT(resourceBarriers.getSize() > 0); - self.m_cmdList->ResourceBarrier(resourceBarriers.getSize(), resourceBarriers.getBegin()); + Array barrierGroups; + U32 barrierGroupCount = 0; + + if(texBarriers.getSize()) + { + barrierGroups[barrierGroupCount++] = {.Type = D3D12_BARRIER_TYPE_TEXTURE, + .NumBarriers = texBarriers.getSize(), + .pTextureBarriers = texBarriers.getBegin()}; + } + + if(bufferBarriers.getSize()) + { + barrierGroups[barrierGroupCount++] = {.Type = D3D12_BARRIER_TYPE_BUFFER, + .NumBarriers = bufferBarriers.getSize(), + .pBufferBarriers = bufferBarriers.getBegin()}; + } + + ANKI_ASSERT(barrierGroupCount > 0); + self.m_cmdList->Barrier(barrierGroupCount, barrierGroups.getBegin()); } void CommandBuffer::beginOcclusionQuery([[maybe_unused]] OcclusionQuery* query) diff --git a/AnKi/Gr/D3D/D3DTexture.cpp b/AnKi/Gr/D3D/D3DTexture.cpp index 3b4218f04..f1caecde5 100644 --- a/AnKi/Gr/D3D/D3DTexture.cpp +++ b/AnKi/Gr/D3D/D3DTexture.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace anki { @@ -472,71 +473,222 @@ const TextureImpl::View& TextureImpl::getOrCreateView(const TextureSubresourceDe return nview; } -void TextureImpl::computeResourceStates(TextureUsageBit usage, D3D12_RESOURCE_STATES& states) const +D3D12_TEXTURE_BARRIER TextureImpl::computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, + const TextureSubresourceDescriptor& subresource) const { - ANKI_ASSERT((usage & m_usage) == usage); + ANKI_ASSERT((m_usage & before) == before); + ANKI_ASSERT((m_usage & after) == after); + ANKI_ASSERT(subresource == TextureView(this, subresource).getSubresource() && "Should have been sanitized"); + + D3D12_TEXTURE_BARRIER barrier; + + computeBarrierInfo(before, barrier.SyncBefore, barrier.AccessBefore); + computeBarrierInfo(after, barrier.SyncAfter, barrier.AccessAfter); + barrier.LayoutBefore = computeLayout(before); + barrier.LayoutAfter = computeLayout(after); + barrier.pResource = m_resource; + + barrier.Subresources = {}; + if(subresource.m_allSurfacesOrVolumes) + { + barrier.Subresources.IndexOrFirstMipLevel = kMaxU32; + } + else + { + const U8 faceCount = textureTypeIsCube(m_texType) ? 6 : 1; + + barrier.Subresources.IndexOrFirstMipLevel = subresource.m_mipmap; + barrier.Subresources.NumMipLevels = 1; + barrier.Subresources.FirstArraySlice = subresource.m_layer * faceCount + subresource.m_face; + barrier.Subresources.NumArraySlices = 1; + barrier.Subresources.FirstPlane = !!(subresource.m_depthStencilAspect & DepthStencilAspectBit::kDepth) ? 0 : 1; + barrier.Subresources.NumPlanes = (subresource.m_depthStencilAspect == DepthStencilAspectBit::kDepthStencil) ? 2 : 1; + } + + if(before == TextureUsageBit::kNone) + { + barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_DISCARD; + } + return barrier; +} + +void TextureImpl::computeBarrierInfo(TextureUsageBit usage, D3D12_BARRIER_SYNC& stages, D3D12_BARRIER_ACCESS& accesses) const +{ if(usage == TextureUsageBit::kNone) { - // D3D doesn't have a clean slade, figure something out + stages = D3D12_BARRIER_SYNC_NONE; + accesses = D3D12_BARRIER_ACCESS_NO_ACCESS; + return; + } + + stages = {}; + accesses = {}; + const Bool depthStencil = !!m_aspect; + const Bool rt = getGrManagerImpl().getDeviceCapabilities().m_rayTracingEnabled; - states |= D3D12_RESOURCE_STATE_COMMON; + if(!!(usage & (TextureUsageBit::kSampledGeometry | TextureUsageBit::kStorageGeometryRead))) + { + stages |= D3D12_BARRIER_SYNC_VERTEX_SHADING; + accesses |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; } - else + + if(!!(usage & TextureUsageBit::kStorageGeometryWrite)) { - states = D3D12_RESOURCE_STATES(0); - if(!!(usage & TextureUsageBit::kAllFramebuffer)) - { - states |= D3D12_RESOURCE_STATE_RENDER_TARGET; + stages |= D3D12_BARRIER_SYNC_VERTEX_SHADING; + accesses |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + } - if(!!(usage & TextureUsageBit::kFramebufferWrite) && !!(m_aspect & DepthStencilAspectBit::kDepth)) - { - states |= D3D12_RESOURCE_STATE_DEPTH_WRITE; - } + if(!!(usage & (TextureUsageBit::kSampledFragment | TextureUsageBit::kStorageFragmentRead))) + { + stages |= D3D12_BARRIER_SYNC_PIXEL_SHADING; + accesses |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + } - if(!!(usage & TextureUsageBit::kFramebufferRead) && !!(m_aspect & DepthStencilAspectBit::kDepth)) - { - states |= D3D12_RESOURCE_STATE_DEPTH_READ; - } - } + if(!!(usage & TextureUsageBit::kStorageFragmentWrite)) + { + stages |= D3D12_BARRIER_SYNC_PIXEL_SHADING; + accesses |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + } + + if(!!(usage & (TextureUsageBit::kSampledCompute | TextureUsageBit::kStorageComputeRead))) + { + stages |= D3D12_BARRIER_SYNC_COMPUTE_SHADING; + accesses |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + } - if(!!(usage & TextureUsageBit::kAllStorage)) + if(!!(usage & TextureUsageBit::kStorageComputeWrite)) + { + stages |= D3D12_BARRIER_SYNC_COMPUTE_SHADING; + accesses |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + } + + if(!!(usage & (TextureUsageBit::kSampledTraceRays | TextureUsageBit::kStorageTraceRaysRead)) && rt) + { + stages |= D3D12_BARRIER_SYNC_RAYTRACING; + accesses |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE; + } + + if(!!(usage & TextureUsageBit::kStorageTraceRaysWrite) && rt) + { + stages |= D3D12_BARRIER_SYNC_COMPUTE_SHADING; + accesses |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; + } + + if(!!(usage & TextureUsageBit::kFramebufferRead)) + { + if(depthStencil) { - states |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + stages |= D3D12_BARRIER_SYNC_DEPTH_STENCIL; + accesses |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ; } - - if(!!(usage & TextureUsageBit::kSampledFragment)) + else { - states |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + stages |= D3D12_BARRIER_SYNC_RENDER_TARGET; + accesses |= D3D12_BARRIER_ACCESS_RENDER_TARGET; } + } - if(!!(usage & (TextureUsageBit::kAllSampled & ~TextureUsageBit::kSampledFragment))) + if(!!(usage & TextureUsageBit::kFramebufferWrite)) + { + if(depthStencil) { - states |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + stages |= D3D12_BARRIER_SYNC_DEPTH_STENCIL; + accesses |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE; } - - if(!!(usage & TextureUsageBit::kTransferDestination)) + else { - states |= D3D12_RESOURCE_STATE_COPY_DEST; + stages |= D3D12_BARRIER_SYNC_RENDER_TARGET; + accesses |= D3D12_BARRIER_ACCESS_RENDER_TARGET; } + } + + if(!!(usage & TextureUsageBit::kFramebufferShadingRate)) + { + stages |= D3D12_BARRIER_SYNC_PIXEL_SHADING; + accesses |= D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE; + } + + if(!!(usage & TextureUsageBit::kGenerateMipmaps)) + { + ANKI_ASSERT(!"TODO rm"); + } - if(!!(usage & TextureUsageBit::kFramebufferShadingRate)) + if(!!(usage & TextureUsageBit::kTransferDestination)) + { + stages |= D3D12_BARRIER_SYNC_COPY; + accesses |= D3D12_BARRIER_ACCESS_COPY_DEST; + } + + if(!!(usage & TextureUsageBit::kPresent)) + { + stages |= D3D12_BARRIER_SYNC_COPY; + accesses |= D3D12_BARRIER_ACCESS_COPY_SOURCE; + } +} + +D3D12_BARRIER_LAYOUT TextureImpl::computeLayout(TextureUsageBit usage) const +{ + const Bool depthStencil = !!m_aspect; + D3D12_BARRIER_LAYOUT out = {}; + + if(usage == TextureUsageBit::kNone) + { + out = D3D12_BARRIER_LAYOUT_UNDEFINED; + } + else if(depthStencil) + { + if(!(usage & ~(TextureUsageBit::kAllSampled | TextureUsageBit::kFramebufferRead))) { - states |= D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE; + // Only depth tests and sampled + out = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ; } - - if(!!(usage & TextureUsageBit::kPresent)) + else { - states |= D3D12_RESOURCE_STATE_PRESENT; + // Only attachment write, the rest (eg transfer) are not supported for now + ANKI_ASSERT(usage == TextureUsageBit::kFramebufferWrite || usage == TextureUsageBit::kAllFramebuffer); + out = D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE; } } -} + else if(!(usage & ~TextureUsageBit::kAllFramebuffer)) + { + // Color attachment + out = D3D12_BARRIER_LAYOUT_RENDER_TARGET; + } + else if(!(usage & ~TextureUsageBit::kFramebufferShadingRate)) + { + // SRI + out = D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE; + } + else if(!(usage & ~TextureUsageBit::kAllStorage)) + { + // Only image load/store + out = D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS; + } + else if(!(usage & ~TextureUsageBit::kAllSampled)) + { + // Only sampled + out = D3D12_BARRIER_LAYOUT_SHADER_RESOURCE; + } + else if(usage == TextureUsageBit::kGenerateMipmaps) + { + ANKI_ASSERT(!"TODO rm"); + } + else if(usage == TextureUsageBit::kTransferDestination) + { + out = D3D12_BARRIER_LAYOUT_COPY_DEST; + } + else if(usage == TextureUsageBit::kPresent) + { + out = D3D12_BARRIER_LAYOUT_PRESENT; + } + else + { + // No idea so play it safe + out = D3D12_BARRIER_LAYOUT_COMMON; + } -void TextureImpl::computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, D3D12_RESOURCE_STATES& statesBefore, - D3D12_RESOURCE_STATES& statesAfter) const -{ - computeResourceStates(before, statesBefore); - computeResourceStates(after, statesAfter); + return out; } } // end namespace anki diff --git a/AnKi/Gr/D3D/D3DTexture.h b/AnKi/Gr/D3D/D3DTexture.h index 3ed451163..2a2bb7b58 100644 --- a/AnKi/Gr/D3D/D3DTexture.h +++ b/AnKi/Gr/D3D/D3DTexture.h @@ -77,9 +77,7 @@ class TextureImpl final : public Texture return view.getFirstMipmap() + (arraySlice * m_mipCount) + (planeSlice * m_mipCount * arraySize); } - /// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier. - void computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, D3D12_RESOURCE_STATES& statesBefore, - D3D12_RESOURCE_STATES& statesAfter) const; + D3D12_TEXTURE_BARRIER computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, const TextureSubresourceDescriptor& subresource) const; ID3D12Resource& getD3DResource() const { @@ -137,7 +135,9 @@ class TextureImpl final : public Texture void initView(const TextureSubresourceDescriptor& subresource, TextureUsageBit usage, View& view) const; - void computeResourceStates(TextureUsageBit usage, D3D12_RESOURCE_STATES& states) const; + void computeBarrierInfo(TextureUsageBit usage, D3D12_BARRIER_SYNC& stages, D3D12_BARRIER_ACCESS& accesses) const; + + D3D12_BARRIER_LAYOUT computeLayout(TextureUsageBit usage) const; Bool isExternal() const {