diff options
Diffstat (limited to 'tools/gfx/d3d12/d3d12-command-encoder.cpp')
| -rw-r--r-- | tools/gfx/d3d12/d3d12-command-encoder.cpp | 1406 |
1 files changed, 1406 insertions, 0 deletions
diff --git a/tools/gfx/d3d12/d3d12-command-encoder.cpp b/tools/gfx/d3d12/d3d12-command-encoder.cpp new file mode 100644 index 000000000..516053d39 --- /dev/null +++ b/tools/gfx/d3d12/d3d12-command-encoder.cpp @@ -0,0 +1,1406 @@ +// d3d12-command-encoder.cpp +#include "d3d12-command-encoder.h" + +#include "d3d12-command-buffer.h" +#include "d3d12-device.h" +#include "d3d12-pipeline-state.h" +#include "d3d12-query.h" +#include "d3d12-shader-object.h" +#include "d3d12-shader-program.h" +#include "d3d12-shader-table.h" +#include "d3d12-transient-heap.h" +#include "d3d12-texture.h" +#include "d3d12-vertex-layout.h" + +#include "d3d12-helper-functions.h" + +namespace gfx +{ +namespace d3d12 +{ + +using namespace Slang; + +int PipelineCommandEncoder::getBindPointIndex(PipelineType type) +{ + switch (type) + { + case PipelineType::Graphics: + return 0; + case PipelineType::Compute: + return 1; + case PipelineType::RayTracing: + return 2; + default: + assert(!"unknown pipeline type."); + return -1; + } +} + +void PipelineCommandEncoder::init(CommandBufferImpl* commandBuffer) +{ + m_commandBuffer = commandBuffer; + m_d3dCmdList = m_commandBuffer->m_cmdList; + m_renderer = commandBuffer->m_renderer; + m_transientHeap = commandBuffer->m_transientHeap; + m_device = commandBuffer->m_renderer->m_device; +} + +Result PipelineCommandEncoder::bindPipelineImpl( + IPipelineState* pipelineState, IShaderObject** outRootObject) +{ + m_currentPipeline = static_cast<PipelineStateBase*>(pipelineState); + auto rootObject = &m_commandBuffer->m_rootShaderObject; + m_commandBuffer->m_mutableRootShaderObject = nullptr; + SLANG_RETURN_ON_FAIL(rootObject->reset( + m_renderer, + m_currentPipeline->getProgram<ShaderProgramImpl>()->m_rootObjectLayout, + m_commandBuffer->m_transientHeap)); + *outRootObject = rootObject; + m_bindingDirty = true; + return SLANG_OK; +} + +Result PipelineCommandEncoder::bindPipelineWithRootObjectImpl( + IPipelineState* pipelineState, IShaderObject* rootObject) +{ + m_currentPipeline = static_cast<PipelineStateBase*>(pipelineState); + m_commandBuffer->m_mutableRootShaderObject = + static_cast<MutableRootShaderObjectImpl*>(rootObject); + m_bindingDirty = true; + return SLANG_OK; +} + +Result PipelineCommandEncoder::_bindRenderState( + Submitter* submitter, RefPtr<PipelineStateBase>& newPipeline) +{ + RootShaderObjectImpl* rootObjectImpl = m_commandBuffer->m_mutableRootShaderObject + ? m_commandBuffer->m_mutableRootShaderObject.Ptr() + : &m_commandBuffer->m_rootShaderObject; + SLANG_RETURN_ON_FAIL( + m_renderer->maybeSpecializePipeline(m_currentPipeline, rootObjectImpl, newPipeline)); + PipelineStateBase* newPipelineImpl = static_cast<PipelineStateBase*>(newPipeline.Ptr()); + auto commandList = m_d3dCmdList; + auto pipelineTypeIndex = (int)newPipelineImpl->desc.type; + auto programImpl = static_cast<ShaderProgramImpl*>(newPipelineImpl->m_program.Ptr()); + newPipelineImpl->ensureAPIPipelineStateCreated(); + submitter->setRootSignature(programImpl->m_rootObjectLayout->m_rootSignature); + submitter->setPipelineState(newPipelineImpl); + RootShaderObjectLayoutImpl* rootLayoutImpl = programImpl->m_rootObjectLayout; + + // We need to set up a context for binding shader objects to the pipeline state. + // This type mostly exists to bundle together a bunch of parameters that would + // otherwise need to be tunneled down through all the shader object binding + // logic. + // + BindingContext context = {}; + context.encoder = this; + context.submitter = submitter; + context.device = m_renderer; + context.transientHeap = m_transientHeap; + context.outOfMemoryHeap = (D3D12_DESCRIPTOR_HEAP_TYPE)(-1); + // We kick off binding of shader objects at the root object, and the objects + // themselves will be responsible for allocating, binding, and filling in + // any descriptor tables or other root parameters needed. + // + m_commandBuffer->bindDescriptorHeaps(); + if (rootObjectImpl->bindAsRoot(&context, rootLayoutImpl) == SLANG_E_OUT_OF_MEMORY) + { + if (!m_transientHeap->canResize()) + { + return SLANG_E_OUT_OF_MEMORY; + } + + // If we run out of heap space while binding, allocate new descriptor heaps and try again. + ID3D12DescriptorHeap* d3dheap = nullptr; + m_commandBuffer->invalidateDescriptorHeapBinding(); + switch (context.outOfMemoryHeap) + { + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: + SLANG_RETURN_ON_FAIL(m_transientHeap->allocateNewViewDescriptorHeap(m_renderer)); + d3dheap = m_transientHeap->getCurrentViewHeap().getHeap(); + m_commandBuffer->bindDescriptorHeaps(); + break; + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: + SLANG_RETURN_ON_FAIL(m_transientHeap->allocateNewSamplerDescriptorHeap(m_renderer)); + d3dheap = m_transientHeap->getCurrentSamplerHeap().getHeap(); + m_commandBuffer->bindDescriptorHeaps(); + break; + default: + assert(!"shouldn't be here"); + return SLANG_FAIL; + } + + // Try again. + SLANG_RETURN_ON_FAIL(rootObjectImpl->bindAsRoot(&context, rootLayoutImpl)); + } + + return SLANG_OK; +} + +void ResourceCommandEncoderImpl::bufferBarrier( + GfxCount count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) +{ + ShortList<D3D12_RESOURCE_BARRIER, 16> barriers; + for (GfxIndex i = 0; i < count; i++) + { + auto bufferImpl = static_cast<BufferResourceImpl*>(buffers[i]); + + D3D12_RESOURCE_BARRIER barrier = {}; + // If the src == dst, it must be a UAV barrier. + barrier.Type = (src == dst && dst == ResourceState::UnorderedAccess) + ? D3D12_RESOURCE_BARRIER_TYPE_UAV + : D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + + if (barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_UAV) + { + barrier.UAV.pResource = bufferImpl->m_resource; + } + else + { + barrier.Transition.pResource = bufferImpl->m_resource; + barrier.Transition.StateBefore = D3DUtil::getResourceState(src); + barrier.Transition.StateAfter = D3DUtil::getResourceState(dst); + barrier.Transition.Subresource = 0; + if (barrier.Transition.StateAfter == barrier.Transition.StateBefore) + continue; + } + barriers.add(barrier); + } + if (barriers.getCount()) + { + m_commandBuffer->m_cmdList4->ResourceBarrier( + (UINT)barriers.getCount(), barriers.getArrayView().getBuffer()); + } +} + +void ResourceCommandEncoderImpl::writeTimestamp(IQueryPool* pool, GfxIndex index) +{ + static_cast<QueryPoolImpl*>(pool)->writeTimestamp(m_commandBuffer->m_cmdList, index); +} + +void ResourceCommandEncoderImpl::copyTexture( + ITextureResource* dst, + ResourceState dstState, + SubresourceRange dstSubresource, + ITextureResource::Offset3D dstOffset, + ITextureResource* src, + ResourceState srcState, + SubresourceRange srcSubresource, + ITextureResource::Offset3D srcOffset, + ITextureResource::Extents extent) +{ + auto dstTexture = static_cast<TextureResourceImpl*>(dst); + auto srcTexture = static_cast<TextureResourceImpl*>(src); + + if (dstSubresource.layerCount == 0 && dstSubresource.mipLevelCount == 0 && + srcSubresource.layerCount == 0 && srcSubresource.mipLevelCount == 0) + { + m_commandBuffer->m_cmdList->CopyResource( + dstTexture->m_resource.getResource(), srcTexture->m_resource.getResource()); + return; + } + + auto d3dFormat = D3DUtil::getMapFormat(dstTexture->getDesc()->format); + auto aspectMask = (int32_t)dstSubresource.aspectMask; + if (dstSubresource.aspectMask == TextureAspect::Default) + aspectMask = (int32_t)TextureAspect::Color; + while (aspectMask) + { + auto aspect = Math::getLowestBit((int32_t)aspectMask); + aspectMask &= ~aspect; + auto planeIndex = D3DUtil::getPlaneSlice(d3dFormat, (TextureAspect)aspect); + for (GfxIndex layer = 0; layer < dstSubresource.layerCount; layer++) + { + for (GfxIndex mipLevel = 0; mipLevel < dstSubresource.mipLevelCount; mipLevel++) + { + D3D12_TEXTURE_COPY_LOCATION dstRegion = {}; + + dstRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstRegion.pResource = dstTexture->m_resource.getResource(); + dstRegion.SubresourceIndex = D3DUtil::getSubresourceIndex( + dstSubresource.mipLevel + mipLevel, + dstSubresource.baseArrayLayer + layer, + planeIndex, + dstTexture->getDesc()->numMipLevels, + dstTexture->getDesc()->arraySize); + + D3D12_TEXTURE_COPY_LOCATION srcRegion = {}; + srcRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcRegion.pResource = srcTexture->m_resource.getResource(); + srcRegion.SubresourceIndex = D3DUtil::getSubresourceIndex( + srcSubresource.mipLevel + mipLevel, + srcSubresource.baseArrayLayer + layer, + planeIndex, + srcTexture->getDesc()->numMipLevels, + srcTexture->getDesc()->arraySize); + + D3D12_BOX srcBox = {}; + srcBox.left = srcOffset.x; + srcBox.top = srcOffset.y; + srcBox.front = srcOffset.z; + srcBox.right = srcBox.left + extent.width; + srcBox.bottom = srcBox.top + extent.height; + srcBox.back = srcBox.front + extent.depth; + + m_commandBuffer->m_cmdList->CopyTextureRegion( + &dstRegion, dstOffset.x, dstOffset.y, dstOffset.z, &srcRegion, &srcBox); + } + } + } +} + +void ResourceCommandEncoderImpl::uploadTextureData( + ITextureResource* dst, + SubresourceRange subResourceRange, + ITextureResource::Offset3D offset, + ITextureResource::Extents extent, + ITextureResource::SubresourceData* subResourceData, + GfxCount subResourceDataCount) +{ + auto dstTexture = static_cast<TextureResourceImpl*>(dst); + auto baseSubresourceIndex = D3DUtil::getSubresourceIndex( + subResourceRange.mipLevel, + subResourceRange.baseArrayLayer, + 0, + dstTexture->getDesc()->numMipLevels, + dstTexture->getDesc()->arraySize); + auto textureSize = dstTexture->getDesc()->size; + FormatInfo formatInfo = {}; + gfxGetFormatInfo(dstTexture->getDesc()->format, &formatInfo); + for (GfxCount i = 0; i < subResourceDataCount; i++) + { + auto subresourceIndex = baseSubresourceIndex + i; + // Get the footprint + D3D12_RESOURCE_DESC texDesc = dstTexture->m_resource.getResource()->GetDesc(); + + D3D12_TEXTURE_COPY_LOCATION dstRegion = {}; + + dstRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstRegion.SubresourceIndex = subresourceIndex; + dstRegion.pResource = dstTexture->m_resource.getResource(); + + D3D12_TEXTURE_COPY_LOCATION srcRegion = {}; + srcRegion.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint = srcRegion.PlacedFootprint; + footprint.Offset = 0; + footprint.Footprint.Format = texDesc.Format; + uint32_t mipLevel = + D3DUtil::getSubresourceMipLevel(subresourceIndex, dstTexture->getDesc()->numMipLevels); + if (extent.width != ITextureResource::kRemainingTextureSize) + { + footprint.Footprint.Width = extent.width; + } + else + { + footprint.Footprint.Width = Math::Max(1, (textureSize.width >> mipLevel)) - offset.x; + } + if (extent.height != ITextureResource::kRemainingTextureSize) + { + footprint.Footprint.Height = extent.height; + } + else + { + footprint.Footprint.Height = Math::Max(1, (textureSize.height >> mipLevel)) - offset.y; + } + if (extent.depth != ITextureResource::kRemainingTextureSize) + { + footprint.Footprint.Depth = extent.depth; + } + else + { + footprint.Footprint.Depth = Math::Max(1, (textureSize.depth >> mipLevel)) - offset.z; + } + auto rowSize = (footprint.Footprint.Width + formatInfo.blockWidth - 1) / + formatInfo.blockWidth * formatInfo.blockSizeInBytes; + auto rowCount = + (footprint.Footprint.Height + formatInfo.blockHeight - 1) / formatInfo.blockHeight; + footprint.Footprint.RowPitch = + (UINT)D3DUtil::calcAligned(rowSize, (uint32_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + + auto bufferSize = footprint.Footprint.RowPitch * rowCount * footprint.Footprint.Depth; + + IBufferResource* stagingBuffer; + Offset stagingBufferOffset = 0; + m_commandBuffer->m_transientHeap->allocateStagingBuffer( + bufferSize, stagingBuffer, stagingBufferOffset, MemoryType::Upload, true); + assert(stagingBufferOffset == 0); + BufferResourceImpl* bufferImpl = static_cast<BufferResourceImpl*>(stagingBuffer); + uint8_t* bufferData = nullptr; + D3D12_RANGE mapRange = { 0, 0 }; + bufferImpl->m_resource.getResource()->Map(0, &mapRange, (void**)&bufferData); + for (uint32_t z = 0; z < footprint.Footprint.Depth; z++) + { + auto imageStart = bufferData + footprint.Footprint.RowPitch * rowCount * (Size)z; + auto srcData = (uint8_t*)subResourceData->data + subResourceData->strideZ * z; + for (uint32_t row = 0; row < rowCount; row++) + { + memcpy( + imageStart + row * (Size)footprint.Footprint.RowPitch, + srcData + subResourceData->strideY * row, + rowSize); + } + } + bufferImpl->m_resource.getResource()->Unmap(0, nullptr); + srcRegion.pResource = bufferImpl->m_resource.getResource(); + m_commandBuffer->m_cmdList->CopyTextureRegion( + &dstRegion, offset.x, offset.y, offset.z, &srcRegion, nullptr); + } +} + +void ResourceCommandEncoderImpl::clearResourceView( + IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) +{ + auto viewImpl = static_cast<ResourceViewImpl*>(view); + switch (view->getViewDesc()->type) + { + case IResourceView::Type::RenderTarget: + m_commandBuffer->m_cmdList->ClearRenderTargetView( + viewImpl->m_descriptor.cpuHandle, clearValue->color.floatValues, 0, nullptr); + break; + case IResourceView::Type::DepthStencil: + { + D3D12_CLEAR_FLAGS clearFlags = (D3D12_CLEAR_FLAGS)0; + if (flags & ClearResourceViewFlags::ClearDepth) + { + clearFlags |= D3D12_CLEAR_FLAG_DEPTH; + } + if (flags & ClearResourceViewFlags::ClearStencil) + { + clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + } + m_commandBuffer->m_cmdList->ClearDepthStencilView( + viewImpl->m_descriptor.cpuHandle, + clearFlags, + clearValue->depthStencil.depth, + (UINT8)clearValue->depthStencil.stencil, + 0, + nullptr); + break; + } + case IResourceView::Type::UnorderedAccess: + { + ID3D12Resource* d3dResource = nullptr; + switch (viewImpl->m_resource->getType()) + { + case IResource::Type::Buffer: + d3dResource = static_cast<BufferResourceImpl*>(viewImpl->m_resource.Ptr()) + ->m_resource.getResource(); + break; + default: + d3dResource = static_cast<TextureResourceImpl*>(viewImpl->m_resource.Ptr()) + ->m_resource.getResource(); + break; + } + auto gpuHandleIndex = + m_commandBuffer->m_transientHeap->getCurrentViewHeap().allocate(1); + if (gpuHandleIndex == -1) + { + m_commandBuffer->m_transientHeap->allocateNewViewDescriptorHeap( + m_commandBuffer->m_renderer); + gpuHandleIndex = m_commandBuffer->m_transientHeap->getCurrentViewHeap().allocate(1); + m_commandBuffer->bindDescriptorHeaps(); + } + this->m_commandBuffer->m_renderer->m_device->CopyDescriptorsSimple( + 1, + m_commandBuffer->m_transientHeap->getCurrentViewHeap().getCpuHandle(gpuHandleIndex), + viewImpl->m_descriptor.cpuHandle, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + if (flags & ClearResourceViewFlags::FloatClearValues) + { + m_commandBuffer->m_cmdList->ClearUnorderedAccessViewFloat( + m_commandBuffer->m_transientHeap->getCurrentViewHeap().getGpuHandle( + gpuHandleIndex), + viewImpl->m_descriptor.cpuHandle, + d3dResource, + clearValue->color.floatValues, + 0, + nullptr); + } + else + { + m_commandBuffer->m_cmdList->ClearUnorderedAccessViewUint( + m_commandBuffer->m_transientHeap->getCurrentViewHeap().getGpuHandle( + gpuHandleIndex), + viewImpl->m_descriptor.cpuHandle, + d3dResource, + clearValue->color.uintValues, + 0, + nullptr); + } + break; + } + default: + break; + } +} + +void ResourceCommandEncoderImpl::resolveResource( + ITextureResource* source, + ResourceState sourceState, + SubresourceRange sourceRange, + ITextureResource* dest, + ResourceState destState, + SubresourceRange destRange) +{ + auto srcTexture = static_cast<TextureResourceImpl*>(source); + auto srcDesc = srcTexture->getDesc(); + auto dstTexture = static_cast<TextureResourceImpl*>(dest); + auto dstDesc = dstTexture->getDesc(); + + for (GfxIndex layer = 0; layer < sourceRange.layerCount; ++layer) + { + for (GfxIndex mip = 0; mip < sourceRange.mipLevelCount; ++mip) + { + auto srcSubresourceIndex = D3DUtil::getSubresourceIndex( + mip + sourceRange.mipLevel, + layer + sourceRange.baseArrayLayer, + 0, + srcDesc->numMipLevels, + srcDesc->arraySize); + auto dstSubresourceIndex = D3DUtil::getSubresourceIndex( + mip + destRange.mipLevel, + layer + destRange.baseArrayLayer, + 0, + dstDesc->numMipLevels, + dstDesc->arraySize); + + DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc->format); + + m_commandBuffer->m_cmdList->ResolveSubresource( + dstTexture->m_resource.getResource(), + dstSubresourceIndex, + srcTexture->m_resource.getResource(), + srcSubresourceIndex, + format); + } + } +} + +void ResourceCommandEncoderImpl::resolveQuery( + IQueryPool* queryPool, GfxIndex index, GfxCount count, IBufferResource* buffer, Offset offset) +{ + auto queryBase = static_cast<QueryPoolBase*>(queryPool); + switch (queryBase->m_desc.type) + { + case QueryType::AccelerationStructureCompactedSize: + case QueryType::AccelerationStructureCurrentSize: + case QueryType::AccelerationStructureSerializedSize: + { + auto queryPoolImpl = static_cast<PlainBufferProxyQueryPoolImpl*>(queryPool); + auto bufferImpl = static_cast<BufferResourceImpl*>(buffer); + auto srcQueryBuffer = queryPoolImpl->m_bufferResource->m_resource.getResource(); + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.pResource = srcQueryBuffer; + m_commandBuffer->m_cmdList->ResourceBarrier(1, &barrier); + + m_commandBuffer->m_cmdList->CopyBufferRegion( + bufferImpl->m_resource.getResource(), + (uint64_t)offset, + srcQueryBuffer, + index * sizeof(uint64_t), + count * sizeof(uint64_t)); + + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + barrier.Transition.pResource = srcQueryBuffer; + m_commandBuffer->m_cmdList->ResourceBarrier(1, &barrier); + } + break; + default: + { + auto queryPoolImpl = static_cast<QueryPoolImpl*>(queryPool); + auto bufferImpl = static_cast<BufferResourceImpl*>(buffer); + m_commandBuffer->m_cmdList->ResolveQueryData( + queryPoolImpl->m_queryHeap.get(), + queryPoolImpl->m_queryType, + index, + count, + bufferImpl->m_resource.getResource(), + offset); + } + break; + } +} + +void ResourceCommandEncoderImpl::copyTextureToBuffer( + IBufferResource* dst, + Offset dstOffset, + Size dstSize, + Size dstRowStride, + ITextureResource* src, + ResourceState srcState, + SubresourceRange srcSubresource, + ITextureResource::Offset3D srcOffset, + ITextureResource::Extents extent) +{ + assert(srcSubresource.mipLevelCount <= 1); + + auto srcTexture = static_cast<TextureResourceImpl*>(src); + auto dstBuffer = static_cast<BufferResourceImpl*>(dst); + auto baseSubresourceIndex = D3DUtil::getSubresourceIndex( + srcSubresource.mipLevel, + srcSubresource.baseArrayLayer, + 0, + srcTexture->getDesc()->numMipLevels, + srcTexture->getDesc()->arraySize); + auto textureSize = srcTexture->getDesc()->size; + FormatInfo formatInfo = {}; + gfxGetFormatInfo(srcTexture->getDesc()->format, &formatInfo); + if (srcSubresource.mipLevelCount == 0) + srcSubresource.mipLevelCount = srcTexture->getDesc()->numMipLevels; + if (srcSubresource.layerCount == 0) + srcSubresource.layerCount = srcTexture->getDesc()->arraySize; + + for (GfxCount layer = 0; layer < srcSubresource.layerCount; layer++) + { + // Get the footprint + D3D12_RESOURCE_DESC texDesc = srcTexture->m_resource.getResource()->GetDesc(); + + D3D12_TEXTURE_COPY_LOCATION dstRegion = {}; + dstRegion.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dstRegion.pResource = dstBuffer->m_resource.getResource(); + D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint = dstRegion.PlacedFootprint; + + D3D12_TEXTURE_COPY_LOCATION srcRegion = {}; + srcRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcRegion.SubresourceIndex = D3DUtil::getSubresourceIndex( + srcSubresource.mipLevel, + layer + srcSubresource.baseArrayLayer, + 0, + srcTexture->getDesc()->numMipLevels, + srcTexture->getDesc()->arraySize); + srcRegion.pResource = srcTexture->m_resource.getResource(); + + footprint.Offset = dstOffset; + footprint.Footprint.Format = texDesc.Format; + uint32_t mipLevel = srcSubresource.mipLevel; + if (extent.width != 0xFFFFFFFF) + { + footprint.Footprint.Width = extent.width; + } + else + { + footprint.Footprint.Width = Math::Max(1, (textureSize.width >> mipLevel)) - srcOffset.x; + } + if (extent.height != 0xFFFFFFFF) + { + footprint.Footprint.Height = extent.height; + } + else + { + footprint.Footprint.Height = + Math::Max(1, (textureSize.height >> mipLevel)) - srcOffset.y; + } + if (extent.depth != 0xFFFFFFFF) + { + footprint.Footprint.Depth = extent.depth; + } + else + { + footprint.Footprint.Depth = Math::Max(1, (textureSize.depth >> mipLevel)) - srcOffset.z; + } + + assert(dstRowStride % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 0); + footprint.Footprint.RowPitch = (UINT)dstRowStride; + + auto bufferSize = + footprint.Footprint.RowPitch * footprint.Footprint.Height * footprint.Footprint.Depth; + + D3D12_BOX srcBox = {}; + srcBox.left = srcOffset.x; + srcBox.top = srcOffset.y; + srcBox.front = srcOffset.z; + srcBox.right = srcOffset.x + extent.width; + srcBox.bottom = srcOffset.y + extent.height; + srcBox.back = srcOffset.z + extent.depth; + m_commandBuffer->m_cmdList->CopyTextureRegion(&dstRegion, 0, 0, 0, &srcRegion, &srcBox); + } +} + +void ResourceCommandEncoderImpl::textureSubresourceBarrier( + ITextureResource* texture, + SubresourceRange subresourceRange, + ResourceState src, + ResourceState dst) +{ + auto textureImpl = static_cast<TextureResourceImpl*>(texture); + + ShortList<D3D12_RESOURCE_BARRIER> barriers; + D3D12_RESOURCE_BARRIER barrier; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + if (src == dst && src == ResourceState::UnorderedAccess) + { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = textureImpl->m_resource.getResource(); + barriers.add(barrier); + } + else + { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3DUtil::getResourceState(src); + barrier.Transition.StateAfter = D3DUtil::getResourceState(dst); + if (barrier.Transition.StateBefore == barrier.Transition.StateAfter) + return; + barrier.Transition.pResource = textureImpl->m_resource.getResource(); + auto d3dFormat = D3DUtil::getMapFormat(textureImpl->getDesc()->format); + auto aspectMask = (int32_t)subresourceRange.aspectMask; + if (subresourceRange.aspectMask == TextureAspect::Default) + aspectMask = (int32_t)TextureAspect::Color; + while (aspectMask) + { + auto aspect = Math::getLowestBit((int32_t)aspectMask); + aspectMask &= ~aspect; + auto planeIndex = D3DUtil::getPlaneSlice(d3dFormat, (TextureAspect)aspect); + for (GfxCount layer = 0; layer < subresourceRange.layerCount; layer++) + { + for (GfxCount mip = 0; mip < subresourceRange.mipLevelCount; mip++) + { + barrier.Transition.Subresource = D3DUtil::getSubresourceIndex( + mip + subresourceRange.mipLevel, + layer + subresourceRange.baseArrayLayer, + planeIndex, + textureImpl->getDesc()->numMipLevels, + textureImpl->getDesc()->arraySize); + barriers.add(barrier); + } + } + } + } + m_commandBuffer->m_cmdList->ResourceBarrier( + (UINT)barriers.getCount(), barriers.getArrayView().getBuffer()); +} + +void ResourceCommandEncoderImpl::beginDebugEvent(const char* name, float rgbColor[3]) +{ + auto beginEvent = m_commandBuffer->m_renderer->m_BeginEventOnCommandList; + if (beginEvent) + { + beginEvent( + m_commandBuffer->m_cmdList, + 0xff000000 | (uint8_t(rgbColor[0] * 255.0f) << 16) | + (uint8_t(rgbColor[1] * 255.0f) << 8) | uint8_t(rgbColor[2] * 255.0f), + name); + } +} + +void ResourceCommandEncoderImpl::endDebugEvent() +{ + auto endEvent = m_commandBuffer->m_renderer->m_EndEventOnCommandList; + if (endEvent) + { + endEvent(m_commandBuffer->m_cmdList); + } +} + +void ResourceCommandEncoderImpl::copyBuffer( + IBufferResource* dst, Offset dstOffset, IBufferResource* src, Offset srcOffset, Size size) +{ + auto dstBuffer = static_cast<BufferResourceImpl*>(dst); + auto srcBuffer = static_cast<BufferResourceImpl*>(src); + + m_commandBuffer->m_cmdList->CopyBufferRegion( + dstBuffer->m_resource.getResource(), + dstOffset, + srcBuffer->m_resource.getResource(), + srcOffset, + size); +} + +void ResourceCommandEncoderImpl::uploadBufferData( + IBufferResource* dst, Offset offset, Size size, void* data) +{ + uploadBufferDataImpl( + m_commandBuffer->m_renderer->m_device, + m_commandBuffer->m_cmdList, + m_commandBuffer->m_transientHeap, + static_cast<BufferResourceImpl*>(dst), + offset, + size, + data); +} + +void ResourceCommandEncoderImpl::textureBarrier( + GfxCount count, ITextureResource* const* textures, ResourceState src, ResourceState dst) +{ + ShortList<D3D12_RESOURCE_BARRIER> barriers; + + for (GfxIndex i = 0; i < count; i++) + { + auto textureImpl = static_cast<TextureResourceImpl*>(textures[i]); + auto d3dFormat = D3DUtil::getMapFormat(textureImpl->getDesc()->format); + auto textureDesc = textureImpl->getDesc(); + D3D12_RESOURCE_BARRIER barrier; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + if (src == dst && src == ResourceState::UnorderedAccess) + { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = textureImpl->m_resource.getResource(); + } + else + { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3DUtil::getResourceState(src); + barrier.Transition.StateAfter = D3DUtil::getResourceState(dst); + if (barrier.Transition.StateBefore == barrier.Transition.StateAfter) + continue; + barrier.Transition.pResource = textureImpl->m_resource.getResource(); + auto planeCount = + D3DUtil::getPlaneSliceCount(D3DUtil::getMapFormat(textureImpl->getDesc()->format)); + auto arraySize = textureDesc->arraySize; + if (arraySize == 0) + arraySize = 1; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + } + barriers.add(barrier); + } + if (barriers.getCount()) + { + m_commandBuffer->m_cmdList->ResourceBarrier( + (UINT)barriers.getCount(), barriers.getArrayView().getBuffer()); + } +} + +void RenderCommandEncoderImpl::init( + DeviceImpl* renderer, + TransientResourceHeapImpl* transientHeap, + CommandBufferImpl* cmdBuffer, + RenderPassLayoutImpl* renderPass, + FramebufferImpl* framebuffer) +{ + PipelineCommandEncoder::init(cmdBuffer); + m_preCmdList = nullptr; + m_renderPass = renderPass; + m_framebuffer = framebuffer; + m_transientHeap = transientHeap; + m_boundVertexBuffers.clear(); + m_boundIndexBuffer = nullptr; + m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + m_primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + m_boundIndexFormat = DXGI_FORMAT_UNKNOWN; + m_boundIndexOffset = 0; + m_currentPipeline = nullptr; + + // Set render target states. + if (!framebuffer) + { + return; + } + m_d3dCmdList->OMSetRenderTargets( + (UINT)framebuffer->renderTargetViews.getCount(), + framebuffer->renderTargetDescriptors.getArrayView().getBuffer(), + FALSE, + framebuffer->depthStencilView ? &framebuffer->depthStencilDescriptor : nullptr); + + // Issue clear commands based on render pass set up. + for (Index i = 0; i < framebuffer->renderTargetViews.getCount(); i++) + { + if (i >= renderPass->m_renderTargetAccesses.getCount()) + continue; + + auto& access = renderPass->m_renderTargetAccesses[i]; + + // Transit resource states. + { + D3D12BarrierSubmitter submitter(m_d3dCmdList); + auto resourceViewImpl = framebuffer->renderTargetViews[i].Ptr(); + if (resourceViewImpl) + { + auto textureResource = + static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr()); + if (textureResource) + { + D3D12_RESOURCE_STATES initialState; + if (access.initialState == ResourceState::Undefined) + { + initialState = textureResource->m_defaultState; + } + else + { + initialState = D3DUtil::getResourceState(access.initialState); + } + textureResource->m_resource.transition( + initialState, D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); + } + } + } + // Clear. + if (access.loadOp == IRenderPassLayout::TargetLoadOp::Clear) + { + m_d3dCmdList->ClearRenderTargetView( + framebuffer->renderTargetDescriptors[i], + framebuffer->renderTargetClearValues[i].values, + 0, + nullptr); + } + } + + if (renderPass->m_hasDepthStencil) + { + // Transit resource states. + { + D3D12BarrierSubmitter submitter(m_d3dCmdList); + auto resourceViewImpl = framebuffer->depthStencilView.Ptr(); + auto textureResource = + static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr()); + D3D12_RESOURCE_STATES initialState; + if (renderPass->m_depthStencilAccess.initialState == ResourceState::Undefined) + { + initialState = textureResource->m_defaultState; + } + else + { + initialState = + D3DUtil::getResourceState(renderPass->m_depthStencilAccess.initialState); + } + textureResource->m_resource.transition( + initialState, D3D12_RESOURCE_STATE_DEPTH_WRITE, submitter); + } + // Clear. + uint32_t clearFlags = 0; + if (renderPass->m_depthStencilAccess.loadOp == IRenderPassLayout::TargetLoadOp::Clear) + { + clearFlags |= D3D12_CLEAR_FLAG_DEPTH; + } + if (renderPass->m_depthStencilAccess.stencilLoadOp == + IRenderPassLayout::TargetLoadOp::Clear) + { + clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + } + if (clearFlags) + { + m_d3dCmdList->ClearDepthStencilView( + framebuffer->depthStencilDescriptor, + (D3D12_CLEAR_FLAGS)clearFlags, + framebuffer->depthStencilClearValue.depth, + framebuffer->depthStencilClearValue.stencil, + 0, + nullptr); + } + } +} + +Result RenderCommandEncoderImpl::bindPipeline(IPipelineState* state, IShaderObject** outRootObject) +{ + return bindPipelineImpl(state, outRootObject); +} + +Result RenderCommandEncoderImpl::bindPipelineWithRootObject( + IPipelineState* state, IShaderObject* rootObject) +{ + return bindPipelineWithRootObjectImpl(state, rootObject); +} + +void RenderCommandEncoderImpl::setViewports(GfxCount count, const Viewport* viewports) +{ + static const int kMaxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + assert(count <= kMaxViewports && count <= kMaxRTVCount); + for (GfxIndex ii = 0; ii < count; ++ii) + { + auto& inViewport = viewports[ii]; + auto& dxViewport = m_viewports[ii]; + + dxViewport.TopLeftX = inViewport.originX; + dxViewport.TopLeftY = inViewport.originY; + dxViewport.Width = inViewport.extentX; + dxViewport.Height = inViewport.extentY; + dxViewport.MinDepth = inViewport.minZ; + dxViewport.MaxDepth = inViewport.maxZ; + } + m_d3dCmdList->RSSetViewports(UINT(count), m_viewports); +} + +void RenderCommandEncoderImpl::setScissorRects(GfxCount count, const ScissorRect* rects) +{ + static const int kMaxScissorRects = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + assert(count <= kMaxScissorRects && count <= kMaxRTVCount); + + for (GfxIndex ii = 0; ii < count; ++ii) + { + auto& inRect = rects[ii]; + auto& dxRect = m_scissorRects[ii]; + + dxRect.left = LONG(inRect.minX); + dxRect.top = LONG(inRect.minY); + dxRect.right = LONG(inRect.maxX); + dxRect.bottom = LONG(inRect.maxY); + } + + m_d3dCmdList->RSSetScissorRects(UINT(count), m_scissorRects); +} + +void RenderCommandEncoderImpl::setPrimitiveTopology(PrimitiveTopology topology) +{ + m_primitiveTopologyType = D3DUtil::getPrimitiveType(topology); + m_primitiveTopology = D3DUtil::getPrimitiveTopology(topology); +} + +void RenderCommandEncoderImpl::setVertexBuffers( + GfxIndex startSlot, + GfxCount slotCount, + IBufferResource* const* buffers, + const Offset* offsets) +{ + { + const Index num = startSlot + slotCount; + if (num > m_boundVertexBuffers.getCount()) + { + m_boundVertexBuffers.setCount(num); + } + } + + for (GfxIndex i = 0; i < slotCount; i++) + { + BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]); + + BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i]; + boundBuffer.m_buffer = buffer; + boundBuffer.m_offset = int(offsets[i]); + } +} + +void RenderCommandEncoderImpl::setIndexBuffer( + IBufferResource* buffer, Format indexFormat, Offset offset) +{ + m_boundIndexBuffer = (BufferResourceImpl*)buffer; + m_boundIndexFormat = D3DUtil::getMapFormat(indexFormat); + m_boundIndexOffset = (UINT)offset; +} + +void RenderCommandEncoderImpl::prepareDraw() +{ + auto pipelineState = m_currentPipeline.Ptr(); + if (!pipelineState || (pipelineState->desc.type != PipelineType::Graphics)) + { + assert(!"No graphics pipeline state set"); + return; + } + + // Submit - setting for graphics + { + GraphicsSubmitter submitter(m_d3dCmdList); + RefPtr<PipelineStateBase> newPipeline; + if (SLANG_FAILED(_bindRenderState(&submitter, newPipeline))) + { + assert(!"Failed to bind render state"); + } + } + + m_d3dCmdList->IASetPrimitiveTopology(m_primitiveTopology); + + // Set up vertex buffer views + { + auto inputLayout = (InputLayoutImpl*)pipelineState->inputLayout.Ptr(); + if (inputLayout) + { + int numVertexViews = 0; + D3D12_VERTEX_BUFFER_VIEW vertexViews[16]; + for (Index i = 0; i < m_boundVertexBuffers.getCount(); i++) + { + const BoundVertexBuffer& boundVertexBuffer = m_boundVertexBuffers[i]; + BufferResourceImpl* buffer = boundVertexBuffer.m_buffer; + if (buffer) + { + D3D12_VERTEX_BUFFER_VIEW& vertexView = vertexViews[numVertexViews++]; + vertexView.BufferLocation = + buffer->m_resource.getResource()->GetGPUVirtualAddress() + + boundVertexBuffer.m_offset; + vertexView.SizeInBytes = + UINT(buffer->getDesc()->sizeInBytes - boundVertexBuffer.m_offset); + vertexView.StrideInBytes = inputLayout->m_vertexStreamStrides[i]; + } + } + m_d3dCmdList->IASetVertexBuffers(0, numVertexViews, vertexViews); + } + } + // Set up index buffer + if (m_boundIndexBuffer) + { + D3D12_INDEX_BUFFER_VIEW indexBufferView; + indexBufferView.BufferLocation = + m_boundIndexBuffer->m_resource.getResource()->GetGPUVirtualAddress() + + m_boundIndexOffset; + indexBufferView.SizeInBytes = + UINT(m_boundIndexBuffer->getDesc()->sizeInBytes - m_boundIndexOffset); + indexBufferView.Format = m_boundIndexFormat; + + m_d3dCmdList->IASetIndexBuffer(&indexBufferView); + } +} + +void RenderCommandEncoderImpl::draw(GfxCount vertexCount, GfxIndex startVertex) +{ + prepareDraw(); + m_d3dCmdList->DrawInstanced((uint32_t)vertexCount, 1, (uint32_t)startVertex, 0); +} + +void RenderCommandEncoderImpl::drawIndexed( + GfxCount indexCount, GfxIndex startIndex, GfxIndex baseVertex) +{ + prepareDraw(); + m_d3dCmdList->DrawIndexedInstanced((uint32_t)indexCount, 1, (uint32_t)startIndex, (uint32_t)baseVertex, 0); +} + +void RenderCommandEncoderImpl::endEncoding() +{ + PipelineCommandEncoder::endEncodingImpl(); + if (!m_framebuffer) + return; + // Issue clear commands based on render pass set up. + for (Index i = 0; i < m_renderPass->m_renderTargetAccesses.getCount(); i++) + { + auto& access = m_renderPass->m_renderTargetAccesses[i]; + + // Transit resource states. + { + D3D12BarrierSubmitter submitter(m_d3dCmdList); + auto resourceViewImpl = m_framebuffer->renderTargetViews[i].Ptr(); + if (!resourceViewImpl) + continue; + auto textureResource = + static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr()); + if (textureResource) + { + textureResource->m_resource.transition( + D3D12_RESOURCE_STATE_RENDER_TARGET, + D3DUtil::getResourceState(access.finalState), + submitter); + } + } + } + + if (m_renderPass->m_hasDepthStencil) + { + // Transit resource states. + D3D12BarrierSubmitter submitter(m_d3dCmdList); + auto resourceViewImpl = m_framebuffer->depthStencilView.Ptr(); + auto textureResource = + static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr()); + textureResource->m_resource.transition( + D3D12_RESOURCE_STATE_DEPTH_WRITE, + D3DUtil::getResourceState(m_renderPass->m_depthStencilAccess.finalState), + submitter); + } + m_framebuffer = nullptr; +} + +void RenderCommandEncoderImpl::setStencilReference(uint32_t referenceValue) +{ + m_d3dCmdList->OMSetStencilRef((UINT)referenceValue); +} + +void RenderCommandEncoderImpl::drawIndirect( + GfxCount maxDrawCount, + IBufferResource* argBuffer, + Offset argOffset, + IBufferResource* countBuffer, + Offset countOffset) +{ + prepareDraw(); + + auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer); + auto countBufferImpl = static_cast<BufferResourceImpl*>(countBuffer); + + m_d3dCmdList->ExecuteIndirect( + m_renderer->drawIndirectCmdSignature, + (uint32_t)maxDrawCount, + argBufferImpl->m_resource, + (uint64_t)argOffset, + countBufferImpl ? countBufferImpl->m_resource.getResource() : nullptr, + (uint64_t)countOffset); +} + +void RenderCommandEncoderImpl::drawIndexedIndirect( + GfxCount maxDrawCount, + IBufferResource* argBuffer, + Offset argOffset, + IBufferResource* countBuffer, + Offset countOffset) +{ + prepareDraw(); + + auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer); + auto countBufferImpl = static_cast<BufferResourceImpl*>(countBuffer); + + m_d3dCmdList->ExecuteIndirect( + m_renderer->drawIndexedIndirectCmdSignature, + (uint32_t)maxDrawCount, + argBufferImpl->m_resource, + (uint64_t)argOffset, + countBufferImpl ? countBufferImpl->m_resource.getResource() : nullptr, + (uint64_t)countOffset); +} + +Result RenderCommandEncoderImpl::setSamplePositions( + GfxCount samplesPerPixel, GfxCount pixelCount, const SamplePosition* samplePositions) +{ + if (m_commandBuffer->m_cmdList1) + { + m_commandBuffer->m_cmdList1->SetSamplePositions( + (uint32_t)samplesPerPixel, (uint32_t)pixelCount, (D3D12_SAMPLE_POSITION*)samplePositions); + return SLANG_OK; + } + return SLANG_E_NOT_AVAILABLE; +} + +void RenderCommandEncoderImpl::drawInstanced( + GfxCount vertexCount, + GfxCount instanceCount, + GfxIndex startVertex, + GfxIndex startInstanceLocation) +{ + prepareDraw(); + m_d3dCmdList->DrawInstanced( + (uint32_t)vertexCount, + (uint32_t)instanceCount, + (uint32_t)startVertex, + (uint32_t)startInstanceLocation); +} + +void RenderCommandEncoderImpl::drawIndexedInstanced( + GfxCount indexCount, + GfxCount instanceCount, + GfxIndex startIndexLocation, + GfxIndex baseVertexLocation, + GfxIndex startInstanceLocation) +{ + prepareDraw(); + m_d3dCmdList->DrawIndexedInstanced( + (uint32_t)indexCount, + (uint32_t)instanceCount, + (uint32_t)startIndexLocation, + baseVertexLocation, + (uint32_t)startInstanceLocation); +} + +void ComputeCommandEncoderImpl::endEncoding() { PipelineCommandEncoder::endEncodingImpl(); } + +void ComputeCommandEncoderImpl::init( + DeviceImpl* renderer, TransientResourceHeapImpl* transientHeap, CommandBufferImpl* cmdBuffer) +{ + PipelineCommandEncoder::init(cmdBuffer); + m_preCmdList = nullptr; + m_transientHeap = transientHeap; + m_currentPipeline = nullptr; +} + +Result ComputeCommandEncoderImpl::bindPipeline(IPipelineState* state, IShaderObject** outRootObject) +{ + return bindPipelineImpl(state, outRootObject); +} + +Result ComputeCommandEncoderImpl::bindPipelineWithRootObject( + IPipelineState* state, IShaderObject* rootObject) +{ + return bindPipelineWithRootObjectImpl(state, rootObject); +} + +void ComputeCommandEncoderImpl::dispatchCompute(int x, int y, int z) +{ + // Submit binding for compute + { + ComputeSubmitter submitter(m_d3dCmdList); + RefPtr<PipelineStateBase> newPipeline; + if (SLANG_FAILED(_bindRenderState(&submitter, newPipeline))) + { + assert(!"Failed to bind render state"); + } + } + m_d3dCmdList->Dispatch(x, y, z); +} + +void ComputeCommandEncoderImpl::dispatchComputeIndirect(IBufferResource* argBuffer, Offset offset) +{ + // Submit binding for compute + { + ComputeSubmitter submitter(m_d3dCmdList); + RefPtr<PipelineStateBase> newPipeline; + if (SLANG_FAILED(_bindRenderState(&submitter, newPipeline))) + { + assert(!"Failed to bind render state"); + } + } + auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer); + + m_d3dCmdList->ExecuteIndirect( + m_renderer->dispatchIndirectCmdSignature, 1, argBufferImpl->m_resource, (uint64_t)offset, nullptr, 0); +} + +#if SLANG_GFX_HAS_DXR_SUPPORT + +void RayTracingCommandEncoderImpl::buildAccelerationStructure( + const IAccelerationStructure::BuildDesc& desc, + GfxCount propertyQueryCount, + AccelerationStructureQueryDesc* queryDescs) +{ + if (!m_commandBuffer->m_cmdList4) + { + getDebugCallback()->handleMessage( + DebugMessageType::Error, + DebugMessageSource::Layer, + "Ray-tracing is not supported on current system."); + return; + } + AccelerationStructureImpl* destASImpl = nullptr; + if (desc.dest) + destASImpl = static_cast<AccelerationStructureImpl*>(desc.dest); + AccelerationStructureImpl* srcASImpl = nullptr; + if (desc.source) + srcASImpl = static_cast<AccelerationStructureImpl*>(desc.source); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; + buildDesc.DestAccelerationStructureData = destASImpl->getDeviceAddress(); + buildDesc.SourceAccelerationStructureData = srcASImpl ? srcASImpl->getDeviceAddress() : 0; + buildDesc.ScratchAccelerationStructureData = desc.scratchData; + D3DAccelerationStructureInputsBuilder builder; + builder.build(desc.inputs, getDebugCallback()); + buildDesc.Inputs = builder.desc; + + List<D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC> postBuildInfoDescs; + translatePostBuildInfoDescs(propertyQueryCount, queryDescs, postBuildInfoDescs); + m_commandBuffer->m_cmdList4->BuildRaytracingAccelerationStructure( + &buildDesc, (UINT)propertyQueryCount, postBuildInfoDescs.getBuffer()); +} + +void RayTracingCommandEncoderImpl::copyAccelerationStructure( + IAccelerationStructure* dest, IAccelerationStructure* src, AccelerationStructureCopyMode mode) +{ + auto destASImpl = static_cast<AccelerationStructureImpl*>(dest); + auto srcASImpl = static_cast<AccelerationStructureImpl*>(src); + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE copyMode; + switch (mode) + { + case AccelerationStructureCopyMode::Clone: + copyMode = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE; + break; + case AccelerationStructureCopyMode::Compact: + copyMode = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_COMPACT; + break; + default: + getDebugCallback()->handleMessage( + DebugMessageType::Error, + DebugMessageSource::Layer, + "Unsupported AccelerationStructureCopyMode."); + return; + } + m_commandBuffer->m_cmdList4->CopyRaytracingAccelerationStructure( + destASImpl->getDeviceAddress(), srcASImpl->getDeviceAddress(), copyMode); +} + +void RayTracingCommandEncoderImpl::queryAccelerationStructureProperties( + GfxCount accelerationStructureCount, + IAccelerationStructure* const* accelerationStructures, + GfxCount queryCount, + AccelerationStructureQueryDesc* queryDescs) +{ + List<D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC> postBuildInfoDescs; + List<DeviceAddress> asAddresses; + asAddresses.setCount(accelerationStructureCount); + for (GfxIndex i = 0; i < accelerationStructureCount; i++) + asAddresses[i] = accelerationStructures[i]->getDeviceAddress(); + translatePostBuildInfoDescs(queryCount, queryDescs, postBuildInfoDescs); + m_commandBuffer->m_cmdList4->EmitRaytracingAccelerationStructurePostbuildInfo( + postBuildInfoDescs.getBuffer(), (UINT)accelerationStructureCount, asAddresses.getBuffer()); +} + +void RayTracingCommandEncoderImpl::serializeAccelerationStructure( + DeviceAddress dest, IAccelerationStructure* src) +{ + auto srcASImpl = static_cast<AccelerationStructureImpl*>(src); + m_commandBuffer->m_cmdList4->CopyRaytracingAccelerationStructure( + dest, + srcASImpl->getDeviceAddress(), + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_SERIALIZE); +} + +void RayTracingCommandEncoderImpl::deserializeAccelerationStructure( + IAccelerationStructure* dest, DeviceAddress source) +{ + auto destASImpl = static_cast<AccelerationStructureImpl*>(dest); + m_commandBuffer->m_cmdList4->CopyRaytracingAccelerationStructure( + dest->getDeviceAddress(), + source, + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_DESERIALIZE); +} + +void RayTracingCommandEncoderImpl::bindPipeline( + IPipelineState* state, IShaderObject** outRootObject) +{ + bindPipelineImpl(state, outRootObject); +} + +void RayTracingCommandEncoderImpl::dispatchRays( + GfxIndex rayGenShaderIndex, + IShaderTable* shaderTable, + GfxCount width, + GfxCount height, + GfxCount depth) +{ + RefPtr<PipelineStateBase> newPipeline; + PipelineStateBase* pipeline = m_currentPipeline.Ptr(); + { + struct RayTracingSubmitter : public ComputeSubmitter + { + ID3D12GraphicsCommandList4* m_cmdList4; + RayTracingSubmitter(ID3D12GraphicsCommandList4* cmdList4) + : ComputeSubmitter(cmdList4) + , m_cmdList4(cmdList4) + {} + virtual void setPipelineState(PipelineStateBase* pipeline) override + { + auto pipelineImpl = static_cast<RayTracingPipelineStateImpl*>(pipeline); + m_cmdList4->SetPipelineState1(pipelineImpl->m_stateObject.get()); + } + }; + RayTracingSubmitter submitter(m_commandBuffer->m_cmdList4); + if (SLANG_FAILED(_bindRenderState(&submitter, newPipeline))) + { + assert(!"Failed to bind render state"); + } + if (newPipeline) + pipeline = newPipeline.Ptr(); + } + auto pipelineImpl = static_cast<RayTracingPipelineStateImpl*>(pipeline); + + auto shaderTableImpl = static_cast<ShaderTableImpl*>(shaderTable); + + auto shaderTableBuffer = + shaderTableImpl->getOrCreateBuffer(pipelineImpl, m_transientHeap, static_cast<ResourceCommandEncoderImpl*>(this)); + auto shaderTableAddr = shaderTableBuffer->getDeviceAddress(); + + D3D12_DISPATCH_RAYS_DESC dispatchDesc = {}; + + dispatchDesc.RayGenerationShaderRecord.StartAddress = + shaderTableAddr + shaderTableImpl->m_rayGenTableOffset + + rayGenShaderIndex * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + dispatchDesc.RayGenerationShaderRecord.SizeInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + + dispatchDesc.MissShaderTable.StartAddress = + shaderTableAddr + shaderTableImpl->m_missTableOffset; + dispatchDesc.MissShaderTable.SizeInBytes = + shaderTableImpl->m_missShaderCount * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + dispatchDesc.MissShaderTable.StrideInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + + dispatchDesc.HitGroupTable.StartAddress = + shaderTableAddr + shaderTableImpl->m_hitGroupTableOffset; + dispatchDesc.HitGroupTable.SizeInBytes = + shaderTableImpl->m_hitGroupCount * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + dispatchDesc.HitGroupTable.StrideInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + + dispatchDesc.Width = (UINT)width; + dispatchDesc.Height = (UINT)height; + dispatchDesc.Depth = (UINT)depth; + m_commandBuffer->m_cmdList4->DispatchRays(&dispatchDesc); +} + +#endif + +} // namespace d3d12 +} // namespace gfx |
