diff options
| author | lucy96chen <47800040+lucy96chen@users.noreply.github.com> | 2022-05-17 10:56:14 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-17 10:56:14 -0700 |
| commit | 5a3aa6159e0ef0241b528812e1d138f0d7055f22 (patch) | |
| tree | 71d286e06030ee73f0b739e071cd58dd05d507d1 /tools/gfx/d3d12/render-d3d12.cpp | |
| parent | 716e75b9ed1acfaee3dc7f3bc347ad17fca65e05 (diff) | |
Split render-d3d12.h/cpp into a set of smaller files (#2231)
* Split render-d3d12 into numerous smaller files to make the code easier to parse
* Added all new D3D12 files created from splitting render-d3d12
* Fixed several uses of attachment still floating around; Changed resource-d3d12 and descriptor-heap-d3d12 to match naming conventions of new d3d12 implementation header files
* Readded files with name changes because changing them from inside VS apparently results in them being treated as new files
* Merged in externals changes from master
* Small cleanup changes
* Rerun CI
Co-authored-by: Theresa Foley <10618364+tangent-vector@users.noreply.github.com>
Diffstat (limited to 'tools/gfx/d3d12/render-d3d12.cpp')
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 7667 |
1 files changed, 0 insertions, 7667 deletions
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp deleted file mode 100644 index 2506c3b63..000000000 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ /dev/null @@ -1,7667 +0,0 @@ -// render-d3d12.cpp -#include "render-d3d12.h" - -#ifdef GFX_NVAPI -# include "../nvapi/nvapi-include.h" -#endif - -#include "../d3d/d3d-util.h" -#include "../flag-combiner.h" -#include "../nvapi/nvapi-util.h" -#include "slang-com-ptr.h" -#include <stdio.h> - -#ifdef _DEBUG -# define ENABLE_DEBUG_LAYER 1 -#else -# define ENABLE_DEBUG_LAYER 0 -#endif - -namespace gfx -{ -using namespace Slang; - -namespace d3d12 -{ - -namespace -{ -bool isSupportedNVAPIOp(ID3D12Device* dev, uint32_t op) -{ -#ifdef GFX_NVAPI - { - bool isSupported; - NvAPI_Status status = - NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(dev, NvU32(op), &isSupported); - return status == NVAPI_OK && isSupported; - } -#else - return false; -#endif -} - -D3D12_RESOURCE_FLAGS calcResourceFlag(ResourceState state) -{ - switch (state) - { - case ResourceState::RenderTarget: - return D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - case ResourceState::DepthRead: - case ResourceState::DepthWrite: - return D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - case ResourceState::UnorderedAccess: - case ResourceState::AccelerationStructure: - return D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - default: - return D3D12_RESOURCE_FLAG_NONE; - } -} - -D3D12_RESOURCE_FLAGS calcResourceFlags(ResourceStateSet states) -{ - int dstFlags = 0; - for (uint32_t i = 0; i < (uint32_t)ResourceState::_Count; i++) - { - auto state = (ResourceState)i; - if (states.contains(state)) - dstFlags |= calcResourceFlag(state); - } - return (D3D12_RESOURCE_FLAGS)dstFlags; -} - -D3D12_RESOURCE_DIMENSION calcResourceDimension(IResource::Type type) -{ - switch (type) - { - case IResource::Type::Buffer: - return D3D12_RESOURCE_DIMENSION_BUFFER; - case IResource::Type::Texture1D: - return D3D12_RESOURCE_DIMENSION_TEXTURE1D; - case IResource::Type::TextureCube: - case IResource::Type::Texture2D: - { - return D3D12_RESOURCE_DIMENSION_TEXTURE2D; - } - case IResource::Type::Texture3D: - return D3D12_RESOURCE_DIMENSION_TEXTURE3D; - default: - return D3D12_RESOURCE_DIMENSION_UNKNOWN; - } -} - -DXGI_FORMAT getTypelessFormatFromDepthFormat(Format format) -{ - switch (format) - { - case Format::D16_UNORM: - return DXGI_FORMAT_R16_TYPELESS; - case Format::D32_FLOAT: - return DXGI_FORMAT_R32_TYPELESS; - default: - return D3DUtil::getMapFormat(format); - } -} - -bool isTypelessDepthFormat(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R32_TYPELESS: - return true; - default: - return false; - } -} - -D3D12_FILTER_TYPE translateFilterMode(TextureFilteringMode mode) -{ - switch (mode) - { - default: - return D3D12_FILTER_TYPE(0); - -#define CASE(SRC, DST) \ - case TextureFilteringMode::SRC: \ - return D3D12_FILTER_TYPE_##DST - - CASE(Point, POINT); - CASE(Linear, LINEAR); - -#undef CASE - } -} - -D3D12_FILTER_REDUCTION_TYPE translateFilterReduction(TextureReductionOp op) -{ - switch (op) - { - default: - return D3D12_FILTER_REDUCTION_TYPE(0); - -#define CASE(SRC, DST) \ - case TextureReductionOp::SRC: \ - return D3D12_FILTER_REDUCTION_TYPE_##DST - - CASE(Average, STANDARD); - CASE(Comparison, COMPARISON); - CASE(Minimum, MINIMUM); - CASE(Maximum, MAXIMUM); - -#undef CASE - } -} - -D3D12_TEXTURE_ADDRESS_MODE translateAddressingMode(TextureAddressingMode mode) -{ - switch (mode) - { - default: - return D3D12_TEXTURE_ADDRESS_MODE(0); - -#define CASE(SRC, DST) \ - case TextureAddressingMode::SRC: \ - return D3D12_TEXTURE_ADDRESS_MODE_##DST - - CASE(Wrap, WRAP); - CASE(ClampToEdge, CLAMP); - CASE(ClampToBorder, BORDER); - CASE(MirrorRepeat, MIRROR); - CASE(MirrorOnce, MIRROR_ONCE); - -#undef CASE - } -} - -D3D12_COMPARISON_FUNC translateComparisonFunc(ComparisonFunc func) -{ - switch (func) - { - default: - // TODO: need to report failures - return D3D12_COMPARISON_FUNC_ALWAYS; - -#define CASE(FROM, TO) \ - case ComparisonFunc::FROM: \ - return D3D12_COMPARISON_FUNC_##TO - - CASE(Never, NEVER); - CASE(Less, LESS); - CASE(Equal, EQUAL); - CASE(LessEqual, LESS_EQUAL); - CASE(Greater, GREATER); - CASE(NotEqual, NOT_EQUAL); - CASE(GreaterEqual, GREATER_EQUAL); - CASE(Always, ALWAYS); -#undef CASE - } -} - -uint32_t getViewDescriptorCount(const ITransientResourceHeap::Desc& desc) -{ - return Math::Max( - Math::Max( - desc.srvDescriptorCount, - desc.uavDescriptorCount, - desc.accelerationStructureDescriptorCount), - desc.constantBufferDescriptorCount, - 2048); -} - -void initSrvDesc( - IResource::Type resourceType, - const ITextureResource::Desc& textureDesc, - const D3D12_RESOURCE_DESC& desc, - DXGI_FORMAT pixelFormat, - SubresourceRange subresourceRange, - D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) -{ - // create SRV - descOut = D3D12_SHADER_RESOURCE_VIEW_DESC(); - - descOut.Format = (pixelFormat == DXGI_FORMAT_UNKNOWN) - ? D3DUtil::calcFormat(D3DUtil::USAGE_SRV, desc.Format) - : pixelFormat; - descOut.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - if (desc.DepthOrArraySize == 1) - { - switch (desc.Dimension) - { - case D3D12_RESOURCE_DIMENSION_TEXTURE1D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; - descOut.Texture1D.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - descOut.Texture1D.MostDetailedMip = subresourceRange.mipLevel; - break; - case D3D12_RESOURCE_DIMENSION_TEXTURE2D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - descOut.Texture2D.PlaneSlice = - D3DUtil::getPlaneSlice(descOut.Format, subresourceRange.aspectMask); - descOut.Texture2D.ResourceMinLODClamp = 0.0f; - descOut.Texture2D.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - descOut.Texture2D.MostDetailedMip = subresourceRange.mipLevel; - break; - case D3D12_RESOURCE_DIMENSION_TEXTURE3D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; - descOut.Texture3D.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - descOut.Texture3D.MostDetailedMip = subresourceRange.mipLevel; - break; - default: - assert(!"Unknown dimension"); - } - } - else if (resourceType == IResource::Type::TextureCube) - { - if (textureDesc.arraySize > 1) - { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - - descOut.TextureCubeArray.NumCubes = subresourceRange.layerCount == 0 - ? textureDesc.arraySize - : subresourceRange.layerCount / 6; - descOut.TextureCubeArray.First2DArrayFace = subresourceRange.baseArrayLayer; - descOut.TextureCubeArray.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - descOut.TextureCubeArray.MostDetailedMip = subresourceRange.mipLevel; - descOut.TextureCubeArray.ResourceMinLODClamp = 0; - } - else - { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - - descOut.TextureCube.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - descOut.TextureCube.MostDetailedMip = subresourceRange.mipLevel; - descOut.TextureCube.ResourceMinLODClamp = 0; - } - } - else - { - assert(desc.DepthOrArraySize > 1); - - switch (desc.Dimension) - { - case D3D12_RESOURCE_DIMENSION_TEXTURE1D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; - descOut.Texture1D.MostDetailedMip = subresourceRange.mipLevel; - descOut.Texture1D.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - : subresourceRange.mipLevelCount; - descOut.Texture1DArray.ArraySize = subresourceRange.layerCount == 0 - ? desc.DepthOrArraySize - : subresourceRange.layerCount; - descOut.Texture1DArray.FirstArraySlice = subresourceRange.baseArrayLayer; - descOut.Texture1DArray.ResourceMinLODClamp = 0; - descOut.Texture1DArray.MostDetailedMip = subresourceRange.mipLevel; - descOut.Texture1DArray.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - break; - case D3D12_RESOURCE_DIMENSION_TEXTURE2D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - descOut.Texture2DArray.ArraySize = subresourceRange.layerCount == 0 - ? desc.DepthOrArraySize - : subresourceRange.layerCount; - descOut.Texture2DArray.FirstArraySlice = subresourceRange.baseArrayLayer; - descOut.Texture2DArray.PlaneSlice = - D3DUtil::getPlaneSlice(descOut.Format, subresourceRange.aspectMask); - descOut.Texture2DArray.ResourceMinLODClamp = 0; - descOut.Texture2DArray.MostDetailedMip = subresourceRange.mipLevel; - descOut.Texture2DArray.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - subresourceRange.mipLevel - : subresourceRange.mipLevelCount; - break; - case D3D12_RESOURCE_DIMENSION_TEXTURE3D: - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; - descOut.Texture3D.MostDetailedMip = subresourceRange.mipLevel; - descOut.Texture3D.MipLevels = subresourceRange.mipLevelCount == 0 - ? desc.MipLevels - : subresourceRange.mipLevelCount; - break; - - default: - assert(!"Unknown dimension"); - } - } -} - -Result initTextureResourceDesc( - D3D12_RESOURCE_DESC& resourceDesc, const ITextureResource::Desc& srcDesc) -{ - const DXGI_FORMAT pixelFormat = D3DUtil::getMapFormat(srcDesc.format); - if (pixelFormat == DXGI_FORMAT_UNKNOWN) - { - return SLANG_FAIL; - } - - const int arraySize = calcEffectiveArraySize(srcDesc); - - const D3D12_RESOURCE_DIMENSION dimension = calcResourceDimension(srcDesc.type); - if (dimension == D3D12_RESOURCE_DIMENSION_UNKNOWN) - { - return SLANG_FAIL; - } - - const int numMipMaps = srcDesc.numMipLevels; - resourceDesc.Dimension = dimension; - resourceDesc.Format = pixelFormat; - resourceDesc.Width = srcDesc.size.width; - resourceDesc.Height = srcDesc.size.height; - resourceDesc.DepthOrArraySize = (srcDesc.size.depth > 1) ? srcDesc.size.depth : arraySize; - - resourceDesc.MipLevels = numMipMaps; - resourceDesc.SampleDesc.Count = srcDesc.sampleDesc.numSamples; - resourceDesc.SampleDesc.Quality = srcDesc.sampleDesc.quality; - - resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - - resourceDesc.Flags |= calcResourceFlags(srcDesc.allowedStates); - - resourceDesc.Alignment = 0; - - if (isDepthFormat(srcDesc.format) && - (srcDesc.allowedStates.contains(ResourceState::ShaderResource) || - srcDesc.allowedStates.contains(ResourceState::UnorderedAccess))) - { - resourceDesc.Format = getTypelessFormatFromDepthFormat(srcDesc.format); - } - - return SLANG_OK; -} - -void initBufferResourceDesc(Size bufferSize, D3D12_RESOURCE_DESC& out) -{ - out = {}; - - out.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - out.Alignment = 0; - out.Width = bufferSize; - out.Height = 1; - out.DepthOrArraySize = 1; - out.MipLevels = 1; - out.Format = DXGI_FORMAT_UNKNOWN; - out.SampleDesc.Count = 1; - out.SampleDesc.Quality = 0; - out.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - out.Flags = D3D12_RESOURCE_FLAG_NONE; -} - -Result uploadBufferDataImpl( - ID3D12Device* device, - ID3D12GraphicsCommandList* cmdList, - TransientResourceHeapImpl* transientHeap, - BufferResourceImpl* buffer, - Offset offset, - Size size, - void* data) -{ - IBufferResource* uploadResource; - Offset uploadResourceOffset = 0; - if (buffer->getDesc()->memoryType != MemoryType::Upload) - { - SLANG_RETURN_ON_FAIL(transientHeap->allocateStagingBuffer( - size, uploadResource, uploadResourceOffset, MemoryType::Upload)); - } - - D3D12Resource& uploadResourceRef = - (buffer->getDesc()->memoryType == MemoryType::Upload) - ? buffer->m_resource - : static_cast<BufferResourceImpl*>(uploadResource)->m_resource; - - D3D12_RANGE readRange = {}; - readRange.Begin = 0; - readRange.End = 0; - void* uploadData; - SLANG_RETURN_ON_FAIL( - uploadResourceRef.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&uploadData))); - memcpy((uint8_t*)uploadData + uploadResourceOffset + offset, data, size); - D3D12_RANGE writtenRange = {}; - writtenRange.Begin = uploadResourceOffset + offset; - writtenRange.End = uploadResourceOffset + offset + size; - uploadResourceRef.getResource()->Unmap(0, &writtenRange); - - if (buffer->getDesc()->memoryType != MemoryType::Upload) - { - cmdList->CopyBufferRegion( - buffer->m_resource.getResource(), - offset, - uploadResourceRef.getResource(), - uploadResourceOffset + offset, - size); - } - - return SLANG_OK; -} - -Result createNullDescriptor( - ID3D12Device* d3dDevice, - D3D12_CPU_DESCRIPTOR_HANDLE destDescriptor, - const ShaderObjectLayoutImpl::BindingRangeInfo& bindingRange) -{ - switch (bindingRange.bindingType) - { - case slang::BindingType::ConstantBuffer: - { - D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; - cbvDesc.BufferLocation = 0; - cbvDesc.SizeInBytes = 0; - d3dDevice->CreateConstantBufferView(&cbvDesc, destDescriptor); - } - break; - case slang::BindingType::MutableRawBuffer: - { - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; - d3dDevice->CreateUnorderedAccessView(nullptr, nullptr, &uavDesc, destDescriptor); - } - break; - case slang::BindingType::MutableTypedBuffer: - { - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - d3dDevice->CreateUnorderedAccessView(nullptr, nullptr, &uavDesc, destDescriptor); - } - break; - case slang::BindingType::RawBuffer: - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - d3dDevice->CreateShaderResourceView(nullptr, &srvDesc, destDescriptor); - } - break; - case slang::BindingType::TypedBuffer: - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - d3dDevice->CreateShaderResourceView(nullptr, &srvDesc, destDescriptor); - } - break; - case slang::BindingType::Texture: - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - switch (bindingRange.resourceShape) - { - case SLANG_TEXTURE_1D: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; - break; - case SLANG_TEXTURE_1D_ARRAY: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; - break; - case SLANG_TEXTURE_2D: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - break; - case SLANG_TEXTURE_2D_ARRAY: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - break; - case SLANG_TEXTURE_3D: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; - break; - case SLANG_TEXTURE_CUBE: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - break; - case SLANG_TEXTURE_CUBE_ARRAY: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - break; - case SLANG_TEXTURE_2D_MULTISAMPLE: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; - break; - case SLANG_TEXTURE_2D_MULTISAMPLE_ARRAY: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; - break; - default: - return SLANG_OK; - } - d3dDevice->CreateShaderResourceView(nullptr, &srvDesc, destDescriptor); - } - break; - default: - break; - } - return SLANG_OK; -} -} // namespace - -Result DeviceImpl::createBuffer( - const D3D12_RESOURCE_DESC& resourceDesc, - const void* srcData, - Size srcDataSize, - D3D12_RESOURCE_STATES finalState, - D3D12Resource& resourceOut, - bool isShared, - MemoryType memoryType) -{ - const Size bufferSize = Size(resourceDesc.Width); - - D3D12_HEAP_PROPERTIES heapProps; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE; - if (isShared) - flags |= D3D12_HEAP_FLAG_SHARED; - - D3D12_RESOURCE_DESC desc = resourceDesc; - - D3D12_RESOURCE_STATES initialState = finalState; - - switch (memoryType) - { - case MemoryType::ReadBack: - assert(!srcData); - - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - initialState |= D3D12_RESOURCE_STATE_COPY_DEST; - - break; - case MemoryType::Upload: - - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - initialState |= D3D12_RESOURCE_STATE_GENERIC_READ; - - break; - case MemoryType::DeviceLocal: - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - initialState = (srcData ? D3D12_RESOURCE_STATE_COPY_DEST : finalState); - break; - default: - return SLANG_FAIL; - } - - // Create the resource. - SLANG_RETURN_ON_FAIL( - resourceOut.initCommitted(m_device, heapProps, flags, desc, initialState, nullptr)); - - if (srcData) - { - D3D12Resource uploadResource; - - if (memoryType == MemoryType::DeviceLocal) - { - // If the buffer is on the default heap, create upload buffer. - D3D12_RESOURCE_DESC uploadDesc(resourceDesc); - uploadDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - - SLANG_RETURN_ON_FAIL(uploadResource.initCommitted( - m_device, - heapProps, - D3D12_HEAP_FLAG_NONE, - uploadDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr)); - } - - // Be careful not to actually copy a resource here. - D3D12Resource& uploadResourceRef = - (memoryType == MemoryType::DeviceLocal) ? uploadResource : resourceOut; - - // Copy data to the intermediate upload heap and then schedule a copy - // from the upload heap to the vertex buffer. - UINT8* dstData; - D3D12_RANGE readRange = {}; // We do not intend to read from this resource on the CPU. - - ID3D12Resource* dxUploadResource = uploadResourceRef.getResource(); - - SLANG_RETURN_ON_FAIL( - dxUploadResource->Map(0, &readRange, reinterpret_cast<void**>(&dstData))); - ::memcpy(dstData, srcData, srcDataSize); - dxUploadResource->Unmap(0, nullptr); - - if (memoryType == MemoryType::DeviceLocal) - { - auto encodeInfo = encodeResourceCommands(); - encodeInfo.d3dCommandList->CopyBufferRegion( - resourceOut, 0, uploadResourceRef, 0, bufferSize); - submitResourceCommandsAndWait(encodeInfo); - } - } - - return SLANG_OK; -} - -Result DeviceImpl::captureTextureToSurface( - TextureResourceImpl* resourceImpl, - ResourceState state, - ISlangBlob** outBlob, - Size* outRowPitch, - Size* outPixelSize) -{ - auto& resource = resourceImpl->m_resource; - - const D3D12_RESOURCE_STATES initialState = D3DUtil::getResourceState(state); - - const ITextureResource::Desc& gfxDesc = *resourceImpl->getDesc(); - const D3D12_RESOURCE_DESC desc = resource.getResource()->GetDesc(); - - // Don't bother supporting MSAA for right now - if (desc.SampleDesc.Count > 1) - { - fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); - return SLANG_FAIL; - } - - FormatInfo formatInfo; - gfxGetFormatInfo(gfxDesc.format, &formatInfo); - Size bytesPerPixel = formatInfo.blockSizeInBytes / formatInfo.pixelsPerBlock; - Size rowPitch = int(desc.Width) * bytesPerPixel; - static const Size align = 256; // D3D requires minimum 256 byte alignment for texture data. - rowPitch = (rowPitch + align - 1) & ~(align - 1); // Bit trick for rounding up - Size bufferSize = rowPitch * int(desc.Height) * int(desc.DepthOrArraySize); - if (outRowPitch) - *outRowPitch = rowPitch; - if (outPixelSize) - *outPixelSize = bytesPerPixel; - - D3D12Resource stagingResource; - { - D3D12_RESOURCE_DESC stagingDesc; - initBufferResourceDesc(bufferSize, stagingDesc); - - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - SLANG_RETURN_ON_FAIL(stagingResource.initCommitted( - m_device, - heapProps, - D3D12_HEAP_FLAG_NONE, - stagingDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr)); - } - - auto encodeInfo = encodeResourceCommands(); - auto currentState = D3DUtil::getResourceState(state); - - { - D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList); - resource.transition(currentState, D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); - } - - // Do the copy - { - D3D12_TEXTURE_COPY_LOCATION srcLoc; - srcLoc.pResource = resource; - srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcLoc.SubresourceIndex = 0; - - D3D12_TEXTURE_COPY_LOCATION dstLoc; - dstLoc.pResource = stagingResource; - dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dstLoc.PlacedFootprint.Offset = 0; - dstLoc.PlacedFootprint.Footprint.Format = desc.Format; - dstLoc.PlacedFootprint.Footprint.Width = UINT(desc.Width); - dstLoc.PlacedFootprint.Footprint.Height = UINT(desc.Height); - dstLoc.PlacedFootprint.Footprint.Depth = UINT(desc.DepthOrArraySize); - dstLoc.PlacedFootprint.Footprint.RowPitch = UINT(rowPitch); - - encodeInfo.d3dCommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); - } - - { - D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList); - resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, currentState, submitter); - } - - // Submit the copy, and wait for copy to complete - submitResourceCommandsAndWait(encodeInfo); - - { - ID3D12Resource* dxResource = stagingResource; - - UINT8* data; - D3D12_RANGE readRange = {0, bufferSize}; - - SLANG_RETURN_ON_FAIL(dxResource->Map(0, &readRange, reinterpret_cast<void**>(&data))); - - RefPtr<Slang::ListBlob> resultBlob = new Slang::ListBlob(); - resultBlob->m_data.setCount(bufferSize); - memcpy(resultBlob->m_data.getBuffer(), data, bufferSize); - dxResource->Unmap(0, nullptr); - returnComPtr(outBlob, resultBlob); - return SLANG_OK; - } -} - -Result DeviceImpl::getNativeDeviceHandles(InteropHandles* outHandles) -{ - outHandles->handles[0].handleValue = (uint64_t)m_device; - outHandles->handles[0].api = InteropHandleAPI::D3D12; - return SLANG_OK; -} - -Result DeviceImpl::_createDevice( - DeviceCheckFlags deviceCheckFlags, - const UnownedStringSlice& nameMatch, - D3D_FEATURE_LEVEL featureLevel, - D3D12DeviceInfo& outDeviceInfo) -{ - if (m_dxDebug && (deviceCheckFlags & DeviceCheckFlag::UseDebug)) - { - m_dxDebug->EnableDebugLayer(); - } - - outDeviceInfo.clear(); - - ComPtr<IDXGIFactory> dxgiFactory; - SLANG_RETURN_ON_FAIL(D3DUtil::createFactory(deviceCheckFlags, dxgiFactory)); - - List<ComPtr<IDXGIAdapter>> dxgiAdapters; - SLANG_RETURN_ON_FAIL( - D3DUtil::findAdapters(deviceCheckFlags, nameMatch, dxgiFactory, dxgiAdapters)); - - ComPtr<ID3D12Device> device; - ComPtr<IDXGIAdapter> adapter; - - for (Index i = 0; i < dxgiAdapters.getCount(); ++i) - { - IDXGIAdapter* dxgiAdapter = dxgiAdapters[i]; - if (SLANG_SUCCEEDED( - m_D3D12CreateDevice(dxgiAdapter, featureLevel, IID_PPV_ARGS(device.writeRef())))) - { - adapter = dxgiAdapter; - break; - } - } - - if (!device) - { - return SLANG_FAIL; - } - - if (m_dxDebug && (deviceCheckFlags & DeviceCheckFlag::UseDebug)) - { - ComPtr<ID3D12InfoQueue> infoQueue; - if (SLANG_SUCCEEDED(device->QueryInterface(infoQueue.writeRef()))) - { - // Make break - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - if (m_extendedDesc.debugBreakOnD3D12Error) - { - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); - } - D3D12_MESSAGE_ID hideMessages[] = { - D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, - D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE, - }; - D3D12_INFO_QUEUE_FILTER f = {}; - f.DenyList.NumIDs = (UINT)SLANG_COUNT_OF(hideMessages); - f.DenyList.pIDList = hideMessages; - infoQueue->AddStorageFilterEntries(&f); - - // Apparently there is a problem with sm 6.3 with spurious errors, with debug layer - // enabled - D3D12_FEATURE_DATA_SHADER_MODEL featureShaderModel; - featureShaderModel.HighestShaderModel = D3D_SHADER_MODEL(0x63); - SLANG_SUCCEEDED(device->CheckFeatureSupport( - D3D12_FEATURE_SHADER_MODEL, &featureShaderModel, sizeof(featureShaderModel))); - - if (featureShaderModel.HighestShaderModel >= D3D_SHADER_MODEL(0x63)) - { - // Filter out any messages that cause issues - // TODO: Remove this when the debug layers work properly - D3D12_MESSAGE_ID messageIds[] = { - // When the debug layer is enabled this error is triggered sometimes after a - // CopyDescriptorsSimple call The failed check validates that the source and - // destination ranges of the copy do not overlap. The check assumes descriptor - // handles are pointers to memory, but this is not always the case and the check - // fails (even though everything is okay). - D3D12_MESSAGE_ID_COPY_DESCRIPTORS_INVALID_RANGES, - }; - - // We filter INFO messages because they are way too many - D3D12_MESSAGE_SEVERITY severities[] = {D3D12_MESSAGE_SEVERITY_INFO}; - - D3D12_INFO_QUEUE_FILTER infoQueueFilter = {}; - infoQueueFilter.DenyList.NumSeverities = SLANG_COUNT_OF(severities); - infoQueueFilter.DenyList.pSeverityList = severities; - infoQueueFilter.DenyList.NumIDs = SLANG_COUNT_OF(messageIds); - infoQueueFilter.DenyList.pIDList = messageIds; - - infoQueue->PushStorageFilter(&infoQueueFilter); - } - } - } - - // Get the descs - { - adapter->GetDesc(&outDeviceInfo.m_desc); - - // Look up GetDesc1 info - ComPtr<IDXGIAdapter1> adapter1; - if (SLANG_SUCCEEDED(adapter->QueryInterface(adapter1.writeRef()))) - { - adapter1->GetDesc1(&outDeviceInfo.m_desc1); - } - } - - // Save other info - outDeviceInfo.m_device = device; - outDeviceInfo.m_dxgiFactory = dxgiFactory; - outDeviceInfo.m_adapter = adapter; - outDeviceInfo.m_isWarp = D3DUtil::isWarp(dxgiFactory, adapter); - const UINT kMicrosoftVendorId = 5140; - outDeviceInfo.m_isSoftware = - outDeviceInfo.m_isWarp || - ((outDeviceInfo.m_desc1.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0) || - outDeviceInfo.m_desc.VendorId == kMicrosoftVendorId; - - return SLANG_OK; -} - -Result DeviceImpl::initialize(const Desc& desc) -{ - SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc)); - - // Find extended desc. - for (GfxIndex i = 0; i < desc.extendedDescCount; i++) - { - StructType stype; - memcpy(&stype, desc.extendedDescs[i], sizeof(stype)); - if (stype == StructType::D3D12ExtendedDesc) - { - memcpy(&m_extendedDesc, desc.extendedDescs[i], sizeof(m_extendedDesc)); - } - } - - // Initialize queue index allocator. - // Support max 32 queues. - m_queueIndexAllocator.initPool(32); - - // Initialize DeviceInfo - { - m_info.deviceType = DeviceType::DirectX12; - m_info.bindingStyle = BindingStyle::DirectX; - m_info.projectionStyle = ProjectionStyle::DirectX; - m_info.apiName = "Direct3D 12"; - static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; - ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity)); - } - - // Rather than statically link against D3D, we load it dynamically. - - HMODULE d3dModule = LoadLibraryA("d3d12.dll"); - if (!d3dModule) - { - fprintf(stderr, "error: failed load 'd3d12.dll'\n"); - return SLANG_FAIL; - } - - // Get all the dll entry points - m_D3D12SerializeRootSignature = - (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)loadProc(d3dModule, "D3D12SerializeRootSignature"); - if (!m_D3D12SerializeRootSignature) - { - return SLANG_FAIL; - } - - HMODULE pixModule = LoadLibraryW(L"WinPixEventRuntime.dll"); - if (pixModule) - { - m_BeginEventOnCommandList = - (PFN_BeginEventOnCommandList)GetProcAddress(pixModule, "PIXBeginEventOnCommandList"); - m_EndEventOnCommandList = - (PFN_EndEventOnCommandList)GetProcAddress(pixModule, "PIXEndEventOnCommandList"); - } - -#if ENABLE_DEBUG_LAYER - m_D3D12GetDebugInterface = - (PFN_D3D12_GET_DEBUG_INTERFACE)loadProc(d3dModule, "D3D12GetDebugInterface"); - if (m_D3D12GetDebugInterface) - { - if (SLANG_SUCCEEDED(m_D3D12GetDebugInterface(IID_PPV_ARGS(m_dxDebug.writeRef())))) - { -# if 0 - // Can enable for extra validation. NOTE! That d3d12 warns if you do.... - // D3D12 MESSAGE : Device Debug Layer Startup Options : GPU - Based Validation is enabled(disabled by default). - // This results in new validation not possible during API calls on the CPU, by creating patched shaders that have validation - // added directly to the shader. However, it can slow things down a lot, especially for applications with numerous - // PSOs.Time to see the first render frame may take several minutes. - // [INITIALIZATION MESSAGE #1016: CREATEDEVICE_DEBUG_LAYER_STARTUP_OPTIONS] - - ComPtr<ID3D12Debug1> debug1; - if (SLANG_SUCCEEDED(m_dxDebug->QueryInterface(debug1.writeRef()))) - { - debug1->SetEnableGPUBasedValidation(true); - } -# endif - } - } -#endif - - m_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)loadProc(d3dModule, "D3D12CreateDevice"); - if (!m_D3D12CreateDevice) - { - return SLANG_FAIL; - } - - if (desc.existingDeviceHandles.handles[0].handleValue == 0) - { - FlagCombiner combiner; - // TODO: we should probably provide a command-line option - // to override UseDebug of default rather than leave it - // up to each back-end to specify. -#if ENABLE_DEBUG_LAYER - combiner.add( - DeviceCheckFlag::UseDebug, ChangeType::OnOff); ///< First try debug then non debug -#else - combiner.add(DeviceCheckFlag::UseDebug, ChangeType::Off); ///< Don't bother with debug -#endif - combiner.add( - DeviceCheckFlag::UseHardwareDevice, - ChangeType::OnOff); ///< First try hardware, then reference - - const D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; - - const int numCombinations = combiner.getNumCombinations(); - for (int i = 0; i < numCombinations; ++i) - { - if (SLANG_SUCCEEDED(_createDevice( - combiner.getCombination(i), - UnownedStringSlice(desc.adapter), - featureLevel, - m_deviceInfo))) - { - break; - } - } - - if (!m_deviceInfo.m_adapter) - { - // Couldn't find an adapter - return SLANG_FAIL; - } - } - else - { - // Store the existing device handle in desc in m_deviceInfo - m_deviceInfo.m_device = (ID3D12Device*)desc.existingDeviceHandles.handles[0].handleValue; - } - - // Set the device - m_device = m_deviceInfo.m_device; - - if (m_deviceInfo.m_isSoftware) - { - m_features.add("software-device"); - } - else - { - m_features.add("hardware-device"); - } - - // NVAPI - if (desc.nvapiExtnSlot >= 0) - { - if (SLANG_FAILED(NVAPIUtil::initialize())) - { - return SLANG_E_NOT_AVAILABLE; - } - -#ifdef GFX_NVAPI - // From DOCS: Applications are expected to bind null UAV to this slot. - // NOTE! We don't currently do this, but doesn't seem to be a problem. - - const NvAPI_Status status = - NvAPI_D3D12_SetNvShaderExtnSlotSpace(m_device, NvU32(desc.nvapiExtnSlot), NvU32(0)); - - if (status != NVAPI_OK) - { - return SLANG_E_NOT_AVAILABLE; - } - - if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_UINT64_ATOMIC)) - { - m_features.add("atomic-int64"); - } - if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_FP32_ATOMIC)) - { - m_features.add("atomic-float"); - } - - m_nvapi = true; -#endif - } - - D3D12_FEATURE_DATA_SHADER_MODEL shaderModelData = {}; - shaderModelData.HighestShaderModel = D3D_SHADER_MODEL_6_6; - - // Find what features are supported - { - // Check this is how this is laid out... - SLANG_COMPILE_TIME_ASSERT(D3D_SHADER_MODEL_6_0 == 0x60); - - { - // TODO: Currently warp causes a crash when using half, so disable for now - if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport( - D3D12_FEATURE_SHADER_MODEL, &shaderModelData, sizeof(shaderModelData))) && - m_deviceInfo.m_isWarp == false && shaderModelData.HighestShaderModel >= 0x62) - { - // With sm_6_2 we have half - m_features.add("half"); - } - } - { - D3D12_FEATURE_DATA_D3D12_OPTIONS options; - if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport( - D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) - { - // Check double precision support - if (options.DoublePrecisionFloatShaderOps) - m_features.add("double"); - - // Check conservative-rasterization support - auto conservativeRasterTier = options.ConservativeRasterizationTier; - if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_3) - { - m_features.add("conservative-rasterization-3"); - m_features.add("conservative-rasterization-2"); - m_features.add("conservative-rasterization-1"); - } - else if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_2) - { - m_features.add("conservative-rasterization-2"); - m_features.add("conservative-rasterization-1"); - } - else if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_1) - { - m_features.add("conservative-rasterization-1"); - } - - // Check rasterizer ordered views support - if (options.ROVsSupported) - { - m_features.add("rasterizer-ordered-views"); - } - } - } - { - D3D12_FEATURE_DATA_D3D12_OPTIONS2 options; - if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport( - D3D12_FEATURE_D3D12_OPTIONS2, &options, sizeof(options)))) - { - // Check programmable sample positions support - switch (options.ProgrammableSamplePositionsTier) - { - case D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_2: - m_features.add("programmable-sample-positions-2"); - m_features.add("programmable-sample-positions-1"); - break; - case D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1: - m_features.add("programmable-sample-positions-1"); - break; - default: - break; - } - } - } - { - D3D12_FEATURE_DATA_D3D12_OPTIONS3 options; - if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport( - D3D12_FEATURE_D3D12_OPTIONS3, &options, sizeof(options)))) - { - // Check barycentrics support - if (options.BarycentricsSupported) - { - m_features.add("barycentrics"); - } - } - } - // Check ray tracing support - { - D3D12_FEATURE_DATA_D3D12_OPTIONS5 options; - if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport( - D3D12_FEATURE_D3D12_OPTIONS5, &options, sizeof(options)))) - { - if (options.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) - { - m_features.add("ray-tracing"); - } - if (options.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1) - { - m_features.add("ray-query"); - } - } - } - } - - m_desc = desc; - - // Create a command queue for internal resource transfer operations. - SLANG_RETURN_ON_FAIL(createCommandQueueImpl(m_resourceCommandQueue.writeRef())); - // `CommandQueueImpl` holds a back reference to `D3D12Device`, make it a weak reference here - // since this object is already owned by `D3D12Device`. - m_resourceCommandQueue->breakStrongReferenceToDevice(); - // Retrieve timestamp frequency. - m_resourceCommandQueue->m_d3dQueue->GetTimestampFrequency(&m_info.timestampFrequency); - - SLANG_RETURN_ON_FAIL(createTransientResourceHeapImpl( - ITransientResourceHeap::Flags::AllowResizing, - 0, - 8, - 4, - m_resourceCommandTransientHeap.writeRef())); - // `TransientResourceHeap` holds a back reference to `D3D12Device`, make it a weak reference - // here since this object is already owned by `D3D12Device`. - m_resourceCommandTransientHeap->breakStrongReferenceToDevice(); - - m_cpuViewHeap = new D3D12GeneralExpandingDescriptorHeap(); - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->init( - m_device, - 1024 * 1024, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - m_cpuSamplerHeap = new D3D12GeneralExpandingDescriptorHeap(); - SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap->init( - m_device, 2048, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - - m_rtvAllocator = new D3D12GeneralExpandingDescriptorHeap(); - SLANG_RETURN_ON_FAIL(m_rtvAllocator->init( - m_device, 16 * 1024, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - m_dsvAllocator = new D3D12GeneralExpandingDescriptorHeap(); - SLANG_RETURN_ON_FAIL(m_dsvAllocator->init( - m_device, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - - ComPtr<IDXGIDevice> dxgiDevice; - if (m_deviceInfo.m_adapter) - { - DXGI_ADAPTER_DESC adapterDesc; - m_deviceInfo.m_adapter->GetDesc(&adapterDesc); - m_adapterName = String::fromWString(adapterDesc.Description); - m_info.adapterName = m_adapterName.begin(); - } - - // Initialize DXR interface. -#if SLANG_GFX_HAS_DXR_SUPPORT - m_device->QueryInterface<ID3D12Device5>(m_deviceInfo.m_device5.writeRef()); - m_device5 = m_deviceInfo.m_device5.get(); -#endif - // Check shader model version. - SlangCompileTarget compileTarget = SLANG_DXBC; - const char* profileName = "sm_5_1"; - switch (shaderModelData.HighestShaderModel) - { - case D3D_SHADER_MODEL_5_1: - compileTarget = SLANG_DXBC; - profileName = "sm_5_1"; - break; - case D3D_SHADER_MODEL_6_0: - compileTarget = SLANG_DXIL; - profileName = "sm_6_0"; - break; - case D3D_SHADER_MODEL_6_1: - compileTarget = SLANG_DXIL; - profileName = "sm_6_1"; - break; - case D3D_SHADER_MODEL_6_2: - compileTarget = SLANG_DXIL; - profileName = "sm_6_2"; - break; - case D3D_SHADER_MODEL_6_3: - compileTarget = SLANG_DXIL; - profileName = "sm_6_3"; - break; - case D3D_SHADER_MODEL_6_4: - compileTarget = SLANG_DXIL; - profileName = "sm_6_4"; - break; - case D3D_SHADER_MODEL_6_5: - compileTarget = SLANG_DXIL; - profileName = "sm_6_5"; - break; - default: - compileTarget = SLANG_DXIL; - profileName = "sm_6_6"; - break; - } - m_features.add(profileName); - // If user specified a higher shader model than what the system supports, return failure. - int userSpecifiedShaderModel = D3DUtil::getShaderModelFromProfileName(desc.slang.targetProfile); - if (userSpecifiedShaderModel > shaderModelData.HighestShaderModel) - { - getDebugCallback()->handleMessage( - gfx::DebugMessageType::Error, - gfx::DebugMessageSource::Layer, - "The requested shader model is not supported by the system."); - return SLANG_E_NOT_AVAILABLE; - } - SLANG_RETURN_ON_FAIL(slangContext.initialize( - desc.slang, - compileTarget, - profileName, - makeArray(slang::PreprocessorMacroDesc{"__D3D12__", "1"}).getView())); - - // Allocate a D3D12 "command signature" object that matches the behavior - // of a D3D11-style `DrawInstancedIndirect` operation. - { - D3D12_INDIRECT_ARGUMENT_DESC args; - args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; - - D3D12_COMMAND_SIGNATURE_DESC desc; - desc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); - desc.NumArgumentDescs = 1; - desc.pArgumentDescs = &args; - desc.NodeMask = 0; - - SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature( - &desc, nullptr, IID_PPV_ARGS(drawIndirectCmdSignature.writeRef()))); - } - - // Allocate a D3D12 "command signature" object that matches the behavior - // of a D3D11-style `DrawIndexedInstancedIndirect` operation. - { - D3D12_INDIRECT_ARGUMENT_DESC args; - args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; - - D3D12_COMMAND_SIGNATURE_DESC desc; - desc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); - desc.NumArgumentDescs = 1; - desc.pArgumentDescs = &args; - desc.NodeMask = 0; - - SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature( - &desc, nullptr, IID_PPV_ARGS(drawIndexedIndirectCmdSignature.writeRef()))); - } - - // Allocate a D3D12 "command signature" object that matches the behavior - // of a D3D11-style `Dispatch` operation. - { - D3D12_INDIRECT_ARGUMENT_DESC args; - args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; - - D3D12_COMMAND_SIGNATURE_DESC desc; - desc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); - desc.NumArgumentDescs = 1; - desc.pArgumentDescs = &args; - desc.NodeMask = 0; - - SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature( - &desc, nullptr, IID_PPV_ARGS(dispatchIndirectCmdSignature.writeRef()))); - } - m_isInitialized = true; - return SLANG_OK; -} - -Result DeviceImpl::createTransientResourceHeap( - const ITransientResourceHeap::Desc& desc, ITransientResourceHeap** outHeap) -{ - RefPtr<TransientResourceHeapImpl> heap; - SLANG_RETURN_ON_FAIL(createTransientResourceHeapImpl( - desc.flags, - desc.constantBufferSize, - getViewDescriptorCount(desc), - Math::Max(1024, desc.samplerDescriptorCount), - heap.writeRef())); - returnComPtr(outHeap, heap); - return SLANG_OK; -} - -Result DeviceImpl::createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue) -{ - RefPtr<CommandQueueImpl> queue; - SLANG_RETURN_ON_FAIL(createCommandQueueImpl(queue.writeRef())); - returnComPtr(outQueue, queue); - return SLANG_OK; -} - -Result DeviceImpl::createSwapchain( - const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) -{ - RefPtr<SwapchainImpl> swapchain = new SwapchainImpl(); - SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window)); - returnComPtr(outSwapchain, swapchain); - return SLANG_OK; -} - -SlangResult DeviceImpl::readTextureResource( - ITextureResource* resource, - ResourceState state, - ISlangBlob** outBlob, - Size* outRowPitch, - Size* outPixelSize) -{ - return captureTextureToSurface( - static_cast<TextureResourceImpl*>(resource), state, outBlob, outRowPitch, outPixelSize); -} - -Result DeviceImpl::getTextureAllocationInfo( - const ITextureResource::Desc& desc, Size* outSize, Size* outAlignment) -{ - TextureResource::Desc srcDesc = fixupTextureDesc(desc); - D3D12_RESOURCE_DESC resourceDesc = {}; - initTextureResourceDesc(resourceDesc, srcDesc); - auto allocInfo = m_device->GetResourceAllocationInfo(0, 1, &resourceDesc); - *outSize = (Size)allocInfo.SizeInBytes; - *outAlignment = (Size)allocInfo.Alignment; - return SLANG_OK; -} - -Result DeviceImpl::getTextureRowAlignment(Size* outAlignment) -{ - *outAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; - return SLANG_OK; -} - -Result DeviceImpl::createTextureResource( - const ITextureResource::Desc& descIn, - const ITextureResource::SubresourceData* initData, - ITextureResource** outResource) -{ - // Description of uploading on Dx12 - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx - - TextureResource::Desc srcDesc = fixupTextureDesc(descIn); - - D3D12_RESOURCE_DESC resourceDesc = {}; - initTextureResourceDesc(resourceDesc, srcDesc); - const int arraySize = calcEffectiveArraySize(srcDesc); - const int numMipMaps = srcDesc.numMipLevels; - - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc)); - - // Create the target resource - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE; - if (descIn.isShared) - flags |= D3D12_HEAP_FLAG_SHARED; - - D3D12_CLEAR_VALUE clearValue; - D3D12_CLEAR_VALUE* clearValuePtr = &clearValue; - if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | - D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0) - { - clearValuePtr = nullptr; - } - if (isTypelessDepthFormat(resourceDesc.Format)) - { - clearValuePtr = nullptr; - } - clearValue.Format = resourceDesc.Format; - memcpy(clearValue.Color, &descIn.optimalClearValue.color, sizeof(clearValue.Color)); - clearValue.DepthStencil.Depth = descIn.optimalClearValue.depthStencil.depth; - clearValue.DepthStencil.Stencil = descIn.optimalClearValue.depthStencil.stencil; - SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted( - m_device, - heapProps, - flags, - resourceDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - clearValuePtr)); - - texture->m_resource.setDebugName(L"Texture"); - } - - // Calculate the layout - List<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> layouts; - layouts.setCount(numMipMaps); - List<UInt64> mipRowSizeInBytes; - mipRowSizeInBytes.setCount(srcDesc.numMipLevels); - List<UInt32> mipNumRows; - mipNumRows.setCount(numMipMaps); - - // NOTE! This is just the size for one array upload -> not for the whole texture - UInt64 requiredSize = 0; - m_device->GetCopyableFootprints( - &resourceDesc, - 0, - srcDesc.numMipLevels, - 0, - layouts.begin(), - mipNumRows.begin(), - mipRowSizeInBytes.begin(), - &requiredSize); - - // Sub resource indexing - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing - if (initData) - { - // Create the upload texture - D3D12Resource uploadTexture; - - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC uploadResourceDesc; - - uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - uploadResourceDesc.Width = requiredSize; - uploadResourceDesc.Height = 1; - uploadResourceDesc.DepthOrArraySize = 1; - uploadResourceDesc.MipLevels = 1; - uploadResourceDesc.SampleDesc.Count = 1; - uploadResourceDesc.SampleDesc.Quality = 0; - uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - uploadResourceDesc.Alignment = 0; - - SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted( - m_device, - heapProps, - D3D12_HEAP_FLAG_NONE, - uploadResourceDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr)); - - uploadTexture.setDebugName(L"TextureUpload"); - } - // Get the pointer to the upload resource - ID3D12Resource* uploadResource = uploadTexture; - - int subResourceIndex = 0; - for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) - { - uint8_t* p; - uploadResource->Map(0, nullptr, reinterpret_cast<void**>(&p)); - - for (int j = 0; j < numMipMaps; ++j) - { - auto srcSubresource = initData[subResourceIndex + j]; - - const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; - const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; - - TextureResource::Extents mipSize = calcMipSize(srcDesc.size, j); - if (gfxIsCompressedFormat(descIn.format)) - { - mipSize.width = int(D3DUtil::calcAligned(mipSize.width, 4)); - mipSize.height = int(D3DUtil::calcAligned(mipSize.height, 4)); - } - - assert( - footprint.Width == mipSize.width && footprint.Height == mipSize.height && - footprint.Depth == mipSize.depth); - - auto mipRowSize = mipRowSizeInBytes[j]; - - const ptrdiff_t dstMipRowPitch = ptrdiff_t(footprint.RowPitch); - const ptrdiff_t srcMipRowPitch = ptrdiff_t(srcSubresource.strideY); - - const ptrdiff_t dstMipLayerPitch = ptrdiff_t(footprint.RowPitch * footprint.Height); - const ptrdiff_t srcMipLayerPitch = ptrdiff_t(srcSubresource.strideZ); - - // Our outer loop will copy the depth layers one at a time. - // - const uint8_t* srcLayer = (const uint8_t*)srcSubresource.data; - uint8_t* dstLayer = p + layouts[j].Offset; - for (int l = 0; l < mipSize.depth; l++) - { - // Our inner loop will copy the rows one at a time. - // - const uint8_t* srcRow = srcLayer; - uint8_t* dstRow = dstLayer; - int j = gfxIsCompressedFormat(descIn.format) - ? 4 - : 1; // BC compressed formats are organized into 4x4 blocks - for (int k = 0; k < mipSize.height; k += j) - { - ::memcpy(dstRow, srcRow, (Size)mipRowSize); - - srcRow += srcMipRowPitch; - dstRow += dstMipRowPitch; - } - - srcLayer += srcMipLayerPitch; - dstLayer += dstMipLayerPitch; - } - - // assert(srcRow == (const uint8_t*)(srcMip.getBuffer() + srcMip.getCount())); - } - uploadResource->Unmap(0, nullptr); - - auto encodeInfo = encodeResourceCommands(); - for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex) - { - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx - - D3D12_TEXTURE_COPY_LOCATION src; - src.pResource = uploadTexture; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint = layouts[mipIndex]; - - D3D12_TEXTURE_COPY_LOCATION dst; - dst.pResource = texture->m_resource; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst.SubresourceIndex = subResourceIndex; - encodeInfo.d3dCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); - - subResourceIndex++; - } - - // Block - waiting for copy to complete (so can drop upload texture) - submitResourceCommandsAndWait(encodeInfo); - } - } - { - auto encodeInfo = encodeResourceCommands(); - { - D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList); - texture->m_resource.transition( - D3D12_RESOURCE_STATE_COPY_DEST, texture->m_defaultState, submitter); - } - submitResourceCommandsAndWait(encodeInfo); - } - - returnComPtr(outResource, texture); - return SLANG_OK; -} - -Result DeviceImpl::createTextureFromNativeHandle( - InteropHandle handle, const ITextureResource::Desc& srcDesc, ITextureResource** outResource) -{ - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc)); - - if (handle.api == InteropHandleAPI::D3D12) - { - texture->m_resource.setResource((ID3D12Resource*)handle.handleValue); - } - else - { - return SLANG_FAIL; - } - - returnComPtr(outResource, texture); - return SLANG_OK; -} - -Result DeviceImpl::createBufferResource( - const IBufferResource::Desc& descIn, const void* initData, IBufferResource** outResource) -{ - BufferResource::Desc srcDesc = fixupBufferDesc(descIn); - - RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc)); - - D3D12_RESOURCE_DESC bufferDesc; - initBufferResourceDesc(descIn.sizeInBytes, bufferDesc); - - bufferDesc.Flags |= calcResourceFlags(srcDesc.allowedStates); - - const D3D12_RESOURCE_STATES initialState = buffer->m_defaultState; - SLANG_RETURN_ON_FAIL(createBuffer( - bufferDesc, - initData, - srcDesc.sizeInBytes, - initialState, - buffer->m_resource, - descIn.isShared, - descIn.memoryType)); - - returnComPtr(outResource, buffer); - return SLANG_OK; -} - -Result DeviceImpl::createBufferFromNativeHandle( - InteropHandle handle, const IBufferResource::Desc& srcDesc, IBufferResource** outResource) -{ - RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc)); - - if (handle.api == InteropHandleAPI::D3D12) - { - buffer->m_resource.setResource((ID3D12Resource*)handle.handleValue); - } - else - { - return SLANG_FAIL; - } - - returnComPtr(outResource, buffer); - return SLANG_OK; -} - -Result DeviceImpl::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) -{ - D3D12_FILTER_REDUCTION_TYPE dxReduction = translateFilterReduction(desc.reductionOp); - D3D12_FILTER dxFilter; - if (desc.maxAnisotropy > 1) - { - dxFilter = D3D12_ENCODE_ANISOTROPIC_FILTER(dxReduction); - } - else - { - D3D12_FILTER_TYPE dxMin = translateFilterMode(desc.minFilter); - D3D12_FILTER_TYPE dxMag = translateFilterMode(desc.magFilter); - D3D12_FILTER_TYPE dxMip = translateFilterMode(desc.mipFilter); - - dxFilter = D3D12_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, dxReduction); - } - - D3D12_SAMPLER_DESC dxDesc = {}; - dxDesc.Filter = dxFilter; - dxDesc.AddressU = translateAddressingMode(desc.addressU); - dxDesc.AddressV = translateAddressingMode(desc.addressV); - dxDesc.AddressW = translateAddressingMode(desc.addressW); - dxDesc.MipLODBias = desc.mipLODBias; - dxDesc.MaxAnisotropy = desc.maxAnisotropy; - dxDesc.ComparisonFunc = translateComparisonFunc(desc.comparisonFunc); - for (int ii = 0; ii < 4; ++ii) - dxDesc.BorderColor[ii] = desc.borderColor[ii]; - dxDesc.MinLOD = desc.minLOD; - dxDesc.MaxLOD = desc.maxLOD; - - auto& samplerHeap = m_cpuSamplerHeap; - - D3D12Descriptor cpuDescriptor; - samplerHeap->allocate(&cpuDescriptor); - m_device->CreateSampler(&dxDesc, cpuDescriptor.cpuHandle); - - // TODO: We really ought to have a free-list of sampler-heap - // entries that we check before we go to the heap, and then - // when we are done with a sampler we simply add it to the free list. - // - RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl(); - samplerImpl->m_allocator = samplerHeap; - samplerImpl->m_descriptor = cpuDescriptor; - returnComPtr(outSampler, samplerImpl); - return SLANG_OK; -} - -Result DeviceImpl::createTextureView( - ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) -{ - auto resourceImpl = (TextureResourceImpl*)texture; - - RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl(); - viewImpl->m_resource = resourceImpl; - viewImpl->m_desc = desc; - bool isArray = resourceImpl ? resourceImpl->getDesc()->arraySize != 0 : false; - bool isMultiSample = resourceImpl ? resourceImpl->getDesc()->sampleDesc.numSamples > 1 : false; - switch (desc.type) - { - default: - return SLANG_FAIL; - - case IResourceView::Type::RenderTarget: - { - SLANG_RETURN_ON_FAIL(m_rtvAllocator->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_rtvAllocator; - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = D3DUtil::getMapFormat(desc.format); - isArray = desc.subresourceRange.layerCount > 1; - switch (desc.renderTarget.shape) - { - case IResource::Type::Texture1D: - rtvDesc.ViewDimension = - isArray ? D3D12_RTV_DIMENSION_TEXTURE1DARRAY : D3D12_RTV_DIMENSION_TEXTURE1D; - rtvDesc.Texture1D.MipSlice = desc.subresourceRange.mipLevel; - break; - case IResource::Type::Texture2D: - if (isMultiSample) - { - rtvDesc.ViewDimension = isArray ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY - : D3D12_RTV_DIMENSION_TEXTURE2DMS; - rtvDesc.Texture2DMSArray.ArraySize = desc.subresourceRange.layerCount; - rtvDesc.Texture2DMSArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - } - else - { - rtvDesc.ViewDimension = isArray ? D3D12_RTV_DIMENSION_TEXTURE2DARRAY - : D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel; - rtvDesc.Texture2DArray.PlaneSlice = - resourceImpl ? D3DUtil::getPlaneSlice( - D3DUtil::getMapFormat(resourceImpl->getDesc()->format), - desc.subresourceRange.aspectMask) - : 0; - rtvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount; - rtvDesc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - } - break; - case IResource::Type::Texture3D: - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = desc.subresourceRange.mipLevel; - rtvDesc.Texture3D.FirstWSlice = desc.subresourceRange.baseArrayLayer; - rtvDesc.Texture3D.WSize = (desc.subresourceRange.layerCount == 0) ? -1 : desc.subresourceRange.layerCount; - break; - case IResource::Type::Buffer: - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_BUFFER; - break; - default: - return SLANG_FAIL; - } - m_device->CreateRenderTargetView( - resourceImpl ? resourceImpl->m_resource.getResource() : nullptr, - &rtvDesc, - viewImpl->m_descriptor.cpuHandle); - } - break; - - case IResourceView::Type::DepthStencil: - { - SLANG_RETURN_ON_FAIL(m_dsvAllocator->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_dsvAllocator; - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = D3DUtil::getMapFormat(desc.format); - isArray = desc.subresourceRange.layerCount > 1; - switch (desc.renderTarget.shape) - { - case IResource::Type::Texture1D: - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D; - dsvDesc.Texture1D.MipSlice = desc.subresourceRange.mipLevel; - break; - case IResource::Type::Texture2D: - if (isMultiSample) - { - dsvDesc.ViewDimension = isArray ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY - : D3D12_DSV_DIMENSION_TEXTURE2DMS; - dsvDesc.Texture2DMSArray.ArraySize = desc.subresourceRange.layerCount; - dsvDesc.Texture2DMSArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - } - else - { - dsvDesc.ViewDimension = isArray ? D3D12_DSV_DIMENSION_TEXTURE2DARRAY - : D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel; - dsvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount; - dsvDesc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - } - break; - default: - return SLANG_FAIL; - } - m_device->CreateDepthStencilView( - resourceImpl ? resourceImpl->m_resource.getResource() : nullptr, - &dsvDesc, - viewImpl->m_descriptor.cpuHandle); - } - break; - - case IResourceView::Type::UnorderedAccess: - { - // TODO: need to support the separate "counter resource" for the case - // of append/consume buffers with attached counters. - - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - D3D12_UNORDERED_ACCESS_VIEW_DESC d3d12desc = {}; - auto& resourceDesc = *resourceImpl->getDesc(); - d3d12desc.Format = gfxIsTypelessFormat(texture->getDesc()->format) - ? D3DUtil::getMapFormat(desc.format) - : D3DUtil::getMapFormat(texture->getDesc()->format); - switch (resourceImpl->getDesc()->type) - { - case IResource::Type::Texture1D: - d3d12desc.ViewDimension = resourceDesc.arraySize == 0 - ? D3D12_UAV_DIMENSION_TEXTURE1D - : D3D12_UAV_DIMENSION_TEXTURE1DARRAY; - d3d12desc.Texture1D.MipSlice = desc.subresourceRange.mipLevel; - d3d12desc.Texture1DArray.ArraySize = desc.subresourceRange.layerCount == 0 - ? resourceDesc.arraySize - : desc.subresourceRange.layerCount; - d3d12desc.Texture1DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - - break; - case IResource::Type::Texture2D: - d3d12desc.ViewDimension = resourceDesc.arraySize == 0 - ? D3D12_UAV_DIMENSION_TEXTURE2D - : D3D12_UAV_DIMENSION_TEXTURE2DARRAY; - d3d12desc.Texture2D.MipSlice = desc.subresourceRange.mipLevel; - d3d12desc.Texture2D.PlaneSlice = - D3DUtil::getPlaneSlice(d3d12desc.Format, desc.subresourceRange.aspectMask); - d3d12desc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount == 0 - ? resourceDesc.arraySize - : desc.subresourceRange.layerCount; - d3d12desc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer; - break; - case IResource::Type::Texture3D: - d3d12desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; - d3d12desc.Texture3D.MipSlice = desc.subresourceRange.mipLevel; - d3d12desc.Texture3D.FirstWSlice = desc.subresourceRange.baseArrayLayer; - d3d12desc.Texture3D.WSize = resourceDesc.size.depth; - break; - default: - return SLANG_FAIL; - } - m_device->CreateUnorderedAccessView( - resourceImpl->m_resource, nullptr, &d3d12desc, viewImpl->m_descriptor.cpuHandle); - } - break; - - case IResourceView::Type::ShaderResource: - { - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - - // Need to construct the D3D12_SHADER_RESOURCE_VIEW_DESC because otherwise TextureCube - // is not accessed appropriately (rather than just passing nullptr to - // CreateShaderResourceView) - const D3D12_RESOURCE_DESC resourceDesc = - resourceImpl->m_resource.getResource()->GetDesc(); - const DXGI_FORMAT pixelFormat = desc.format == Format::Unknown - ? resourceDesc.Format - : D3DUtil::getMapFormat(desc.format); - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - initSrvDesc( - resourceImpl->getType(), - *resourceImpl->getDesc(), - resourceDesc, - pixelFormat, - desc.subresourceRange, - srvDesc); - - m_device->CreateShaderResourceView( - resourceImpl->m_resource, &srvDesc, viewImpl->m_descriptor.cpuHandle); - } - break; - } - - returnComPtr(outView, viewImpl); - return SLANG_OK; -} - -Result DeviceImpl::getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates) -{ - D3D12_FEATURE_DATA_FORMAT_SUPPORT support; - support.Format = D3DUtil::getMapFormat(format); - SLANG_RETURN_ON_FAIL( - m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))); - - ResourceStateSet allowedStates; - - auto dxgi1 = support.Support1; - if (dxgi1 & D3D12_FORMAT_SUPPORT1_BUFFER) - allowedStates.add(ResourceState::ConstantBuffer); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER) - allowedStates.add(ResourceState::VertexBuffer); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER) - allowedStates.add(ResourceState::IndexBuffer); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SO_BUFFER) - allowedStates.add(ResourceState::StreamOutput); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE1D) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_GATHER) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON) - allowedStates.add(ResourceState::ShaderResource); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) - allowedStates.add(ResourceState::RenderTarget); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) - allowedStates.add(ResourceState::DepthWrite); - if (dxgi1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) - allowedStates.add(ResourceState::UnorderedAccess); - - *outStates = allowedStates; - return SLANG_OK; -} - -Result DeviceImpl::createBufferView( - IBufferResource* buffer, - IBufferResource* counterBuffer, - IResourceView::Desc const& desc, - IResourceView** outView) -{ - auto resourceImpl = (BufferResourceImpl*)buffer; - auto resourceDesc = *resourceImpl->getDesc(); - - RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl(); - viewImpl->m_resource = resourceImpl; - viewImpl->m_desc = desc; - - switch (desc.type) - { - default: - return SLANG_FAIL; - - case IResourceView::Type::UnorderedAccess: - { - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Format = D3DUtil::getMapFormat(desc.format); - uavDesc.Buffer.FirstElement = desc.bufferRange.firstElement; - uint64_t viewSize = 0; - if (desc.bufferElementSize) - { - uavDesc.Buffer.StructureByteStride = (UINT)desc.bufferElementSize; - uavDesc.Buffer.NumElements = - desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize) - : (UINT)desc.bufferRange.elementCount; - viewSize = (uint64_t)desc.bufferElementSize * uavDesc.Buffer.NumElements; - } - else if (desc.format == Format::Unknown) - { - uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; - uavDesc.Buffer.NumElements = desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / 4) - : UINT(desc.bufferRange.elementCount / 4); - uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; - viewSize = 4ull * uavDesc.Buffer.NumElements; - } - else - { - FormatInfo sizeInfo; - gfxGetFormatInfo(desc.format, &sizeInfo); - assert(sizeInfo.pixelsPerBlock == 1); - uavDesc.Buffer.NumElements = - desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes) - : (UINT)desc.bufferRange.elementCount; - viewSize = (uint64_t)uavDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes; - } - - if (viewSize >= (1ull << 32) - 8) - { - // D3D12 does not support view descriptors that has size near 4GB. - // We will not create actual SRV/UAVs for such large buffers. - // However, a buffer this large can still be bound as root parameter. - // So instead of failing, we quietly ignore descriptor creation. - viewImpl->m_descriptor.cpuHandle.ptr = 0; - } - else - { - auto counterResourceImpl = static_cast<BufferResourceImpl*>(counterBuffer); - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - m_device->CreateUnorderedAccessView( - resourceImpl->m_resource, - counterResourceImpl ? counterResourceImpl->m_resource.getResource() : nullptr, - &uavDesc, - viewImpl->m_descriptor.cpuHandle); - } - } - break; - - case IResourceView::Type::ShaderResource: - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Format = D3DUtil::getMapFormat(desc.format); - srvDesc.Buffer.StructureByteStride = 0; - srvDesc.Buffer.FirstElement = desc.bufferRange.firstElement; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - uint64_t viewSize = 0; - if (desc.bufferElementSize) - { - srvDesc.Buffer.StructureByteStride = (UINT)desc.bufferElementSize; - srvDesc.Buffer.NumElements = - desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize) - : (UINT)desc.bufferRange.elementCount; - viewSize = (uint64_t)desc.bufferElementSize * srvDesc.Buffer.NumElements; - } - else if (desc.format == Format::Unknown) - { - srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; - srvDesc.Buffer.NumElements = desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / 4) - : UINT(desc.bufferRange.elementCount / 4); - srvDesc.Buffer.Flags |= D3D12_BUFFER_SRV_FLAG_RAW; - viewSize = 4ull * srvDesc.Buffer.NumElements; - } - else - { - FormatInfo sizeInfo; - gfxGetFormatInfo(desc.format, &sizeInfo); - assert(sizeInfo.pixelsPerBlock == 1); - srvDesc.Buffer.NumElements = - desc.bufferRange.elementCount == 0 - ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes) - : (UINT)desc.bufferRange.elementCount; - viewSize = (uint64_t)srvDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes; - } - if (viewSize >= (1ull << 32) - 8) - { - // D3D12 does not support view descriptors that has size near 4GB. - // We will not create actual SRV/UAVs for such large buffers. - // However, a buffer this large can still be bound as root parameter. - // So instead of failing, we quietly ignore descriptor creation. - viewImpl->m_descriptor.cpuHandle.ptr = 0; - } - else - { - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor)); - viewImpl->m_allocator = m_cpuViewHeap; - m_device->CreateShaderResourceView( - resourceImpl->m_resource, &srvDesc, viewImpl->m_descriptor.cpuHandle); - } - } - break; - } - - returnComPtr(outView, viewImpl); - return SLANG_OK; -} - -Result DeviceImpl::createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFb) -{ - RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl(); - framebuffer->renderTargetViews.setCount(desc.renderTargetCount); - framebuffer->renderTargetDescriptors.setCount(desc.renderTargetCount); - framebuffer->renderTargetClearValues.setCount(desc.renderTargetCount); - for (GfxIndex i = 0; i < desc.renderTargetCount; i++) - { - framebuffer->renderTargetViews[i] = - static_cast<ResourceViewImpl*>(desc.renderTargetViews[i]); - framebuffer->renderTargetDescriptors[i] = - framebuffer->renderTargetViews[i]->m_descriptor.cpuHandle; - if (static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_resource.Ptr()) - { - auto clearValue = - static_cast<TextureResourceImpl*>( - static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_resource.Ptr()) - ->getDesc() - ->optimalClearValue.color; - memcpy(&framebuffer->renderTargetClearValues[i], &clearValue, sizeof(ColorClearValue)); - } - else - { - memset(&framebuffer->renderTargetClearValues[i], 0, sizeof(ColorClearValue)); - } - } - framebuffer->depthStencilView = static_cast<ResourceViewImpl*>(desc.depthStencilView); - if (desc.depthStencilView) - { - framebuffer->depthStencilClearValue = - static_cast<TextureResourceImpl*>( - static_cast<ResourceViewImpl*>(desc.depthStencilView)->m_resource.Ptr()) - ->getDesc() - ->optimalClearValue.depthStencil; - framebuffer->depthStencilDescriptor = - static_cast<ResourceViewImpl*>(desc.depthStencilView)->m_descriptor.cpuHandle; - } - else - { - framebuffer->depthStencilDescriptor.ptr = 0; - } - returnComPtr(outFb, framebuffer); - return SLANG_OK; -} - -Result DeviceImpl::createFramebufferLayout( - IFramebufferLayout::Desc const& desc, IFramebufferLayout** outLayout) -{ - RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl(); - layout->m_renderTargets.setCount(desc.renderTargetCount); - for (GfxIndex i = 0; i < desc.renderTargetCount; i++) - { - layout->m_renderTargets[i] = desc.renderTargets[i]; - } - - if (desc.depthStencil) - { - layout->m_hasDepthStencil = true; - layout->m_depthStencil = *desc.depthStencil; - } - else - { - layout->m_hasDepthStencil = false; - } - returnComPtr(outLayout, layout); - return SLANG_OK; -} - -Result DeviceImpl::createRenderPassLayout( - const IRenderPassLayout::Desc& desc, IRenderPassLayout** outRenderPassLayout) -{ - RefPtr<RenderPassLayoutImpl> result = new RenderPassLayoutImpl(); - result->init(desc); - returnComPtr(outRenderPassLayout, result); - return SLANG_OK; -} - -Result DeviceImpl::createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout) -{ - RefPtr<InputLayoutImpl> layout(new InputLayoutImpl); - - // Work out a buffer size to hold all text - Size textSize = 0; - auto inputElementCount = desc.inputElementCount; - auto inputElements = desc.inputElements; - auto vertexStreamCount = desc.vertexStreamCount; - auto vertexStreams = desc.vertexStreams; - for (int i = 0; i < Int(inputElementCount); ++i) - { - const char* text = inputElements[i].semanticName; - textSize += text ? (::strlen(text) + 1) : 0; - } - layout->m_text.setCount(textSize); - char* textPos = layout->m_text.getBuffer(); - - List<D3D12_INPUT_ELEMENT_DESC>& elements = layout->m_elements; - elements.setCount(inputElementCount); - - for (Int i = 0; i < inputElementCount; ++i) - { - const InputElementDesc& srcEle = inputElements[i]; - const auto& srcStream = vertexStreams[srcEle.bufferSlotIndex]; - D3D12_INPUT_ELEMENT_DESC& dstEle = elements[i]; - - // Add text to the buffer - const char* semanticName = srcEle.semanticName; - if (semanticName) - { - const int len = int(::strlen(semanticName)); - ::memcpy(textPos, semanticName, len + 1); - semanticName = textPos; - textPos += len + 1; - } - - dstEle.SemanticName = semanticName; - dstEle.SemanticIndex = (UINT)srcEle.semanticIndex; - dstEle.Format = D3DUtil::getMapFormat(srcEle.format); - dstEle.InputSlot = (UINT)srcEle.bufferSlotIndex; - dstEle.AlignedByteOffset = (UINT)srcEle.offset; - dstEle.InputSlotClass = D3DUtil::getInputSlotClass(srcStream.slotClass); - dstEle.InstanceDataStepRate = (UINT)srcStream.instanceDataStepRate; - } - - auto& vertexStreamStrides = layout->m_vertexStreamStrides; - vertexStreamStrides.setCount(vertexStreamCount); - for (GfxIndex i = 0; i < vertexStreamCount; ++i) - { - vertexStreamStrides[i] = (UINT)vertexStreams[i].stride; - } - - returnComPtr(outLayout, layout); - return SLANG_OK; -} - -const gfx::DeviceInfo& DeviceImpl::getDeviceInfo() const { return m_info; } - -Result DeviceImpl::readBufferResource( - IBufferResource* bufferIn, Offset offset, Size size, ISlangBlob** outBlob) -{ - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - - const Size bufferSize = buffer->getDesc()->sizeInBytes; - - // This will be slow!!! - it blocks CPU on GPU completion - D3D12Resource& resource = buffer->m_resource; - - D3D12Resource stageBuf; - if (buffer->getDesc()->memoryType != MemoryType::ReadBack) - { - auto encodeInfo = encodeResourceCommands(); - - // Readback heap - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - // Resource to readback to - D3D12_RESOURCE_DESC stagingDesc; - initBufferResourceDesc(size, stagingDesc); - - SLANG_RETURN_ON_FAIL(stageBuf.initCommitted( - m_device, - heapProps, - D3D12_HEAP_FLAG_NONE, - stagingDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr)); - - // Do the copy - encodeInfo.d3dCommandList->CopyBufferRegion(stageBuf, 0, resource, offset, size); - - // Wait until complete - submitResourceCommandsAndWait(encodeInfo); - } - - D3D12Resource& stageBufRef = - buffer->getDesc()->memoryType != MemoryType::ReadBack ? stageBuf : resource; - - // Map and copy - RefPtr<ListBlob> blob = new ListBlob(); - { - UINT8* data; - D3D12_RANGE readRange = {0, size}; - - SLANG_RETURN_ON_FAIL( - stageBufRef.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data))); - - // Copy to memory buffer - blob->m_data.setCount(size); - ::memcpy(blob->m_data.getBuffer(), data, size); - - stageBufRef.getResource()->Unmap(0, nullptr); - } - returnComPtr(outBlob, blob); - return SLANG_OK; -} - -Result DeviceImpl::createProgram( - const IShaderProgram::Desc& desc, IShaderProgram** outProgram, ISlangBlob** outDiagnosticBlob) -{ - RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl(); - shaderProgram->init(desc); - ComPtr<ID3DBlob> d3dDiagnosticBlob; - auto rootShaderLayoutResult = RootShaderObjectLayoutImpl::create( - this, - shaderProgram->linkedProgram, - shaderProgram->linkedProgram->getLayout(), - shaderProgram->m_rootObjectLayout.writeRef(), - d3dDiagnosticBlob.writeRef()); - if (!SLANG_SUCCEEDED(rootShaderLayoutResult)) - { - if (outDiagnosticBlob && d3dDiagnosticBlob) - { - RefPtr<StringBlob> diagnosticBlob = - new StringBlob(String((const char*)d3dDiagnosticBlob->GetBufferPointer())); - returnComPtr(outDiagnosticBlob, diagnosticBlob); - } - return rootShaderLayoutResult; - } - returnComPtr(outProgram, shaderProgram); - return SLANG_OK; -} - -Result DeviceImpl::createShaderObjectLayout( - slang::TypeLayoutReflection* typeLayout, ShaderObjectLayoutBase** outLayout) -{ - RefPtr<ShaderObjectLayoutImpl> layout; - SLANG_RETURN_ON_FAIL( - ShaderObjectLayoutImpl::createForElementType(this, typeLayout, layout.writeRef())); - returnRefPtrMove(outLayout, layout); - return SLANG_OK; -} - -Result DeviceImpl::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject) -{ - RefPtr<ShaderObjectImpl> shaderObject; - SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create( - this, reinterpret_cast<ShaderObjectLayoutImpl*>(layout), shaderObject.writeRef())); - returnComPtr(outObject, shaderObject); - return SLANG_OK; -} - -Result DeviceImpl::createMutableShaderObject( - ShaderObjectLayoutBase* layout, IShaderObject** outObject) -{ - auto result = createShaderObject(layout, outObject); - SLANG_RETURN_ON_FAIL(result); - static_cast<ShaderObjectImpl*>(*outObject)->m_isMutable = true; - return result; -} - -Result DeviceImpl::createMutableRootShaderObject(IShaderProgram* program, IShaderObject** outObject) -{ - RefPtr<MutableRootShaderObjectImpl> result = new MutableRootShaderObjectImpl(); - result->init(this); - auto programImpl = static_cast<ShaderProgramImpl*>(program); - result->resetImpl( - this, programImpl->m_rootObjectLayout, m_cpuViewHeap.Ptr(), m_cpuSamplerHeap.Ptr(), true); - returnComPtr(outObject, result); - return SLANG_OK; -} - -Result DeviceImpl::createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outShaderTable) -{ - RefPtr<ShaderTableImpl> result = new ShaderTableImpl(); - result->m_device = this; - result->init(desc); - returnComPtr(outShaderTable, result); - return SLANG_OK; -} - -Result DeviceImpl::createGraphicsPipelineState( - const GraphicsPipelineStateDesc& desc, IPipelineState** outState) -{ - RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this); - pipelineStateImpl->init(desc); - returnComPtr(outState, pipelineStateImpl); - return SLANG_OK; -} - -Result DeviceImpl::createComputePipelineState( - const ComputePipelineStateDesc& desc, IPipelineState** outState) -{ - RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this); - pipelineStateImpl->init(desc); - returnComPtr(outState, pipelineStateImpl); - return SLANG_OK; -} - -DeviceImpl::ResourceCommandRecordInfo DeviceImpl::encodeResourceCommands() -{ - ResourceCommandRecordInfo info; - m_resourceCommandTransientHeap->createCommandBuffer(info.commandBuffer.writeRef()); - info.d3dCommandList = static_cast<CommandBufferImpl*>(info.commandBuffer.get())->m_cmdList; - return info; -} - -void DeviceImpl::submitResourceCommandsAndWait(const DeviceImpl::ResourceCommandRecordInfo& info) -{ - info.commandBuffer->close(); - m_resourceCommandQueue->executeCommandBuffer(info.commandBuffer); - m_resourceCommandTransientHeap->finish(); - m_resourceCommandTransientHeap->synchronizeAndReset(); -} - -Result DeviceImpl::createQueryPool(const IQueryPool::Desc& desc, IQueryPool** outState) -{ - switch (desc.type) - { - case QueryType::AccelerationStructureCompactedSize: - case QueryType::AccelerationStructureSerializedSize: - case QueryType::AccelerationStructureCurrentSize: - { - RefPtr<PlainBufferProxyQueryPoolImpl> queryPoolImpl = - new PlainBufferProxyQueryPoolImpl(); - uint32_t stride = 8; - if (desc.type == QueryType::AccelerationStructureSerializedSize) - stride = 16; - SLANG_RETURN_ON_FAIL(queryPoolImpl->init(desc, this, stride)); - returnComPtr(outState, queryPoolImpl); - return SLANG_OK; - } - default: - { - RefPtr<QueryPoolImpl> queryPoolImpl = new QueryPoolImpl(); - SLANG_RETURN_ON_FAIL(queryPoolImpl->init(desc, this)); - returnComPtr(outState, queryPoolImpl); - return SLANG_OK; - } - } -} - -Result DeviceImpl::createFence(const IFence::Desc& desc, IFence** outFence) -{ - RefPtr<FenceImpl> fence = new FenceImpl(); - SLANG_RETURN_ON_FAIL(fence->init(this, desc)); - returnComPtr(outFence, fence); - return SLANG_OK; -} - -Result DeviceImpl::waitForFences( - GfxCount fenceCount, IFence** fences, uint64_t* fenceValues, bool waitForAll, uint64_t timeout) -{ - ShortList<HANDLE> waitHandles; - for (GfxCount i = 0; i < fenceCount; ++i) - { - auto fenceImpl = static_cast<FenceImpl*>(fences[i]); - waitHandles.add(fenceImpl->getWaitEvent()); - SLANG_RETURN_ON_FAIL( - fenceImpl->m_fence->SetEventOnCompletion(fenceValues[i], fenceImpl->getWaitEvent())); - } - auto result = WaitForMultipleObjects( - fenceCount, - waitHandles.getArrayView().getBuffer(), - waitForAll ? TRUE : FALSE, - timeout == kTimeoutInfinite ? INFINITE : (DWORD)(timeout / 1000000)); - if (result == WAIT_TIMEOUT) - return SLANG_E_TIME_OUT; - return result == WAIT_FAILED ? SLANG_FAIL : SLANG_OK; -} - -Result DeviceImpl::getAccelerationStructurePrebuildInfo( - const IAccelerationStructure::BuildInputs& buildInputs, - IAccelerationStructure::PrebuildInfo* outPrebuildInfo) -{ - if (!m_device5) - return SLANG_E_NOT_AVAILABLE; - - D3DAccelerationStructureInputsBuilder inputsBuilder; - SLANG_RETURN_ON_FAIL(inputsBuilder.build(buildInputs, getDebugCallback())); - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo; - m_device5->GetRaytracingAccelerationStructurePrebuildInfo(&inputsBuilder.desc, &prebuildInfo); - - outPrebuildInfo->resultDataMaxSize = (Size)prebuildInfo.ResultDataMaxSizeInBytes; - outPrebuildInfo->scratchDataSize = (Size)prebuildInfo.ScratchDataSizeInBytes; - outPrebuildInfo->updateScratchDataSize = (Size)prebuildInfo.UpdateScratchDataSizeInBytes; - return SLANG_OK; -} - -Result DeviceImpl::createAccelerationStructure( - const IAccelerationStructure::CreateDesc& desc, IAccelerationStructure** outAS) -{ -#if SLANG_GFX_HAS_DXR_SUPPORT - RefPtr<AccelerationStructureImpl> result = new AccelerationStructureImpl(); - result->m_device5 = m_device5; - result->m_buffer = static_cast<BufferResourceImpl*>(desc.buffer); - result->m_size = desc.size; - result->m_offset = desc.offset; - result->m_allocator = m_cpuViewHeap; - result->m_desc.type = IResourceView::Type::AccelerationStructure; - SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&result->m_descriptor)); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.RaytracingAccelerationStructure.Location = - result->m_buffer->getDeviceAddress() + desc.offset; - m_device->CreateShaderResourceView(nullptr, &srvDesc, result->m_descriptor.cpuHandle); - returnComPtr(outAS, result); - return SLANG_OK; -#else - *outAS = nullptr; - return SLANG_FAIL; -#endif -} - -Result DeviceImpl::createRayTracingPipelineState( - const RayTracingPipelineStateDesc& inDesc, IPipelineState** outState) -{ - if (!m_device5) - { - return SLANG_E_NOT_AVAILABLE; - } - - RefPtr<RayTracingPipelineStateImpl> pipelineStateImpl = new RayTracingPipelineStateImpl(this); - pipelineStateImpl->init(inDesc); - returnComPtr(outState, pipelineStateImpl); - return SLANG_OK; -} - -Result DeviceImpl::createTransientResourceHeapImpl( - ITransientResourceHeap::Flags::Enum flags, - Size constantBufferSize, - uint32_t viewDescriptors, - uint32_t samplerDescriptors, - TransientResourceHeapImpl** outHeap) -{ - RefPtr<TransientResourceHeapImpl> result = new TransientResourceHeapImpl(); - ITransientResourceHeap::Desc desc = {}; - desc.flags = flags; - desc.samplerDescriptorCount = samplerDescriptors; - desc.constantBufferSize = constantBufferSize; - desc.constantBufferDescriptorCount = viewDescriptors; - desc.accelerationStructureDescriptorCount = viewDescriptors; - desc.srvDescriptorCount = viewDescriptors; - desc.uavDescriptorCount = viewDescriptors; - SLANG_RETURN_ON_FAIL(result->init(desc, this, viewDescriptors, samplerDescriptors)); - returnRefPtrMove(outHeap, result); - return SLANG_OK; -} - -Result DeviceImpl::createCommandQueueImpl(CommandQueueImpl** outQueue) -{ - int queueIndex = m_queueIndexAllocator.alloc(1); - // If we run out of queue index space, then the user is requesting too many queues. - if (queueIndex == -1) - return SLANG_FAIL; - - RefPtr<CommandQueueImpl> queue = new CommandQueueImpl(); - SLANG_RETURN_ON_FAIL(queue->init(this, (uint32_t)queueIndex)); - returnRefPtrMove(outQueue, queue); - return SLANG_OK; -} - -PROC DeviceImpl::loadProc(HMODULE module, char const* name) -{ - PROC proc = ::GetProcAddress(module, name); - if (!proc) - { - fprintf(stderr, "error: failed load symbol '%s'\n", name); - return nullptr; - } - return proc; -} - -DeviceImpl::~DeviceImpl() { m_shaderObjectLayoutCache = decltype(m_shaderObjectLayoutCache)(); } - -struct GraphicsSubmitter : public Submitter -{ - virtual void setRootConstantBufferView( - int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetGraphicsRootConstantBufferView(index, gpuBufferLocation); - } - virtual void setRootUAV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetGraphicsRootUnorderedAccessView(index, gpuBufferLocation); - } - virtual void setRootSRV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetGraphicsRootShaderResourceView(index, gpuBufferLocation); - } - virtual void setRootDescriptorTable( - int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override - { - m_commandList->SetGraphicsRootDescriptorTable(index, baseDescriptor); - } - void setRootSignature(ID3D12RootSignature* rootSignature) - { - m_commandList->SetGraphicsRootSignature(rootSignature); - } - void setRootConstants( - Index rootParamIndex, - Index dstOffsetIn32BitValues, - Index countOf32BitValues, - void const* srcData) override - { - m_commandList->SetGraphicsRoot32BitConstants( - UINT(rootParamIndex), UINT(countOf32BitValues), srcData, UINT(dstOffsetIn32BitValues)); - } - virtual void setPipelineState(PipelineStateBase* pipeline) override - { - auto pipelineImpl = static_cast<PipelineStateImpl*>(pipeline); - m_commandList->SetPipelineState(pipelineImpl->m_pipelineState.get()); - } - - GraphicsSubmitter(ID3D12GraphicsCommandList* commandList) - : m_commandList(commandList) - {} - - ID3D12GraphicsCommandList* m_commandList; -}; - -struct ComputeSubmitter : public Submitter -{ - virtual void setRootConstantBufferView( - int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetComputeRootConstantBufferView(index, gpuBufferLocation); - } - virtual void setRootUAV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetComputeRootUnorderedAccessView(index, gpuBufferLocation); - } - virtual void setRootSRV(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetComputeRootShaderResourceView(index, gpuBufferLocation); - } - virtual void setRootDescriptorTable( - int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override - { - m_commandList->SetComputeRootDescriptorTable(index, baseDescriptor); - } - void setRootSignature(ID3D12RootSignature* rootSignature) - { - m_commandList->SetComputeRootSignature(rootSignature); - } - void setRootConstants( - Index rootParamIndex, - Index dstOffsetIn32BitValues, - Index countOf32BitValues, - void const* srcData) override - { - m_commandList->SetComputeRoot32BitConstants( - UINT(rootParamIndex), UINT(countOf32BitValues), srcData, UINT(dstOffsetIn32BitValues)); - } - virtual void setPipelineState(PipelineStateBase* pipeline) override - { - auto pipelineImpl = static_cast<PipelineStateImpl*>(pipeline); - m_commandList->SetPipelineState(pipelineImpl->m_pipelineState.get()); - } - ComputeSubmitter(ID3D12GraphicsCommandList* commandList) - : m_commandList(commandList) - {} - - ID3D12GraphicsCommandList* m_commandList; -}; - -BufferResourceImpl::BufferResourceImpl(const Desc& desc) - : Parent(desc) - , m_defaultState(D3DUtil::getResourceState(desc.defaultState)) -{} - -BufferResourceImpl::~BufferResourceImpl() -{ - if (sharedHandle.handleValue != 0) - { - CloseHandle((HANDLE)sharedHandle.handleValue); - } -} - -DeviceAddress BufferResourceImpl::getDeviceAddress() -{ - return (DeviceAddress)m_resource.getResource()->GetGPUVirtualAddress(); -} - -Result BufferResourceImpl::getNativeResourceHandle(InteropHandle* outHandle) -{ - outHandle->handleValue = (uint64_t)m_resource.getResource(); - outHandle->api = InteropHandleAPI::D3D12; - return SLANG_OK; -} - -Result BufferResourceImpl::getSharedHandle(InteropHandle* outHandle) -{ - // Check if a shared handle already exists for this resource. - if (sharedHandle.handleValue != 0) - { - *outHandle = sharedHandle; - return SLANG_OK; - } - - // If a shared handle doesn't exist, create one and store it. - ComPtr<ID3D12Device> pDevice; - auto pResource = m_resource.getResource(); - pResource->GetDevice(IID_PPV_ARGS(pDevice.writeRef())); - SLANG_RETURN_ON_FAIL(pDevice->CreateSharedHandle( - pResource, NULL, GENERIC_ALL, nullptr, (HANDLE*)&outHandle->handleValue)); - outHandle->api = InteropHandleAPI::D3D12; - sharedHandle = *outHandle; - return SLANG_OK; -} - -Result BufferResourceImpl::map(MemoryRange* rangeToRead, void** outPointer) -{ - D3D12_RANGE range = {}; - if (rangeToRead) - { - range.Begin = (SIZE_T)rangeToRead->offset; - range.End = (SIZE_T)(rangeToRead->offset + rangeToRead->size); - } - SLANG_RETURN_ON_FAIL( - m_resource.getResource()->Map(0, rangeToRead ? &range : nullptr, outPointer)); - return SLANG_OK; -} - -Result BufferResourceImpl::unmap(MemoryRange* writtenRange) -{ - D3D12_RANGE range = {}; - if (writtenRange) - { - range.Begin = (SIZE_T)writtenRange->offset; - range.End = (SIZE_T)(writtenRange->offset + writtenRange->size); - } - m_resource.getResource()->Unmap(0, writtenRange ? &range : nullptr); - return SLANG_OK; -} - -Result BufferResourceImpl::setDebugName(const char* name) -{ - Parent::setDebugName(name); - m_resource.setDebugName(name); - return SLANG_OK; -} - -TextureResourceImpl::TextureResourceImpl(const Desc& desc) - : Parent(desc) - , m_defaultState(D3DUtil::getResourceState(desc.defaultState)) -{} - -TextureResourceImpl::~TextureResourceImpl() -{ - if (sharedHandle.handleValue != 0) - { - CloseHandle((HANDLE)sharedHandle.handleValue); - } -} - -Result TextureResourceImpl::getNativeResourceHandle(InteropHandle* outHandle) -{ - outHandle->handleValue = (uint64_t)m_resource.getResource(); - outHandle->api = InteropHandleAPI::D3D12; - return SLANG_OK; -} - -Result TextureResourceImpl::getSharedHandle(InteropHandle* outHandle) -{ - // Check if a shared handle already exists for this resource. - if (sharedHandle.handleValue != 0) - { - *outHandle = sharedHandle; - return SLANG_OK; - } - - // If a shared handle doesn't exist, create one and store it. - ComPtr<ID3D12Device> pDevice; - auto pResource = m_resource.getResource(); - pResource->GetDevice(IID_PPV_ARGS(pDevice.writeRef())); - SLANG_RETURN_ON_FAIL(pDevice->CreateSharedHandle( - pResource, NULL, GENERIC_ALL, nullptr, (HANDLE*)&outHandle->handleValue)); - outHandle->api = InteropHandleAPI::D3D12; - return SLANG_OK; -} - -Result TextureResourceImpl::setDebugName(const char* name) -{ - Parent::setDebugName(name); - m_resource.setDebugName(name); - return SLANG_OK; -} - -SamplerStateImpl::~SamplerStateImpl() { m_allocator->free(m_descriptor); } - -Result SamplerStateImpl::getNativeHandle(InteropHandle* outHandle) -{ - outHandle->api = InteropHandleAPI::D3D12CpuDescriptorHandle; - outHandle->handleValue = m_descriptor.cpuHandle.ptr; - return SLANG_OK; -} - -#if SLANG_GFX_HAS_DXR_SUPPORT - -DeviceAddress AccelerationStructureImpl::getDeviceAddress() -{ - return m_buffer->getDeviceAddress() + m_offset; -} - -Result AccelerationStructureImpl::getNativeHandle(InteropHandle* outHandle) -{ - outHandle->api = InteropHandleAPI::DeviceAddress; - outHandle->handleValue = getDeviceAddress(); - return SLANG_OK; -} - -#endif // SLANG_GFX_HAS_DXR_SUPPORT - -Result TransientResourceHeapImpl::synchronize() -{ - WaitForMultipleObjects( - (DWORD)m_waitHandles.getCount(), m_waitHandles.getArrayView().getBuffer(), TRUE, INFINITE); - m_waitHandles.clear(); - return SLANG_OK; -} - -Result TransientResourceHeapImpl::synchronizeAndReset() -{ - synchronize(); - - m_currentViewHeapIndex = -1; - m_currentSamplerHeapIndex = -1; - allocateNewViewDescriptorHeap(m_device); - allocateNewSamplerDescriptorHeap(m_device); - m_stagingCpuSamplerHeap.freeAll(); - m_stagingCpuViewHeap.freeAll(); - m_commandListAllocId = 0; - SLANG_RETURN_ON_FAIL(m_commandAllocator->Reset()); - Super::reset(); - return SLANG_OK; -} - -Result TransientResourceHeapImpl::finish() -{ - for (auto& waitInfo : m_waitInfos) - { - if (waitInfo.waitValue == 0) - continue; - if (waitInfo.fence) - { - waitInfo.queue->Signal(waitInfo.fence, waitInfo.waitValue); - waitInfo.fence->SetEventOnCompletion(waitInfo.waitValue, waitInfo.fenceEvent); - m_waitHandles.add(waitInfo.fenceEvent); - } - } - return SLANG_OK; -} - -TransientResourceHeapImpl::QueueWaitInfo& TransientResourceHeapImpl::getQueueWaitInfo( - uint32_t queueIndex) -{ - if (queueIndex < (uint32_t)m_waitInfos.getCount()) - { - return m_waitInfos[queueIndex]; - } - auto oldCount = m_waitInfos.getCount(); - m_waitInfos.setCount(queueIndex + 1); - for (auto i = oldCount; i < m_waitInfos.getCount(); i++) - { - m_waitInfos[i].waitValue = 0; - m_waitInfos[i].fenceEvent = CreateEventEx(nullptr, false, 0, EVENT_ALL_ACCESS); - } - return m_waitInfos[queueIndex]; -} - -D3D12DescriptorHeap& TransientResourceHeapImpl::getCurrentViewHeap() -{ - return m_viewHeaps[m_currentViewHeapIndex]; -} - -D3D12DescriptorHeap& TransientResourceHeapImpl::getCurrentSamplerHeap() -{ - return m_samplerHeaps[m_currentSamplerHeapIndex]; -} - -Result TransientResourceHeapImpl::queryInterface(SlangUUID const& uuid, void** outObject) -{ - if (uuid == GfxGUID::IID_ID3D12TransientResourceHeap) - { - *outObject = static_cast<ID3D12TransientResourceHeap*>(this); - addRef(); - return SLANG_OK; - } - return Super::queryInterface(uuid, outObject); -} - -Result TransientResourceHeapImpl::allocateTransientDescriptorTable( - DescriptorType type, - GfxCount count, - Offset& outDescriptorOffset, - void** outD3DDescriptorHeapHandle) -{ - auto& heap = - (type == DescriptorType::ResourceView) ? getCurrentViewHeap() : getCurrentSamplerHeap(); - int allocResult = heap.allocate((int)count); - if (allocResult == -1) - { - return SLANG_E_OUT_OF_MEMORY; - } - outDescriptorOffset = (Offset)allocResult; - *outD3DDescriptorHeapHandle = heap.getHeap(); - return SLANG_OK; -} - -TransientResourceHeapImpl::~TransientResourceHeapImpl() -{ - synchronize(); - for (auto& waitInfo : m_waitInfos) - CloseHandle(waitInfo.fenceEvent); -} - -Result TransientResourceHeapImpl::init( - const ITransientResourceHeap::Desc& desc, - DeviceImpl* device, - uint32_t viewHeapSize, - uint32_t samplerHeapSize) -{ - Super::init(desc, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, device); - m_canResize = (desc.flags & ITransientResourceHeap::Flags::AllowResizing) != 0; - m_viewHeapSize = viewHeapSize; - m_samplerHeapSize = samplerHeapSize; - - m_stagingCpuViewHeap.init( - device->m_device, - 1000000, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - D3D12_DESCRIPTOR_HEAP_FLAG_NONE); - m_stagingCpuSamplerHeap.init( - device->m_device, - 1000000, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - D3D12_DESCRIPTOR_HEAP_FLAG_NONE); - - auto d3dDevice = device->m_device; - SLANG_RETURN_ON_FAIL(d3dDevice->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(m_commandAllocator.writeRef()))); - - allocateNewViewDescriptorHeap(device); - allocateNewSamplerDescriptorHeap(device); - - return SLANG_OK; -} - -Result TransientResourceHeapImpl::allocateNewViewDescriptorHeap(DeviceImpl* device) -{ - auto nextHeapIndex = m_currentViewHeapIndex + 1; - if (nextHeapIndex < m_viewHeaps.getCount()) - { - m_viewHeaps[nextHeapIndex].deallocateAll(); - m_currentViewHeapIndex = nextHeapIndex; - return SLANG_OK; - } - auto d3dDevice = device->m_device; - D3D12DescriptorHeap viewHeap; - SLANG_RETURN_ON_FAIL(viewHeap.init( - d3dDevice, - m_viewHeapSize, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - m_currentViewHeapIndex = (int32_t)m_viewHeaps.getCount(); - m_viewHeaps.add(_Move(viewHeap)); - return SLANG_OK; -} - -Result TransientResourceHeapImpl::allocateNewSamplerDescriptorHeap(DeviceImpl* device) -{ - auto nextHeapIndex = m_currentSamplerHeapIndex + 1; - if (nextHeapIndex < m_samplerHeaps.getCount()) - { - m_samplerHeaps[nextHeapIndex].deallocateAll(); - m_currentSamplerHeapIndex = nextHeapIndex; - return SLANG_OK; - } - auto d3dDevice = device->m_device; - D3D12DescriptorHeap samplerHeap; - SLANG_RETURN_ON_FAIL(samplerHeap.init( - d3dDevice, - m_samplerHeapSize, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - m_currentSamplerHeapIndex = (int32_t)m_samplerHeaps.getCount(); - m_samplerHeaps.add(_Move(samplerHeap)); - return SLANG_OK; -} - -Result TransientResourceHeapImpl::createCommandBuffer(ICommandBuffer** outCmdBuffer) -{ - if ((Index)m_commandListAllocId < m_commandBufferPool.getCount()) - { - auto result = - static_cast<CommandBufferImpl*>(m_commandBufferPool[m_commandListAllocId].Ptr()); - m_d3dCommandListPool[m_commandListAllocId]->Reset(m_commandAllocator, nullptr); - result->reinit(); - ++m_commandListAllocId; - returnComPtr(outCmdBuffer, result); - return SLANG_OK; - } - ComPtr<ID3D12GraphicsCommandList> cmdList; - m_device->m_device->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - m_commandAllocator, - nullptr, - IID_PPV_ARGS(cmdList.writeRef())); - - m_d3dCommandListPool.add(cmdList); - RefPtr<CommandBufferImpl> cmdBuffer = new CommandBufferImpl(); - cmdBuffer->init(m_device, cmdList, this); - m_commandBufferPool.add(cmdBuffer); - ++m_commandListAllocId; - returnComPtr(outCmdBuffer, cmdBuffer); - return SLANG_OK; -} - -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; -} - -Result QueryPoolImpl::init(const IQueryPool::Desc& desc, DeviceImpl* device) -{ - m_desc = desc; - - // Translate query type. - D3D12_QUERY_HEAP_DESC heapDesc = {}; - heapDesc.Count = (UINT)desc.count; - heapDesc.NodeMask = 1; - switch (desc.type) - { - case QueryType::Timestamp: - heapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; - m_queryType = D3D12_QUERY_TYPE_TIMESTAMP; - break; - default: - return SLANG_E_INVALID_ARG; - } - - // Create query heap. - auto d3dDevice = device->m_device; - SLANG_RETURN_ON_FAIL( - d3dDevice->CreateQueryHeap(&heapDesc, IID_PPV_ARGS(m_queryHeap.writeRef()))); - - // Create readback buffer. - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - D3D12_RESOURCE_DESC resourceDesc = {}; - initBufferResourceDesc(sizeof(uint64_t) * desc.count, resourceDesc); - SLANG_RETURN_ON_FAIL(m_readBackBuffer.initCommitted( - d3dDevice, - heapProps, - D3D12_HEAP_FLAG_NONE, - resourceDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr)); - - // Create command allocator. - SLANG_RETURN_ON_FAIL(d3dDevice->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(m_commandAllocator.writeRef()))); - - // Create command list. - SLANG_RETURN_ON_FAIL(d3dDevice->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - m_commandAllocator, - nullptr, - IID_PPV_ARGS(m_commandList.writeRef()))); - m_commandList->Close(); - - // Create fence. - SLANG_RETURN_ON_FAIL( - d3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.writeRef()))); - - // Get command queue from device. - m_commandQueue = device->m_resourceCommandQueue->m_d3dQueue; - - // Create wait event. - m_waitEvent = CreateEventEx(nullptr, false, 0, EVENT_ALL_ACCESS); - - return SLANG_OK; -} - -Result QueryPoolImpl::getResult(GfxIndex queryIndex, GfxCount count, uint64_t* data) -{ - m_commandList->Reset(m_commandAllocator, nullptr); - m_commandList->ResolveQueryData( - m_queryHeap, - m_queryType, - (UINT)queryIndex, - (UINT)count, - m_readBackBuffer, - sizeof(uint64_t) * queryIndex); - m_commandList->Close(); - ID3D12CommandList* cmdList = m_commandList; - m_commandQueue->ExecuteCommandLists(1, &cmdList); - m_eventValue++; - m_fence->SetEventOnCompletion(m_eventValue, m_waitEvent); - m_commandQueue->Signal(m_fence, m_eventValue); - WaitForSingleObject(m_waitEvent, INFINITE); - m_commandAllocator->Reset(); - - int8_t* mappedData = nullptr; - D3D12_RANGE readRange = { - sizeof(uint64_t) * queryIndex, sizeof(uint64_t) * (queryIndex + count)}; - m_readBackBuffer.getResource()->Map(0, &readRange, (void**)&mappedData); - memcpy(data, mappedData + sizeof(uint64_t) * queryIndex, sizeof(uint64_t) * count); - m_readBackBuffer.getResource()->Unmap(0, nullptr); - return SLANG_OK; -} - -void QueryPoolImpl::writeTimestamp(ID3D12GraphicsCommandList* cmdList, GfxIndex index) -{ - cmdList->EndQuery(m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, (UINT)index); -} - -IQueryPool* PlainBufferProxyQueryPoolImpl::getInterface(const Guid& guid) -{ - if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool) - return static_cast<IQueryPool*>(this); - return nullptr; -} - -Result PlainBufferProxyQueryPoolImpl::init( - const IQueryPool::Desc& desc, DeviceImpl* device, uint32_t stride) -{ - ComPtr<IBufferResource> bufferResource; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.defaultState = ResourceState::CopySource; - bufferDesc.elementSize = 0; - bufferDesc.type = IResource::Type::Buffer; - bufferDesc.sizeInBytes = desc.count * stride; - bufferDesc.format = Format::Unknown; - bufferDesc.allowedStates.add(ResourceState::UnorderedAccess); - SLANG_RETURN_ON_FAIL( - device->createBufferResource(bufferDesc, nullptr, bufferResource.writeRef())); - m_bufferResource = static_cast<BufferResourceImpl*>(bufferResource.get()); - m_queryType = desc.type; - m_device = device; - m_stride = stride; - m_count = (uint32_t)desc.count; - m_desc = desc; - return SLANG_OK; -} - -Result PlainBufferProxyQueryPoolImpl::reset() -{ - m_resultDirty = true; - auto encodeInfo = m_device->encodeResourceCommands(); - D3D12_RESOURCE_BARRIER barrier = {}; - 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 = m_bufferResource->m_resource.getResource(); - encodeInfo.d3dCommandList->ResourceBarrier(1, &barrier); - m_device->submitResourceCommandsAndWait(encodeInfo); - return SLANG_OK; -} - -Result PlainBufferProxyQueryPoolImpl::getResult(GfxIndex queryIndex, GfxCount count, uint64_t* data) -{ - if (m_resultDirty) - { - auto encodeInfo = m_device->encodeResourceCommands(); - 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 = m_bufferResource->m_resource.getResource(); - encodeInfo.d3dCommandList->ResourceBarrier(1, &barrier); - - D3D12Resource stageBuf; - - auto size = (Size)m_count * m_stride; - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC stagingDesc; - initBufferResourceDesc(size, stagingDesc); - - SLANG_RETURN_ON_FAIL(stageBuf.initCommitted( - m_device->m_device, - heapProps, - D3D12_HEAP_FLAG_NONE, - stagingDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr)); - - encodeInfo.d3dCommandList->CopyBufferRegion( - stageBuf, 0, m_bufferResource->m_resource.getResource(), 0, size); - m_device->submitResourceCommandsAndWait(encodeInfo); - void* ptr = nullptr; - stageBuf.getResource()->Map(0, nullptr, &ptr); - m_result.setCount(m_count * m_stride); - memcpy(m_result.getBuffer(), ptr, m_result.getCount()); - - m_resultDirty = false; - } - - memcpy(data, m_result.getBuffer() + queryIndex * m_stride, count * m_stride); - - return SLANG_OK; -} - -void translatePostBuildInfoDescs( - int propertyQueryCount, - AccelerationStructureQueryDesc* queryDescs, - List<D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC>& postBuildInfoDescs) -{ - postBuildInfoDescs.setCount(propertyQueryCount); - for (int i = 0; i < propertyQueryCount; i++) - { - switch (queryDescs[i].queryType) - { - case QueryType::AccelerationStructureCompactedSize: - postBuildInfoDescs[i].InfoType = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE; - postBuildInfoDescs[i].DestBuffer = - static_cast<PlainBufferProxyQueryPoolImpl*>(queryDescs[i].queryPool) - ->m_bufferResource->getDeviceAddress() + - sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC) * - queryDescs[i].firstQueryIndex; - break; - case QueryType::AccelerationStructureCurrentSize: - postBuildInfoDescs[i].InfoType = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_CURRENT_SIZE; - postBuildInfoDescs[i].DestBuffer = - static_cast<PlainBufferProxyQueryPoolImpl*>(queryDescs[i].queryPool) - ->m_bufferResource->getDeviceAddress() + - sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC) * - queryDescs[i].firstQueryIndex; - break; - case QueryType::AccelerationStructureSerializedSize: - postBuildInfoDescs[i].InfoType = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_SERIALIZATION; - postBuildInfoDescs[i].DestBuffer = - static_cast<PlainBufferProxyQueryPoolImpl*>(queryDescs[i].queryPool) - ->m_bufferResource->getDeviceAddress() + - sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_SERIALIZATION_DESC) * - queryDescs[i].firstQueryIndex; - break; - } - } -} - -#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); -} - -RayTracingPipelineStateImpl::RayTracingPipelineStateImpl(DeviceImpl* device) - : m_device(device) -{} - -void RayTracingPipelineStateImpl::init(const RayTracingPipelineStateDesc& inDesc) -{ - PipelineStateDesc pipelineDesc; - pipelineDesc.type = PipelineType::RayTracing; - pipelineDesc.rayTracing.set(inDesc); - initializeBase(pipelineDesc); -} - -Result RayTracingPipelineStateImpl::getNativeHandle(InteropHandle* outHandle) -{ - SLANG_RETURN_ON_FAIL(ensureAPIPipelineStateCreated()); - outHandle->api = InteropHandleAPI::D3D12; - outHandle->handleValue = reinterpret_cast<uint64_t>(m_stateObject.get()); - return SLANG_OK; -} - -Result RayTracingPipelineStateImpl::ensureAPIPipelineStateCreated() -{ - if (m_stateObject) - return SLANG_OK; - - auto program = static_cast<ShaderProgramImpl*>(m_program.Ptr()); - auto slangGlobalScope = program->linkedProgram; - auto programLayout = slangGlobalScope->getLayout(); - - List<D3D12_STATE_SUBOBJECT> subObjects; - ChunkedList<D3D12_DXIL_LIBRARY_DESC> dxilLibraries; - ChunkedList<D3D12_HIT_GROUP_DESC> hitGroups; - ChunkedList<ComPtr<ISlangBlob>> codeBlobs; - ChunkedList<D3D12_EXPORT_DESC> exports; - ChunkedList<const wchar_t*> strPtrs; - - ComPtr<ISlangBlob> diagnostics; - ChunkedList<OSString> stringPool; - auto getWStr = [&](const char* name) - { - String str = String(name); - auto wstr = str.toWString(); - return stringPool.add(wstr)->begin(); - }; - auto compileShader = [&](slang::EntryPointLayout* entryPointInfo, - slang::IComponentType* component, - SlangInt entryPointIndex) - { - ComPtr<ISlangBlob> codeBlob; - auto compileResult = component->getEntryPointCode( - entryPointIndex, 0, codeBlob.writeRef(), diagnostics.writeRef()); - if (diagnostics.get()) - { - getDebugCallback()->handleMessage( - compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error, - DebugMessageSource::Slang, - (char*)diagnostics->getBufferPointer()); - } - SLANG_RETURN_ON_FAIL(compileResult); - codeBlobs.add(codeBlob); - D3D12_DXIL_LIBRARY_DESC library = {}; - library.DXILLibrary.BytecodeLength = codeBlob->getBufferSize(); - library.DXILLibrary.pShaderBytecode = codeBlob->getBufferPointer(); - library.NumExports = 1; - D3D12_EXPORT_DESC exportDesc = {}; - exportDesc.Name = getWStr(entryPointInfo->getNameOverride()); - exportDesc.ExportToRename = getWStr(entryPointInfo->getNameOverride()); - exportDesc.Flags = D3D12_EXPORT_FLAG_NONE; - library.pExports = exports.add(exportDesc); - - D3D12_STATE_SUBOBJECT dxilSubObject = {}; - dxilSubObject.Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - dxilSubObject.pDesc = dxilLibraries.add(library); - subObjects.add(dxilSubObject); - return SLANG_OK; - }; - if (program->linkedEntryPoints.getCount() == 0) - { - for (SlangUInt i = 0; i < programLayout->getEntryPointCount(); i++) - { - SLANG_RETURN_ON_FAIL(compileShader( - programLayout->getEntryPointByIndex(i), program->linkedProgram, (SlangInt)i)); - } - } - else - { - for (auto& entryPoint : program->linkedEntryPoints) - { - SLANG_RETURN_ON_FAIL( - compileShader(entryPoint->getLayout()->getEntryPointByIndex(0), entryPoint, 0)); - } - } - - for (Index i = 0; i < desc.rayTracing.hitGroupDescs.getCount(); i++) - { - auto& hitGroup = desc.rayTracing.hitGroups[i]; - D3D12_HIT_GROUP_DESC hitGroupDesc = {}; - hitGroupDesc.Type = hitGroup.intersectionEntryPoint.getLength() == 0 - ? D3D12_HIT_GROUP_TYPE_TRIANGLES - : D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; - - if (hitGroup.anyHitEntryPoint.getLength()) - { - hitGroupDesc.AnyHitShaderImport = getWStr(hitGroup.anyHitEntryPoint.getBuffer()); - } - if (hitGroup.closestHitEntryPoint.getLength()) - { - hitGroupDesc.ClosestHitShaderImport = - getWStr(hitGroup.closestHitEntryPoint.getBuffer()); - } - if (hitGroup.intersectionEntryPoint.getLength()) - { - hitGroupDesc.IntersectionShaderImport = - getWStr(hitGroup.intersectionEntryPoint.getBuffer()); - } - hitGroupDesc.HitGroupExport = getWStr(hitGroup.hitGroupName.getBuffer()); - - D3D12_STATE_SUBOBJECT hitGroupSubObject = {}; - hitGroupSubObject.Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; - hitGroupSubObject.pDesc = hitGroups.add(hitGroupDesc); - subObjects.add(hitGroupSubObject); - } - - D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {}; - // According to DXR spec, fixed function triangle intersections must use float2 as ray - // attributes that defines the barycentric coordinates at intersection. - shaderConfig.MaxAttributeSizeInBytes = (UINT)desc.rayTracing.maxAttributeSizeInBytes; - shaderConfig.MaxPayloadSizeInBytes = (UINT)desc.rayTracing.maxRayPayloadSize; - D3D12_STATE_SUBOBJECT shaderConfigSubObject = {}; - shaderConfigSubObject.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; - shaderConfigSubObject.pDesc = &shaderConfig; - subObjects.add(shaderConfigSubObject); - - D3D12_GLOBAL_ROOT_SIGNATURE globalSignatureDesc = {}; - globalSignatureDesc.pGlobalRootSignature = program->m_rootObjectLayout->m_rootSignature.get(); - D3D12_STATE_SUBOBJECT globalSignatureSubobject = {}; - globalSignatureSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; - globalSignatureSubobject.pDesc = &globalSignatureDesc; - subObjects.add(globalSignatureSubobject); - - D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {}; - pipelineConfig.MaxTraceRecursionDepth = desc.rayTracing.maxRecursion; - D3D12_STATE_SUBOBJECT pipelineConfigSubobject = {}; - pipelineConfigSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; - pipelineConfigSubobject.pDesc = &pipelineConfig; - subObjects.add(pipelineConfigSubobject); - - if (m_device->m_pipelineCreationAPIDispatcher) - { - m_device->m_pipelineCreationAPIDispatcher->beforeCreateRayTracingState( - m_device, slangGlobalScope); - } - - D3D12_STATE_OBJECT_DESC rtpsoDesc = {}; - rtpsoDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; - rtpsoDesc.NumSubobjects = (UINT)subObjects.getCount(); - rtpsoDesc.pSubobjects = subObjects.getBuffer(); - SLANG_RETURN_ON_FAIL( - m_device->m_device5->CreateStateObject(&rtpsoDesc, IID_PPV_ARGS(m_stateObject.writeRef()))); - - if (m_device->m_pipelineCreationAPIDispatcher) - { - m_device->m_pipelineCreationAPIDispatcher->afterCreateRayTracingState( - m_device, slangGlobalScope); - } - return SLANG_OK; -} - -#endif - -GfxCount ShaderObjectImpl::getEntryPointCount() { return 0; } - -Result ShaderObjectImpl::getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) -{ - *outEntryPoint = nullptr; - return SLANG_OK; -} - -const void* ShaderObjectImpl::getRawData() { return m_data.getBuffer(); } - -Size ShaderObjectImpl::getSize() { return (Size)m_data.getCount(); } - -// TODO: Change Index to Offset/Size? -Result ShaderObjectImpl::setData(ShaderOffset const& inOffset, void const* data, size_t inSize) -{ - Index offset = inOffset.uniformOffset; - Index size = inSize; - - char* dest = m_data.getBuffer(); - Index availableSize = m_data.getCount(); - - // TODO: We really should bounds-check access rather than silently ignoring sets - // that are too large, but we have several test cases that set more data than - // an object actually stores on several targets... - // - if (offset < 0) - { - size += offset; - offset = 0; - } - if ((offset + size) >= availableSize) - { - size = availableSize - offset; - } - - memcpy(dest + offset, data, size); - - m_isConstantBufferDirty = true; - - m_version++; - - return SLANG_OK; -} - -Result ShaderObjectImpl::setObject(ShaderOffset const& offset, IShaderObject* object) -{ - SLANG_RETURN_ON_FAIL(Super::setObject(offset, object)); - if (m_isMutable) - { - auto subObjectIndex = getSubObjectIndex(offset); - if (subObjectIndex >= m_subObjectVersions.getCount()) - m_subObjectVersions.setCount(subObjectIndex + 1); - m_subObjectVersions[subObjectIndex] = static_cast<ShaderObjectImpl*>(object)->m_version; - m_version++; - } - return SLANG_OK; -} - -Result ShaderObjectImpl::setSampler(ShaderOffset const& offset, ISamplerState* sampler) -{ - if (offset.bindingRangeIndex < 0) - return SLANG_E_INVALID_ARG; - auto layout = getLayout(); - if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) - return SLANG_E_INVALID_ARG; - auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - auto samplerImpl = static_cast<SamplerStateImpl*>(sampler); - ID3D12Device* d3dDevice = static_cast<DeviceImpl*>(getDevice())->m_device; - d3dDevice->CopyDescriptorsSimple( - 1, - m_descriptorSet.samplerTable.getCpuHandle( - bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), - samplerImpl->m_descriptor.cpuHandle, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - m_version++; - return SLANG_OK; -} - -Result ShaderObjectImpl::setCombinedTextureSampler( - ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) -{ -#if 0 - if (offset.bindingRangeIndex < 0) - return SLANG_E_INVALID_ARG; - auto layout = getLayout(); - if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) - return SLANG_E_INVALID_ARG; - auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - auto resourceViewImpl = static_cast<ResourceViewImpl*>(textureView); - ID3D12Device* d3dDevice = static_cast<DeviceImpl*>(getDevice())->m_device; - d3dDevice->CopyDescriptorsSimple( - 1, - m_resourceHeap.getCpuHandle( - m_descriptorSet.m_resourceTable + - bindingRange.binding.offsetInDescriptorTable.resource + - (int32_t)offset.bindingArrayIndex), - resourceViewImpl->m_descriptor.cpuHandle, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - auto samplerImpl = static_cast<SamplerStateImpl*>(sampler); - d3dDevice->CopyDescriptorsSimple( - 1, - m_samplerHeap.getCpuHandle( - m_descriptorSet.m_samplerTable + - bindingRange.binding.offsetInDescriptorTable.sampler + - (int32_t)offset.bindingArrayIndex), - samplerImpl->m_descriptor.cpuHandle, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); -#endif - m_version++; - return SLANG_OK; -} - -Result ShaderObjectImpl::init( - DeviceImpl* device, - ShaderObjectLayoutImpl* layout, - DescriptorHeapReference viewHeap, - DescriptorHeapReference samplerHeap) -{ - m_device = device; - - m_layout = layout; - - m_cachedTransientHeap = nullptr; - m_cachedTransientHeapVersion = 0; - m_isConstantBufferDirty = true; - - // If the layout tells us that there is any uniform data, - // then we will allocate a CPU memory buffer to hold that data - // while it is being set from the host. - // - // Once the user is done setting the parameters/fields of this - // shader object, we will produce a GPU-memory version of the - // uniform data (which includes values from this object and - // any existential-type sub-objects). - // - size_t uniformSize = layout->getElementTypeLayout()->getSize(); - if (uniformSize) - { - m_data.setCount(uniformSize); - memset(m_data.getBuffer(), 0, uniformSize); - } - m_rootArguments.setCount(layout->getOwnUserRootParameterCount()); - memset( - m_rootArguments.getBuffer(), - 0, - sizeof(D3D12_GPU_VIRTUAL_ADDRESS) * m_rootArguments.getCount()); - // Each shader object will own CPU descriptor heap memory - // for any resource or sampler descriptors it might store - // as part of its value. - // - // This allocate includes a reservation for any constant - // buffer descriptor pertaining to the ordinary data, - // but does *not* include any descriptors that are managed - // as part of sub-objects. - // - if (auto resourceCount = layout->getResourceSlotCount()) - { - m_descriptorSet.resourceTable.allocate(viewHeap, resourceCount); - - // We must also ensure that the memory for any resources - // referenced by descriptors in this object does not get - // freed while the object is still live. - // - m_boundResources.setCount(resourceCount); - } - if (auto samplerCount = layout->getSamplerSlotCount()) - { - m_descriptorSet.samplerTable.allocate(samplerHeap, samplerCount); - } - - // If the layout specifies that we have any sub-objects, then - // we need to size the array to account for them. - // - Index subObjectCount = layout->getSubObjectSlotCount(); - m_objects.setCount(subObjectCount); - - for (auto subObjectRangeInfo : layout->getSubObjectRanges()) - { - auto subObjectLayout = subObjectRangeInfo.layout; - - // In the case where the sub-object range represents an - // existential-type leaf field (e.g., an `IBar`), we - // cannot pre-allocate the object(s) to go into that - // range, since we can't possibly know what to allocate - // at this point. - // - if (!subObjectLayout) - continue; - // - // Otherwise, we will allocate a sub-object to fill - // in each entry in this range, based on the layout - // information we already have. - - auto& bindingRangeInfo = layout->getBindingRange(subObjectRangeInfo.bindingRangeIndex); - for (uint32_t i = 0; i < bindingRangeInfo.count; ++i) - { - RefPtr<ShaderObjectImpl> subObject; - SLANG_RETURN_ON_FAIL( - ShaderObjectImpl::create(device, subObjectLayout, subObject.writeRef())); - m_objects[bindingRangeInfo.subObjectIndex + i] = subObject; - } - } - - return SLANG_OK; -} - -/// Write the uniform/ordinary data of this object into the given `dest` buffer at the given -/// `offset` - -Result ShaderObjectImpl::_writeOrdinaryData( - PipelineCommandEncoder* encoder, - BufferResourceImpl* buffer, - Offset offset, - Size destSize, - ShaderObjectLayoutImpl* specializedLayout) -{ - auto src = m_data.getBuffer(); - auto srcSize = Size(m_data.getCount()); - - SLANG_ASSERT(srcSize <= destSize); - - uploadBufferDataImpl( - encoder->m_device, - encoder->m_d3dCmdList, - encoder->m_transientHeap, - buffer, - offset, - srcSize, - src); - - // In the case where this object has any sub-objects of - // existential/interface type, we need to recurse on those objects - // that need to write their state into an appropriate "pending" allocation. - // - // Note: Any values that could fit into the "payload" included - // in the existential-type field itself will have already been - // written as part of `setObject()`. This loop only needs to handle - // those sub-objects that do not "fit." - // - // An implementers looking at this code might wonder if things could be changed - // so that *all* writes related to sub-objects for interface-type fields could - // be handled in this one location, rather than having some in `setObject()` and - // others handled here. - // - Index subObjectRangeCounter = 0; - for (auto const& subObjectRangeInfo : specializedLayout->getSubObjectRanges()) - { - Index subObjectRangeIndex = subObjectRangeCounter++; - auto const& bindingRangeInfo = - specializedLayout->getBindingRange(subObjectRangeInfo.bindingRangeIndex); - - // We only need to handle sub-object ranges for interface/existential-type fields, - // because fields of constant-buffer or parameter-block type are responsible for - // the ordinary/uniform data of their own existential/interface-type sub-objects. - // - if (bindingRangeInfo.bindingType != slang::BindingType::ExistentialValue) - continue; - - // Each sub-object range represents a single "leaf" field, but might be nested - // under zero or more outer arrays, such that the number of existential values - // in the same range can be one or more. - // - auto count = bindingRangeInfo.count; - - // We are not concerned with the case where the existential value(s) in the range - // git into the payload part of the leaf field. - // - // In the case where the value didn't fit, the Slang layout strategy would have - // considered the requirements of the value as a "pending" allocation, and would - // allocate storage for the ordinary/uniform part of that pending allocation inside - // of the parent object's type layout. - // - // Here we assume that the Slang reflection API can provide us with a single byte - // offset and stride for the location of the pending data allocation in the - // specialized type layout, which will store the values for this sub-object range. - // - // TODO: The reflection API functions we are assuming here haven't been implemented - // yet, so the functions being called here are stubs. - // - // TODO: It might not be that a single sub-object range can reliably map to a single - // contiguous array with a single stride; we need to carefully consider what the - // layout logic does for complex cases with multiple layers of nested arrays and - // structures. - // - Offset subObjectRangePendingDataOffset = subObjectRangeInfo.offset.pendingOrdinaryData; - Size subObjectRangePendingDataStride = subObjectRangeInfo.stride.pendingOrdinaryData; - - // If the range doesn't actually need/use the "pending" allocation at all, then - // we need to detect that case and skip such ranges. - // - // TODO: This should probably be handled on a per-object basis by caching a "does it - // fit?" bit as part of the information for bound sub-objects, given that we already - // compute the "does it fit?" status as part of `setObject()`. - // - if (subObjectRangePendingDataOffset == 0) - continue; - - for (uint32_t i = 0; i < count; ++i) - { - auto subObject = m_objects[bindingRangeInfo.subObjectIndex + i]; - - RefPtr<ShaderObjectLayoutImpl> subObjectLayout; - SLANG_RETURN_ON_FAIL(subObject->getSpecializedLayout(subObjectLayout.writeRef())); - - auto subObjectOffset = - subObjectRangePendingDataOffset + i * subObjectRangePendingDataStride; - - subObject->_writeOrdinaryData( - encoder, - buffer, - offset + subObjectOffset, - destSize - subObjectOffset, - subObjectLayout); - } - } - - return SLANG_OK; -} - -bool ShaderObjectImpl::shouldAllocateConstantBuffer(TransientResourceHeapImpl* transientHeap) -{ - if (m_isConstantBufferDirty || m_cachedTransientHeap != transientHeap || - m_cachedTransientHeapVersion != transientHeap->getVersion()) - { - return true; - } - return false; -} - -/// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed - -Result ShaderObjectImpl::_ensureOrdinaryDataBufferCreatedIfNeeded( - PipelineCommandEncoder* encoder, ShaderObjectLayoutImpl* specializedLayout) -{ - // If data has been changed since last allocation/filling of constant buffer, - // we will need to allocate a new one. - // - if (!shouldAllocateConstantBuffer(encoder->m_transientHeap)) - { - return SLANG_OK; - } - m_isConstantBufferDirty = false; - m_cachedTransientHeap = encoder->m_transientHeap; - m_cachedTransientHeapVersion = encoder->m_transientHeap->getVersion(); - - // Computing the size of the ordinary data buffer is *not* just as simple - // as using the size of the `m_ordinayData` array that we store. The reason - // for the added complexity is that interface-type fields may lead to the - // storage being specialized such that it needs extra appended data to - // store the concrete values that logically belong in those interface-type - // fields but wouldn't fit in the fixed-size allocation we gave them. - // - m_constantBufferSize = specializedLayout->getTotalOrdinaryDataSize(); - if (m_constantBufferSize == 0) - { - return SLANG_OK; - } - - // Once we have computed how large the buffer should be, we can allocate - // it from the transient resource heap. - // - auto alignedConstantBufferSize = D3DUtil::calcAligned(m_constantBufferSize, 256); - SLANG_RETURN_ON_FAIL(encoder->m_commandBuffer->m_transientHeap->allocateConstantBuffer( - alignedConstantBufferSize, m_constantBufferWeakPtr, m_constantBufferOffset)); - - // Once the buffer is allocated, we can use `_writeOrdinaryData` to fill it in. - // - // Note that `_writeOrdinaryData` is potentially recursive in the case - // where this object contains interface/existential-type fields, so we - // don't need or want to inline it into this call site. - // - SLANG_RETURN_ON_FAIL(_writeOrdinaryData( - encoder, - static_cast<BufferResourceImpl*>(m_constantBufferWeakPtr), - m_constantBufferOffset, - m_constantBufferSize, - specializedLayout)); - - { - // We also create and store a descriptor for our root constant buffer - // into the descriptor table allocation that was reserved for them. - // - // We always know that the ordinary data buffer will be the first descriptor - // in the table of resource views. - // - auto descriptorTable = m_descriptorSet.resourceTable; - D3D12_CONSTANT_BUFFER_VIEW_DESC viewDesc = {}; - viewDesc.BufferLocation = static_cast<BufferResourceImpl*>(m_constantBufferWeakPtr) - ->m_resource.getResource() - ->GetGPUVirtualAddress() + - m_constantBufferOffset; - viewDesc.SizeInBytes = (UINT)alignedConstantBufferSize; - encoder->m_device->CreateConstantBufferView(&viewDesc, descriptorTable.getCpuHandle()); - } - - return SLANG_OK; -} - -void ShaderObjectImpl::updateSubObjectsRecursive() -{ - if (!m_isMutable) - return; - auto& subObjectRanges = getLayout()->getSubObjectRanges(); - for (Slang::Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectRanges.getCount(); - subObjectRangeIndex++) - { - auto const& subObjectRange = subObjectRanges[subObjectRangeIndex]; - auto const& bindingRange = getLayout()->getBindingRange(subObjectRange.bindingRangeIndex); - Slang::Index count = bindingRange.count; - - for (Slang::Index subObjectIndexInRange = 0; subObjectIndexInRange < count; - subObjectIndexInRange++) - { - Slang::Index objectIndex = bindingRange.subObjectIndex + subObjectIndexInRange; - auto subObject = m_objects[objectIndex].Ptr(); - if (!subObject) - continue; - subObject->updateSubObjectsRecursive(); - if (m_subObjectVersions[objectIndex] != m_objects[objectIndex]->m_version) - { - ShaderOffset offset; - offset.bindingRangeIndex = (GfxIndex)subObjectRange.bindingRangeIndex; - offset.bindingArrayIndex = (GfxIndex)subObjectIndexInRange; - setObject(offset, subObject); - } - } - } -} - -/// Prepare to bind this object as a parameter block. -/// -/// This involves allocating and binding any descriptor tables necessary -/// to to store the state of the object. The function returns a descriptor -/// set formed from any table(s) allocated. In addition, the `ioOffset` -/// parameter will be adjusted to be correct for binding values into -/// the resulting descriptor set. -/// -/// Returns: -/// SLANG_OK when successful, -/// SLANG_E_OUT_OF_MEMORY when descriptor heap is full. -/// - -Result ShaderObjectImpl::prepareToBindAsParameterBlock( - BindingContext* context, - BindingOffset& ioOffset, - ShaderObjectLayoutImpl* specializedLayout, - DescriptorSet& outDescriptorSet) -{ - auto transientHeap = context->transientHeap; - auto submitter = context->submitter; - - // When writing into the new descriptor set, resource and sampler - // descriptors will need to start at index zero in the respective - // tables. - // - ioOffset.resource = 0; - ioOffset.sampler = 0; - - // The index of the next root parameter to bind will be maintained, - // but needs to be incremented by the number of descriptor tables - // we allocate (zero or one resource table and zero or one sampler - // table). - // - auto& rootParamIndex = ioOffset.rootParam; - - if (auto descriptorCount = specializedLayout->getTotalResourceDescriptorCount()) - { - // There is a non-zero number of resource descriptors needed, - // so we will allocate a table out of the appropriate heap, - // and store it into the appropriate part of `descriptorSet`. - // - auto descriptorHeap = &transientHeap->getCurrentViewHeap(); - auto& table = outDescriptorSet.resourceTable; - - // Allocate the table. - // - if (!table.allocate(descriptorHeap, descriptorCount)) - { - context->outOfMemoryHeap = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - return SLANG_E_OUT_OF_MEMORY; - } - - // Bind the table to the pipeline, consuming the next available - // root parameter. - // - auto tableRootParamIndex = rootParamIndex++; - submitter->setRootDescriptorTable(tableRootParamIndex, table.getGpuHandle()); - } - if (auto descriptorCount = specializedLayout->getTotalSamplerDescriptorCount()) - { - // There is a non-zero number of sampler descriptors needed, - // so we will allocate a table out of the appropriate heap, - // and store it into the appropriate part of `descriptorSet`. - // - auto descriptorHeap = &transientHeap->getCurrentSamplerHeap(); - auto& table = outDescriptorSet.samplerTable; - - // Allocate the table. - // - if (!table.allocate(descriptorHeap, descriptorCount)) - { - context->outOfMemoryHeap = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - return SLANG_E_OUT_OF_MEMORY; - } - - // Bind the table to the pipeline, consuming the next available - // root parameter. - // - auto tableRootParamIndex = rootParamIndex++; - submitter->setRootDescriptorTable(tableRootParamIndex, table.getGpuHandle()); - } - - return SLANG_OK; -} - -bool ShaderObjectImpl::checkIfCachedDescriptorSetIsValidRecursive(BindingContext* context) -{ - if (shouldAllocateConstantBuffer(context->transientHeap)) - return false; - if (m_isMutable && m_version != m_cachedGPUDescriptorSetVersion) - return false; - if (m_cachedGPUDescriptorSet.resourceTable.getDescriptorCount() != 0 && - m_cachedGPUDescriptorSet.resourceTable.m_heap.ptr.linearHeap->getHeap() != - m_cachedTransientHeap->getCurrentViewHeap().getHeap()) - return false; - if (m_cachedGPUDescriptorSet.samplerTable.getDescriptorCount() != 0 && - m_cachedGPUDescriptorSet.samplerTable.m_heap.ptr.linearHeap->getHeap() != - m_cachedTransientHeap->getCurrentSamplerHeap().getHeap()) - return false; - - auto& subObjectRanges = getLayout()->getSubObjectRanges(); - for (Slang::Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectRanges.getCount(); - subObjectRangeIndex++) - { - auto const& subObjectRange = subObjectRanges[subObjectRangeIndex]; - auto const& bindingRange = getLayout()->getBindingRange(subObjectRange.bindingRangeIndex); - if (bindingRange.bindingType != slang::BindingType::ParameterBlock) - continue; - Slang::Index count = bindingRange.count; - - for (Slang::Index subObjectIndexInRange = 0; subObjectIndexInRange < count; - subObjectIndexInRange++) - { - Slang::Index objectIndex = bindingRange.subObjectIndex + subObjectIndexInRange; - auto subObject = m_objects[objectIndex].Ptr(); - if (!subObject) - continue; - if (subObject->checkIfCachedDescriptorSetIsValidRecursive(context)) - return false; - } - } - return true; -} - -/// Bind this object as a `ParameterBlock<X>` - -Result ShaderObjectImpl::bindAsParameterBlock( - BindingContext* context, BindingOffset const& offset, ShaderObjectLayoutImpl* specializedLayout) -{ - if (checkIfCachedDescriptorSetIsValidRecursive(context)) - { - // If we already have a valid gpu descriptor table in the current - // heap, bind it. - auto rootParamIndex = offset.rootParam; - if (m_cachedGPUDescriptorSet.resourceTable.getDescriptorCount()) - { - auto tableRootParamIndex = rootParamIndex++; - context->submitter->setRootDescriptorTable( - tableRootParamIndex, m_cachedGPUDescriptorSet.resourceTable.getGpuHandle()); - } - if (m_cachedGPUDescriptorSet.samplerTable.getDescriptorCount()) - { - auto tableRootParamIndex = rootParamIndex++; - context->submitter->setRootDescriptorTable( - tableRootParamIndex, m_cachedGPUDescriptorSet.samplerTable.getGpuHandle()); - } - return SLANG_OK; - } - - // The first step to binding an object as a parameter block is to allocate a descriptor - // set (consisting of zero or one resource descriptor table and zero or one sampler - // descriptor table) to represent its values. - // - BindingOffset subOffset = offset; - SLANG_RETURN_ON_FAIL(prepareToBindAsParameterBlock( - context, /* inout */ subOffset, specializedLayout, m_cachedGPUDescriptorSet)); - - // Next we bind the object into that descriptor set as if it were being used - // as a `ConstantBuffer<X>`. - // - SLANG_RETURN_ON_FAIL( - bindAsConstantBuffer(context, m_cachedGPUDescriptorSet, subOffset, specializedLayout)); - - m_cachedGPUDescriptorSetVersion = m_version; - return SLANG_OK; -} - -/// Bind this object as a `ConstantBuffer<X>` - -Result ShaderObjectImpl::bindAsConstantBuffer( - BindingContext* context, - DescriptorSet const& descriptorSet, - BindingOffset const& offset, - ShaderObjectLayoutImpl* specializedLayout) -{ - // If we are to bind as a constant buffer we first need to ensure that - // the ordinary data buffer is created, if this object needs one. - // - SLANG_RETURN_ON_FAIL( - _ensureOrdinaryDataBufferCreatedIfNeeded(context->encoder, specializedLayout)); - - // Next, we need to bind all of the resource descriptors for this object - // (including any ordinary data buffer) into the provided `descriptorSet`. - // - auto resourceCount = specializedLayout->getResourceSlotCount(); - if (resourceCount) - { - auto& dstTable = descriptorSet.resourceTable; - auto& srcTable = m_descriptorSet.resourceTable; - - context->device->m_device->CopyDescriptorsSimple( - UINT(resourceCount), - dstTable.getCpuHandle(offset.resource), - srcTable.getCpuHandle(), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - - // Finally, we delegate to `_bindImpl` to bind samplers and sub-objects, - // since the logic is shared with the `bindAsValue()` case below. - // - SLANG_RETURN_ON_FAIL(_bindImpl(context, descriptorSet, offset, specializedLayout)); - return SLANG_OK; -} - -/// Bind this object as a value (for an interface-type parameter) - -Result ShaderObjectImpl::bindAsValue( - BindingContext* context, - DescriptorSet const& descriptorSet, - BindingOffset const& offset, - ShaderObjectLayoutImpl* specializedLayout) -{ - // When binding a value for an interface-type field we do *not* want - // to bind a buffer for the ordinary data (if there is any) because - // ordinary data for interface-type fields gets allocated into the - // parent object's ordinary data buffer. - // - // This CPU-memory descriptor table that holds resource descriptors - // will have already been allocated to have space for an ordinary data - // buffer (if needed), so we need to take care to skip over that - // descriptor when copying descriptors from the CPU-memory set - // to the GPU-memory `descriptorSet`. - // - auto skipResourceCount = specializedLayout->getOrdinaryDataBufferCount(); - auto resourceCount = specializedLayout->getResourceSlotCount() - skipResourceCount; - if (resourceCount) - { - auto& dstTable = descriptorSet.resourceTable; - auto& srcTable = m_descriptorSet.resourceTable; - - context->device->m_device->CopyDescriptorsSimple( - UINT(resourceCount), - dstTable.getCpuHandle(offset.resource), - srcTable.getCpuHandle(skipResourceCount), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - - // Finally, we delegate to `_bindImpl` to bind samplers and sub-objects, - // since the logic is shared with the `bindAsConstantBuffer()` case above. - // - // Note: Just like we had to do some subtle handling of the ordinary data buffer - // above, here we need to contend with the fact that the `offset.resource` fields - // computed for sub-object ranges were baked to take the ordinary data buffer - // into account, so that if `skipResourceCount` is non-zero then they are all - // too high by `skipResourceCount`. - // - // We will address the problem here by computing a modified offset that adjusts - // for the ordinary data buffer that we have not bound after all. - // - BindingOffset subOffset = offset; - subOffset.resource -= skipResourceCount; - SLANG_RETURN_ON_FAIL(_bindImpl(context, descriptorSet, subOffset, specializedLayout)); - return SLANG_OK; -} - -/// Shared logic for `bindAsConstantBuffer()` and `bindAsValue()` - -Result ShaderObjectImpl::_bindImpl( - BindingContext* context, - DescriptorSet const& descriptorSet, - BindingOffset const& offset, - ShaderObjectLayoutImpl* specializedLayout) -{ - // We start by binding all the sampler decriptors, if needed. - // - // Note: resource descriptors were handled in either `bindAsConstantBuffer()` - // or `bindAsValue()` before calling into `_bindImpl()`. - // - if (auto samplerCount = specializedLayout->getSamplerSlotCount()) - { - auto& dstTable = descriptorSet.samplerTable; - auto& srcTable = m_descriptorSet.samplerTable; - - context->device->m_device->CopyDescriptorsSimple( - UINT(samplerCount), - dstTable.getCpuHandle(offset.sampler), - srcTable.getCpuHandle(), - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - } - - // Next we iterate over the sub-object ranges and bind anything they require. - // - auto& subObjectRanges = specializedLayout->getSubObjectRanges(); - auto subObjectRangeCount = subObjectRanges.getCount(); - for (Index i = 0; i < subObjectRangeCount; i++) - { - auto& subObjectRange = specializedLayout->getSubObjectRange(i); - auto& bindingRange = specializedLayout->getBindingRange(subObjectRange.bindingRangeIndex); - auto subObjectIndex = bindingRange.subObjectIndex; - auto subObjectLayout = subObjectRange.layout.Ptr(); - - BindingOffset rangeOffset = offset; - rangeOffset += subObjectRange.offset; - - BindingOffset rangeStride = subObjectRange.stride; - - switch (bindingRange.bindingType) - { - case slang::BindingType::ConstantBuffer: - { - auto objOffset = rangeOffset; - for (uint32_t j = 0; j < bindingRange.count; j++) - { - auto& object = m_objects[subObjectIndex + j]; - SLANG_RETURN_ON_FAIL(object->bindAsConstantBuffer( - context, descriptorSet, objOffset, subObjectLayout)); - objOffset += rangeStride; - } - } - break; - - case slang::BindingType::ParameterBlock: - { - auto objOffset = rangeOffset; - for (uint32_t j = 0; j < bindingRange.count; j++) - { - auto& object = m_objects[subObjectIndex + j]; - SLANG_RETURN_ON_FAIL( - object->bindAsParameterBlock(context, objOffset, subObjectLayout)); - objOffset += rangeStride; - } - } - break; - - case slang::BindingType::ExistentialValue: - if (subObjectLayout) - { - auto objOffset = rangeOffset; - for (uint32_t j = 0; j < bindingRange.count; j++) - { - auto& object = m_objects[subObjectIndex + j]; - SLANG_RETURN_ON_FAIL( - object->bindAsValue(context, descriptorSet, objOffset, subObjectLayout)); - objOffset += rangeStride; - } - } - break; - } - } - - return SLANG_OK; -} - -Result ShaderObjectImpl::bindRootArguments(BindingContext* context, uint32_t& index) -{ - auto layoutImpl = getLayout(); - for (Index i = 0; i < m_rootArguments.getCount(); i++) - { - switch (layoutImpl->getRootParameterInfo(i).type) - { - case IResourceView::Type::ShaderResource: - case IResourceView::Type::AccelerationStructure: - context->submitter->setRootSRV(index, m_rootArguments[i]); - break; - case IResourceView::Type::UnorderedAccess: - context->submitter->setRootUAV(index, m_rootArguments[i]); - break; - default: - continue; - } - index++; - } - for (auto& subObject : m_objects) - { - if (subObject) - { - SLANG_RETURN_ON_FAIL(subObject->bindRootArguments(context, index)); - } - } - return SLANG_OK; -} - -/// Get the layout of this shader object with specialization arguments considered -/// -/// This operation should only be called after the shader object has been -/// fully filled in and finalized. -/// - -Result ShaderObjectImpl::getSpecializedLayout(ShaderObjectLayoutImpl** outLayout) -{ - if (!m_specializedLayout) - { - SLANG_RETURN_ON_FAIL(_createSpecializedLayout(m_specializedLayout.writeRef())); - } - returnRefPtr(outLayout, m_specializedLayout); - return SLANG_OK; -} - -/// Create the layout for this shader object with specialization arguments considered -/// -/// This operation is virtual so that it can be customized by `RootShaderObject`. -/// - -Result ShaderObjectImpl::_createSpecializedLayout(ShaderObjectLayoutImpl** outLayout) -{ - ExtendedShaderObjectType extendedType; - SLANG_RETURN_ON_FAIL(getSpecializedShaderObjectType(&extendedType)); - - auto renderer = getRenderer(); - RefPtr<ShaderObjectLayoutImpl> layout; - SLANG_RETURN_ON_FAIL(renderer->getShaderObjectLayout( - extendedType.slangType, - m_layout->getContainerType(), - (ShaderObjectLayoutBase**)layout.writeRef())); - - returnRefPtrMove(outLayout, layout); - return SLANG_OK; -} - -Result ShaderObjectImpl::setResource(ShaderOffset const& offset, IResourceView* resourceView) -{ - if (offset.bindingRangeIndex < 0) - return SLANG_E_INVALID_ARG; - auto layout = getLayout(); - if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) - return SLANG_E_INVALID_ARG; - - m_version++; - - ID3D12Device* d3dDevice = static_cast<DeviceImpl*>(getDevice())->m_device; - - auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - - if (bindingRange.isRootParameter && resourceView) - { - auto& rootArg = m_rootArguments[bindingRange.baseIndex]; - switch (resourceView->getViewDesc()->type) - { - case IResourceView::Type::AccelerationStructure: - { - auto resourceViewImpl = static_cast<AccelerationStructureImpl*>(resourceView); - rootArg = resourceViewImpl->getDeviceAddress(); - } - break; - case IResourceView::Type::ShaderResource: - case IResourceView::Type::UnorderedAccess: - { - auto resourceViewImpl = static_cast<ResourceViewImpl*>(resourceView); - if (resourceViewImpl->m_resource->isBuffer()) - { - rootArg = static_cast<BufferResourceImpl*>(resourceViewImpl->m_resource.Ptr()) - ->getDeviceAddress(); - } - else - { - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Layer, - "The shader parameter at the specified offset is a root parameter, and " - "therefore can only be a buffer view."); - return SLANG_FAIL; - } - } - break; - } - return SLANG_OK; - } - - if (resourceView == nullptr) - { - // Create null descriptor for the binding. - auto destDescriptor = m_descriptorSet.resourceTable.getCpuHandle( - bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex); - return createNullDescriptor(d3dDevice, destDescriptor, bindingRange); - } - - ResourceViewInternalImpl* internalResourceView = nullptr; - switch (resourceView->getViewDesc()->type) - { -#if SLANG_GFX_HAS_DXR_SUPPORT - case IResourceView::Type::AccelerationStructure: - { - auto asImpl = static_cast<AccelerationStructureImpl*>(resourceView); - // Hold a reference to the resource to prevent its destruction. - m_boundResources[bindingRange.baseIndex + offset.bindingArrayIndex] = asImpl->m_buffer; - internalResourceView = asImpl; - } - break; -#endif - default: - { - auto resourceViewImpl = static_cast<ResourceViewImpl*>(resourceView); - // Hold a reference to the resource to prevent its destruction. - m_boundResources[bindingRange.baseIndex + offset.bindingArrayIndex] = - resourceViewImpl->m_resource; - internalResourceView = resourceViewImpl; - } - break; - } - - auto descriptorSlotIndex = bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex; - if (internalResourceView->m_descriptor.cpuHandle.ptr) - { - d3dDevice->CopyDescriptorsSimple( - 1, - m_descriptorSet.resourceTable.getCpuHandle( - bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), - internalResourceView->m_descriptor.cpuHandle, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - else - { - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Layer, - "IShaderObject::setResource: the resource view cannot be set to this shader parameter. " - "A possible reason is that the view is too large to be supported by D3D12."); - return SLANG_FAIL; - } - return SLANG_OK; -} - -void PipelineStateImpl::init(const GraphicsPipelineStateDesc& inDesc) -{ - PipelineStateDesc pipelineDesc; - pipelineDesc.type = PipelineType::Graphics; - pipelineDesc.graphics = inDesc; - initializeBase(pipelineDesc); -} - -void PipelineStateImpl::init(const ComputePipelineStateDesc& inDesc) -{ - PipelineStateDesc pipelineDesc; - pipelineDesc.type = PipelineType::Compute; - pipelineDesc.compute = inDesc; - initializeBase(pipelineDesc); -} - -Result PipelineStateImpl::getNativeHandle(InteropHandle* outHandle) -{ - SLANG_RETURN_ON_FAIL(ensureAPIPipelineStateCreated()); - outHandle->api = InteropHandleAPI::D3D12; - outHandle->handleValue = reinterpret_cast<uint64_t>(m_pipelineState.get()); - return SLANG_OK; -} - -Result PipelineStateImpl::ensureAPIPipelineStateCreated() -{ - if (m_pipelineState) - return SLANG_OK; - - auto programImpl = static_cast<ShaderProgramImpl*>(m_program.Ptr()); - if (programImpl->m_shaders.getCount() == 0) - { - SLANG_RETURN_ON_FAIL(programImpl->compileShaders()); - } - if (desc.type == PipelineType::Graphics) - { - // Only actually create a D3D12 pipeline state if the pipeline is fully specialized. - auto inputLayoutImpl = (InputLayoutImpl*)desc.graphics.inputLayout; - - // Describe and create the graphics pipeline state object (PSO) - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - - psoDesc.pRootSignature = programImpl->m_rootObjectLayout->m_rootSignature; - - for (auto& shaderBin : programImpl->m_shaders) - { - switch (shaderBin.stage) - { - case SLANG_STAGE_VERTEX: - psoDesc.VS = {shaderBin.code.getBuffer(), SIZE_T(shaderBin.code.getCount())}; - break; - case SLANG_STAGE_FRAGMENT: - psoDesc.PS = {shaderBin.code.getBuffer(), SIZE_T(shaderBin.code.getCount())}; - break; - case SLANG_STAGE_DOMAIN: - psoDesc.DS = {shaderBin.code.getBuffer(), SIZE_T(shaderBin.code.getCount())}; - break; - case SLANG_STAGE_HULL: - psoDesc.HS = {shaderBin.code.getBuffer(), SIZE_T(shaderBin.code.getCount())}; - break; - case SLANG_STAGE_GEOMETRY: - psoDesc.GS = {shaderBin.code.getBuffer(), SIZE_T(shaderBin.code.getCount())}; - break; - default: - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Layer, - "Unsupported shader stage."); - return SLANG_E_NOT_AVAILABLE; - } - } - - if (inputLayoutImpl) - { - psoDesc.InputLayout = { - inputLayoutImpl->m_elements.getBuffer(), - UINT(inputLayoutImpl->m_elements.getCount())}; - } - - psoDesc.PrimitiveTopologyType = D3DUtil::getPrimitiveType(desc.graphics.primitiveType); - - { - auto framebufferLayout = - static_cast<FramebufferLayoutImpl*>(desc.graphics.framebufferLayout); - const int numRenderTargets = int(framebufferLayout->m_renderTargets.getCount()); - - if (framebufferLayout->m_hasDepthStencil) - { - psoDesc.DSVFormat = D3DUtil::getMapFormat(framebufferLayout->m_depthStencil.format); - psoDesc.SampleDesc.Count = framebufferLayout->m_depthStencil.sampleCount; - } - else - { - psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; - if (framebufferLayout->m_renderTargets.getCount()) - { - psoDesc.SampleDesc.Count = framebufferLayout->m_renderTargets[0].sampleCount; - } - } - psoDesc.NumRenderTargets = numRenderTargets; - for (Int i = 0; i < numRenderTargets; i++) - { - psoDesc.RTVFormats[i] = - D3DUtil::getMapFormat(framebufferLayout->m_renderTargets[i].format); - } - - psoDesc.SampleDesc.Quality = 0; - psoDesc.SampleMask = UINT_MAX; - } - - { - auto& rs = psoDesc.RasterizerState; - rs.FillMode = D3DUtil::getFillMode(desc.graphics.rasterizer.fillMode); - rs.CullMode = D3DUtil::getCullMode(desc.graphics.rasterizer.cullMode); - rs.FrontCounterClockwise = - desc.graphics.rasterizer.frontFace == gfx::FrontFaceMode::CounterClockwise ? TRUE - : FALSE; - rs.DepthBias = desc.graphics.rasterizer.depthBias; - rs.DepthBiasClamp = desc.graphics.rasterizer.depthBiasClamp; - rs.SlopeScaledDepthBias = desc.graphics.rasterizer.slopeScaledDepthBias; - rs.DepthClipEnable = desc.graphics.rasterizer.depthClipEnable ? TRUE : FALSE; - rs.MultisampleEnable = desc.graphics.rasterizer.multisampleEnable ? TRUE : FALSE; - rs.AntialiasedLineEnable = - desc.graphics.rasterizer.antialiasedLineEnable ? TRUE : FALSE; - rs.ForcedSampleCount = desc.graphics.rasterizer.forcedSampleCount; - rs.ConservativeRaster = desc.graphics.rasterizer.enableConservativeRasterization - ? D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON - : D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; - } - - { - D3D12_BLEND_DESC& blend = psoDesc.BlendState; - blend.IndependentBlendEnable = FALSE; - blend.AlphaToCoverageEnable = desc.graphics.blend.alphaToCoverageEnable ? TRUE : FALSE; - blend.RenderTarget[0].RenderTargetWriteMask = (uint8_t)RenderTargetWriteMask::EnableAll; - for (GfxIndex i = 0; i < desc.graphics.blend.targetCount; i++) - { - auto& d3dDesc = blend.RenderTarget[i]; - d3dDesc.BlendEnable = desc.graphics.blend.targets[i].enableBlend ? TRUE : FALSE; - d3dDesc.BlendOp = D3DUtil::getBlendOp(desc.graphics.blend.targets[i].color.op); - d3dDesc.BlendOpAlpha = D3DUtil::getBlendOp(desc.graphics.blend.targets[i].alpha.op); - d3dDesc.DestBlend = - D3DUtil::getBlendFactor(desc.graphics.blend.targets[i].color.dstFactor); - d3dDesc.DestBlendAlpha = - D3DUtil::getBlendFactor(desc.graphics.blend.targets[i].alpha.dstFactor); - d3dDesc.LogicOp = D3D12_LOGIC_OP_NOOP; - d3dDesc.LogicOpEnable = FALSE; - d3dDesc.RenderTargetWriteMask = desc.graphics.blend.targets[i].writeMask; - d3dDesc.SrcBlend = - D3DUtil::getBlendFactor(desc.graphics.blend.targets[i].color.srcFactor); - d3dDesc.SrcBlendAlpha = - D3DUtil::getBlendFactor(desc.graphics.blend.targets[i].alpha.srcFactor); - } - for (GfxIndex i = 1; i < desc.graphics.blend.targetCount; i++) - { - if (memcmp( - &desc.graphics.blend.targets[i], - &desc.graphics.blend.targets[0], - sizeof(desc.graphics.blend.targets[0])) != 0) - { - blend.IndependentBlendEnable = TRUE; - break; - } - } - for (uint32_t i = (uint32_t)desc.graphics.blend.targetCount; - i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; - ++i) - { - blend.RenderTarget[i] = blend.RenderTarget[0]; - } - } - - { - auto& ds = psoDesc.DepthStencilState; - - ds.DepthEnable = desc.graphics.depthStencil.depthTestEnable; - ds.DepthWriteMask = desc.graphics.depthStencil.depthWriteEnable - ? D3D12_DEPTH_WRITE_MASK_ALL - : D3D12_DEPTH_WRITE_MASK_ZERO; - ds.DepthFunc = D3DUtil::getComparisonFunc(desc.graphics.depthStencil.depthFunc); - ds.StencilEnable = desc.graphics.depthStencil.stencilEnable; - ds.StencilReadMask = (UINT8)desc.graphics.depthStencil.stencilReadMask; - ds.StencilWriteMask = (UINT8)desc.graphics.depthStencil.stencilWriteMask; - ds.FrontFace = D3DUtil::translateStencilOpDesc(desc.graphics.depthStencil.frontFace); - ds.BackFace = D3DUtil::translateStencilOpDesc(desc.graphics.depthStencil.backFace); - } - - psoDesc.PrimitiveTopologyType = D3DUtil::getPrimitiveType(desc.graphics.primitiveType); - - if (m_device->m_pipelineCreationAPIDispatcher) - { - SLANG_RETURN_ON_FAIL( - m_device->m_pipelineCreationAPIDispatcher->createGraphicsPipelineState( - m_device, - programImpl->linkedProgram.get(), - &psoDesc, - (void**)m_pipelineState.writeRef())); - } - else - { - SLANG_RETURN_ON_FAIL(m_device->m_device->CreateGraphicsPipelineState( - &psoDesc, IID_PPV_ARGS(m_pipelineState.writeRef()))); - } - } - else - { - - // Only actually create a D3D12 pipeline state if the pipeline is fully specialized. - ComPtr<ID3D12PipelineState> pipelineState; - if (!programImpl->isSpecializable()) - { - // Describe and create the compute pipeline state object - D3D12_COMPUTE_PIPELINE_STATE_DESC computeDesc = {}; - computeDesc.pRootSignature = - desc.compute.d3d12RootSignatureOverride - ? static_cast<ID3D12RootSignature*>(desc.compute.d3d12RootSignatureOverride) - : programImpl->m_rootObjectLayout->m_rootSignature; - computeDesc.CS = { - programImpl->m_shaders[0].code.getBuffer(), - SIZE_T(programImpl->m_shaders[0].code.getCount())}; - -#ifdef GFX_NVAPI - if (m_nvapi) - { - // Also fill the extension structure. - // Use the same UAV slot index and register space that are declared in the shader. - - // For simplicities sake we just use u0 - NVAPI_D3D12_PSO_SET_SHADER_EXTENSION_SLOT_DESC extensionDesc; - extensionDesc.baseVersion = NV_PSO_EXTENSION_DESC_VER; - extensionDesc.version = NV_SET_SHADER_EXTENSION_SLOT_DESC_VER; - extensionDesc.uavSlot = 0; - extensionDesc.registerSpace = 0; - - // Put the pointer to the extension into an array - there can be multiple extensions - // enabled at once. - const NVAPI_D3D12_PSO_EXTENSION_DESC* extensions[] = {&extensionDesc}; - - // Now create the PSO. - const NvAPI_Status nvapiStatus = NvAPI_D3D12_CreateComputePipelineState( - m_device->m_device, - &computeDesc, - SLANG_COUNT_OF(extensions), - extensions, - m_pipelineState.writeRef()); - - if (nvapiStatus != NVAPI_OK) - { - return SLANG_FAIL; - } - } - else -#endif - { - if (m_device->m_pipelineCreationAPIDispatcher) - { - SLANG_RETURN_ON_FAIL( - m_device->m_pipelineCreationAPIDispatcher->createComputePipelineState( - m_device, - programImpl->linkedProgram.get(), - &computeDesc, - (void**)m_pipelineState.writeRef())); - } - else - { - SLANG_RETURN_ON_FAIL(m_device->m_device->CreateComputePipelineState( - &computeDesc, IID_PPV_ARGS(m_pipelineState.writeRef()))); - } - } - } - } - - return SLANG_OK; -} - -// Swapchain Implementation - -Result SwapchainImpl::init( - DeviceImpl* renderer, const ISwapchain::Desc& swapchainDesc, WindowHandle window) -{ - m_queue = static_cast<CommandQueueImpl*>(swapchainDesc.queue)->m_d3dQueue; - m_dxgiFactory = renderer->m_deviceInfo.m_dxgiFactory; - SLANG_RETURN_ON_FAIL( - D3DSwapchainBase::init(swapchainDesc, window, DXGI_SWAP_EFFECT_FLIP_DISCARD)); - renderer->m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.writeRef())); - - SLANG_RETURN_ON_FAIL(m_swapChain->QueryInterface(m_swapChain3.writeRef())); - for (GfxIndex i = 0; i < swapchainDesc.imageCount; i++) - { - m_frameEvents.add(CreateEventEx( - nullptr, - false, - CREATE_EVENT_INITIAL_SET | CREATE_EVENT_MANUAL_RESET, - EVENT_ALL_ACCESS)); - } - return SLANG_OK; -} - -Result SwapchainImpl::resize(GfxCount width, GfxCount height) -{ - for (auto evt : m_frameEvents) - SetEvent(evt); - SLANG_RETURN_ON_FAIL(D3DSwapchainBase::resize(width, height)); - return SLANG_OK; -} - -void SwapchainImpl::createSwapchainBufferImages() -{ - m_images.clear(); - - for (GfxIndex i = 0; i < m_desc.imageCount; i++) - { - ComPtr<ID3D12Resource> d3dResource; - m_swapChain->GetBuffer(i, IID_PPV_ARGS(d3dResource.writeRef())); - ITextureResource::Desc imageDesc = {}; - imageDesc.allowedStates = ResourceStateSet( - ResourceState::Present, ResourceState::RenderTarget, ResourceState::CopyDestination); - imageDesc.type = IResource::Type::Texture2D; - imageDesc.arraySize = 0; - imageDesc.format = m_desc.format; - imageDesc.size.width = m_desc.width; - imageDesc.size.height = m_desc.height; - imageDesc.size.depth = 1; - imageDesc.numMipLevels = 1; - imageDesc.defaultState = ResourceState::Present; - RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc); - image->m_resource.setResource(d3dResource.get()); - image->m_defaultState = D3D12_RESOURCE_STATE_PRESENT; - m_images.add(image); - } - for (auto evt : m_frameEvents) - SetEvent(evt); -} - -int SwapchainImpl::acquireNextImage() -{ - auto result = (int)m_swapChain3->GetCurrentBackBufferIndex(); - WaitForSingleObject(m_frameEvents[result], INFINITE); - ResetEvent(m_frameEvents[result]); - return result; -} - -Result SwapchainImpl::present() -{ - m_fence->SetEventOnCompletion( - fenceValue, m_frameEvents[m_swapChain3->GetCurrentBackBufferIndex()]); - SLANG_RETURN_ON_FAIL(D3DSwapchainBase::present()); - fenceValue++; - m_queue->Signal(m_fence, fenceValue); - return SLANG_OK; -} - -bool SwapchainImpl::isOccluded() -{ - return (m_swapChain3->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED); -} - -Result SwapchainImpl::setFullScreenMode(bool mode) -{ - return m_swapChain3->SetFullscreenState(mode, nullptr); -} - -// CommandQueue implementation. - -Result CommandQueueImpl::init(DeviceImpl* device, uint32_t queueIndex) -{ - m_queueIndex = queueIndex; - m_renderer = device; - m_device = device->m_device; - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - SLANG_RETURN_ON_FAIL( - m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_d3dQueue.writeRef()))); - SLANG_RETURN_ON_FAIL( - m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.writeRef()))); - globalWaitHandle = CreateEventEx( - nullptr, nullptr, CREATE_EVENT_INITIAL_SET | CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); - return SLANG_OK; -} - -CommandQueueImpl::~CommandQueueImpl() -{ - waitOnHost(); - CloseHandle(globalWaitHandle); - m_renderer->m_queueIndexAllocator.free((int)m_queueIndex, 1); -} - -void CommandQueueImpl::executeCommandBuffers( - GfxCount count, ICommandBuffer* const* commandBuffers, IFence* fence, uint64_t valueToSignal) -{ - ShortList<ID3D12CommandList*> commandLists; - for (GfxCount i = 0; i < count; i++) - { - auto cmdImpl = static_cast<CommandBufferImpl*>(commandBuffers[i]); - commandLists.add(cmdImpl->m_cmdList); - } - if (count > 0) - { - m_d3dQueue->ExecuteCommandLists((UINT)count, commandLists.getArrayView().getBuffer()); - - m_fenceValue++; - - for (GfxCount i = 0; i < count; i++) - { - if (i > 0 && commandBuffers[i] == commandBuffers[i - 1]) - continue; - auto cmdImpl = static_cast<CommandBufferImpl*>(commandBuffers[i]); - auto transientHeap = cmdImpl->m_transientHeap; - auto& waitInfo = transientHeap->getQueueWaitInfo(m_queueIndex); - waitInfo.waitValue = m_fenceValue; - waitInfo.fence = m_fence; - waitInfo.queue = m_d3dQueue; - } - } - - if (fence) - { - auto fenceImpl = static_cast<FenceImpl*>(fence); - m_d3dQueue->Signal(fenceImpl->m_fence.get(), valueToSignal); - } -} - -void CommandQueueImpl::waitOnHost() -{ - m_fenceValue++; - m_d3dQueue->Signal(m_fence, m_fenceValue); - ResetEvent(globalWaitHandle); - m_fence->SetEventOnCompletion(m_fenceValue, globalWaitHandle); - WaitForSingleObject(globalWaitHandle, INFINITE); -} - -Result CommandQueueImpl::waitForFenceValuesOnDevice( - GfxCount fenceCount, IFence** fences, uint64_t* waitValues) -{ - for (GfxCount i = 0; i < fenceCount; ++i) - { - auto fenceImpl = static_cast<FenceImpl*>(fences[i]); - m_d3dQueue->Wait(fenceImpl->m_fence.get(), waitValues[i]); - } - return SLANG_OK; -} - -const CommandQueueImpl::Desc& CommandQueueImpl::getDesc() { return m_desc; } - -ICommandQueue* CommandQueueImpl::getInterface(const Guid& guid) -{ - if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandQueue) - return static_cast<ICommandQueue*>(this); - return nullptr; -} - -Result CommandQueueImpl::getNativeHandle(InteropHandle* handle) -{ - handle->api = InteropHandleAPI::D3D12; - handle->handleValue = (uint64_t)m_d3dQueue.get(); - return SLANG_OK; -} - -ResourceViewInternalImpl::~ResourceViewInternalImpl() -{ - if (m_descriptor.cpuHandle.ptr) - m_allocator->free(m_descriptor); -} - -Result ResourceViewImpl::getNativeHandle(InteropHandle* outHandle) -{ - outHandle->api = InteropHandleAPI::D3D12CpuDescriptorHandle; - outHandle->handleValue = m_descriptor.cpuHandle.ptr; - return SLANG_OK; -} - -void RenderPassLayoutImpl::init(const IRenderPassLayout::Desc& desc) -{ - SimpleRenderPassLayout::init(desc); - m_framebufferLayout = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout); - m_hasDepthStencil = m_framebufferLayout->m_hasDepthStencil; -} - -ShaderObjectLayoutImpl::SubObjectRangeOffset::SubObjectRangeOffset( - slang::VariableLayoutReflection* varLayout) -{ - if (auto pendingLayout = varLayout->getPendingDataLayout()) - { - pendingOrdinaryData = (uint32_t)pendingLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNIFORM); - } -} - -ShaderObjectLayoutImpl::SubObjectRangeStride::SubObjectRangeStride( - slang::TypeLayoutReflection* typeLayout) -{ - if (auto pendingLayout = typeLayout->getPendingDataTypeLayout()) - { - pendingOrdinaryData = (uint32_t)pendingLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM); - } -} - -bool ShaderObjectLayoutImpl::isBindingRangeRootParameter( - SlangSession* globalSession, - const char* rootParameterAttributeName, - slang::TypeLayoutReflection* typeLayout, - Index bindingRangeIndex) -{ - bool isRootParameter = false; - if (rootParameterAttributeName) - { - if (auto leafVariable = typeLayout->getBindingRangeLeafVariable(bindingRangeIndex)) - { - if (leafVariable->findUserAttributeByName(globalSession, rootParameterAttributeName)) - { - isRootParameter = true; - } - } - } - return isRootParameter; -} - -Result ShaderObjectLayoutImpl::createForElementType( - RendererBase* renderer, - slang::TypeLayoutReflection* elementType, - ShaderObjectLayoutImpl** outLayout) -{ - Builder builder(renderer); - builder.setElementTypeLayout(elementType); - return builder.build(outLayout); -} - -Result ShaderObjectLayoutImpl::init(Builder* builder) -{ - auto renderer = builder->m_renderer; - - initBase(renderer, builder->m_elementTypeLayout); - - m_containerType = builder->m_containerType; - - m_bindingRanges = _Move(builder->m_bindingRanges); - m_subObjectRanges = _Move(builder->m_subObjectRanges); - m_rootParamsInfo = _Move(builder->m_rootParamsInfo); - - m_ownCounts = builder->m_ownCounts; - m_totalCounts = builder->m_totalCounts; - m_subObjectCount = builder->m_subObjectCount; - m_childRootParameterCount = builder->m_childRootParameterCount; - m_totalOrdinaryDataSize = builder->m_totalOrdinaryDataSize; - - return SLANG_OK; -} - -Result ShaderObjectLayoutImpl::Builder::setElementTypeLayout( - slang::TypeLayoutReflection* typeLayout) -{ - typeLayout = _unwrapParameterGroups(typeLayout, m_containerType); - m_elementTypeLayout = typeLayout; - - // If the type contains any ordinary data, then we must reserve a buffer - // descriptor to hold it when binding as a parameter block. - // - m_totalOrdinaryDataSize = (uint32_t)typeLayout->getSize(); - if (m_totalOrdinaryDataSize != 0) - { - m_ownCounts.resource++; - } - - // We will scan over the reflected Slang binding ranges and add them - // to our array. There are two main things we compute along the way: - // - // * For each binding range we compute a `flatIndex` that can be - // used to identify where the values for the given range begin - // in the flattened arrays (e.g., `m_objects`) and descriptor - // tables that hold the state of a shader object. - // - // * We also update the various counters taht keep track of the number - // of sub-objects, resources, samplers, etc. that are being - // consumed. These counters will contribute to figuring out - // the descriptor table(s) that might be needed to represent - // the object. - // - SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); - for (SlangInt r = 0; r < bindingRangeCount; ++r) - { - slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r); - uint32_t count = (uint32_t)typeLayout->getBindingRangeBindingCount(r); - slang::TypeLayoutReflection* slangLeafTypeLayout = - typeLayout->getBindingRangeLeafTypeLayout(r); - BindingRangeInfo bindingRangeInfo = {}; - bindingRangeInfo.bindingType = slangBindingType; - bindingRangeInfo.resourceShape = slangLeafTypeLayout->getResourceShape(); - bindingRangeInfo.count = count; - bindingRangeInfo.isRootParameter = isBindingRangeRootParameter( - m_renderer->slangContext.globalSession, - static_cast<DeviceImpl*>(m_renderer)->m_extendedDesc.rootParameterShaderAttributeName, - typeLayout, - r); - if (bindingRangeInfo.isRootParameter) - { - RootParameterInfo rootInfo = {}; - switch (slangBindingType) - { - case slang::BindingType::RayTracingAccelerationStructure: - rootInfo.type = IResourceView::Type::AccelerationStructure; - break; - case slang::BindingType::RawBuffer: - case slang::BindingType::TypedBuffer: - rootInfo.type = IResourceView::Type::ShaderResource; - break; - case slang::BindingType::MutableRawBuffer: - case slang::BindingType::MutableTypedBuffer: - rootInfo.type = IResourceView::Type::UnorderedAccess; - break; - } - bindingRangeInfo.baseIndex = (uint32_t)m_rootParamsInfo.getCount(); - for (uint32_t i = 0; i < count; i++) - { - m_rootParamsInfo.add(rootInfo); - } - } - else - { - switch (slangBindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - case slang::BindingType::ExistentialValue: - bindingRangeInfo.baseIndex = m_subObjectCount; - bindingRangeInfo.subObjectIndex = m_subObjectCount; - m_subObjectCount += count; - break; - case slang::BindingType::RawBuffer: - case slang::BindingType::MutableRawBuffer: - if (slangLeafTypeLayout->getType()->getElementType() != nullptr) - { - // A structured buffer occupies both a resource slot and - // a sub-object slot. - bindingRangeInfo.subObjectIndex = m_subObjectCount; - m_subObjectCount += count; - } - bindingRangeInfo.baseIndex = m_ownCounts.resource; - m_ownCounts.resource += count; - break; - case slang::BindingType::Sampler: - bindingRangeInfo.baseIndex = m_ownCounts.sampler; - m_ownCounts.sampler += count; - break; - - case slang::BindingType::CombinedTextureSampler: - // TODO: support this case... - break; - - case slang::BindingType::VaryingInput: - case slang::BindingType::VaryingOutput: - break; - - default: - bindingRangeInfo.baseIndex = m_ownCounts.resource; - m_ownCounts.resource += count; - break; - } - } - m_bindingRanges.add(bindingRangeInfo); - } - - // At this point we've computed the number of resources/samplers that - // the type needs to represent its *own* state, and stored those counts - // in `m_ownCounts`. Next we need to consider any resources/samplers - // and root parameters needed to represent the state of the transitive - // sub-objects of this objet, so that we can compute the total size - // of the object when bound to the pipeline. - - m_totalCounts = m_ownCounts; - - SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount(); - for (SlangInt r = 0; r < subObjectRangeCount; ++r) - { - SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r); - auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex); - auto count = (uint32_t)typeLayout->getBindingRangeBindingCount(bindingRangeIndex); - slang::TypeLayoutReflection* slangLeafTypeLayout = - typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); - - // A sub-object range can either represent a sub-object of a known - // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` - // (in which case we can pre-compute a layout to use, based on - // the type `Foo`) *or* it can represent a sub-object of some - // existential type (e.g., `IBar`) in which case we cannot - // know the appropraite type/layout of sub-object to allocate. - // - RefPtr<ShaderObjectLayoutImpl> subObjectLayout; - if (slangBindingType == slang::BindingType::ExistentialValue) - { - if (auto pendingTypeLayout = slangLeafTypeLayout->getPendingDataTypeLayout()) - { - createForElementType(m_renderer, pendingTypeLayout, subObjectLayout.writeRef()); - } - } - else - { - createForElementType( - m_renderer, - slangLeafTypeLayout->getElementTypeLayout(), - subObjectLayout.writeRef()); - } - - SubObjectRangeInfo subObjectRange; - subObjectRange.bindingRangeIndex = bindingRangeIndex; - subObjectRange.layout = subObjectLayout; - - // The Slang reflection API stors offset information for sub-object ranges, - // and we care about *some* of that information: in particular, we need - // the offset of sub-objects in terms of uniform/ordinary data for the - // cases where we need to fill in "pending" data in our ordinary buffer. - // - subObjectRange.offset = SubObjectRangeOffset(typeLayout->getSubObjectRangeOffset(r)); - subObjectRange.stride = SubObjectRangeStride(slangLeafTypeLayout); - - // The remaining offset information is computed based on the counters - // we are generating here, which depend only on the in-memory layout - // decisions being made in our implementation. Remember that the - // `register` and `space` values coming from DXBC/DXIL do *not* - // dictate the in-memory layout we use. - // - // Note: One subtle point here is that the `.rootParam` offset we are computing - // here does *not* include any root parameters that would be allocated - // for the parent object type itself (e.g., for descriptor tables - // used if it were bound as a parameter block). The later logic when - // we actually go to bind things will need to apply those offsets. - // - // Note: An even *more* subtle point is that the `.resource` offset - // being computed here *does* include the resource descriptor allocated - // for holding the ordinary data buffer, if any. The implications of - // this for later offset math is subtle. - // - subObjectRange.offset.rootParam = m_childRootParameterCount; - subObjectRange.offset.resource = m_totalCounts.resource; - subObjectRange.offset.sampler = m_totalCounts.sampler; - - // Along with the offset information, we also need to compute the - // "stride" between consecutive sub-objects in the range. The actual - // size/stride of a single object depends on the type of range we - // are dealing with. - // - BindingOffset objectCounts; - switch (slangBindingType) - { - default: - { - // We only treat buffers of interface types as actual sub-object binding - // range. - auto bindingRangeTypeLayout = - typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); - if (!bindingRangeTypeLayout) - continue; - auto elementType = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex) - ->getElementTypeLayout(); - if (!elementType) - continue; - if (elementType->getKind() != slang::TypeReflection::Kind::Interface) - { - continue; - } - } - break; - - case slang::BindingType::ConstantBuffer: - { - SLANG_ASSERT(subObjectLayout); - - // The resource and sampler descriptors of a nested - // constant buffer will "leak" into those of the - // parent type, and we need to account for them - // whenever we allocate storage. - // - objectCounts.resource = subObjectLayout->getTotalResourceDescriptorCount(); - objectCounts.sampler = subObjectLayout->getTotalSamplerDescriptorCount(); - objectCounts.rootParam = subObjectRange.layout->getChildRootParameterCount(); - } - break; - - case slang::BindingType::ParameterBlock: - { - SLANG_ASSERT(subObjectLayout); - - // In contrast to a constant buffer, a parameter block can hide - // the resource and sampler descriptor allocation it uses (since they - // are allocated into the tables that make up the parameter block. - // - // The only resource usage that leaks into the surrounding context - // is the number of root parameters consumed. - // - objectCounts.rootParam = subObjectRange.layout->getTotalRootTableParameterCount(); - } - break; - - case slang::BindingType::ExistentialValue: - // An unspecialized existential/interface value cannot consume any resources - // as part of the parent object (it needs to fit inside the fixed-size - // represnetation of existential types). - // - // However, if we are statically specializing to a type that doesn't "fit" - // we may need to account for additional information that needs to be - // allocaated. - // - if (subObjectLayout) - { - // The ordinary data for an existential-type value is allocated into - // the same buffer as the parent object, so we only want to consider - // the resource descriptors *other than* the ordinary data buffer. - // - // Otherwise the logic here is identical to the constant buffer case. - // - objectCounts.resource = - subObjectLayout->getTotalResourceDescriptorCountWithoutOrdinaryDataBuffer(); - objectCounts.sampler = subObjectLayout->getTotalSamplerDescriptorCount(); - objectCounts.rootParam = subObjectRange.layout->getChildRootParameterCount(); - - // Note: In the implementation for some other graphics API (e.g., - // Vulkan) there needs to be more work done to handle the fact that - // "pending" data from interface-type sub-objects get allocated to a - // distinct offset after all the "primary" data. We are consciously - // ignoring that issue here, and the physical layout of a shader object - // into the D3D12 binding state may end up interleaving - // resources/samplers for "primary" and "pending" data. - // - // If this choice ever causes issues, we can revisit the approach here. - - // An interface-type range that includes ordinary data can - // increase the size of the ordinary data buffer we need to - // allocate for the parent object. - // - uint32_t ordinaryDataEnd = - subObjectRange.offset.pendingOrdinaryData + - (uint32_t)count * subObjectRange.stride.pendingOrdinaryData; - - if (ordinaryDataEnd > m_totalOrdinaryDataSize) - { - m_totalOrdinaryDataSize = ordinaryDataEnd; - } - } - break; - } - - // Once we've computed the usage for each object in the range, we can - // easily compute the usage for the entire range. - // - auto rangeResourceCount = count * objectCounts.resource; - auto rangeSamplerCount = count * objectCounts.sampler; - auto rangeRootParamCount = count * objectCounts.rootParam; - - m_totalCounts.resource += rangeResourceCount; - m_totalCounts.sampler += rangeSamplerCount; - m_childRootParameterCount += rangeRootParamCount; - - m_subObjectRanges.add(subObjectRange); - } - - // Once we have added up the resource usage from all the sub-objects - // we can look at the total number of resources and samplers that - // need to be bound as part of this objects descriptor tables and - // that will allow us to decide whether we need to allocate a root - // parameter for a resource table or not, ans similarly for a - // sampler table. - // - if (m_totalCounts.resource) - m_ownCounts.rootParam++; - if (m_totalCounts.sampler) - m_ownCounts.rootParam++; - - m_totalCounts.rootParam = m_ownCounts.rootParam + m_childRootParameterCount; - - return SLANG_OK; -} - -Result ShaderObjectLayoutImpl::Builder::build(ShaderObjectLayoutImpl** outLayout) -{ - auto layout = RefPtr<ShaderObjectLayoutImpl>(new ShaderObjectLayoutImpl()); - SLANG_RETURN_ON_FAIL(layout->init(this)); - - returnRefPtrMove(outLayout, layout); - return SLANG_OK; -} - -Result RootShaderObjectLayoutImpl::Builder::build(RootShaderObjectLayoutImpl** outLayout) -{ - RefPtr<RootShaderObjectLayoutImpl> layout = new RootShaderObjectLayoutImpl(); - SLANG_RETURN_ON_FAIL(layout->init(this)); - - returnRefPtrMove(outLayout, layout); - return SLANG_OK; -} - -void RootShaderObjectLayoutImpl::Builder::addGlobalParams( - slang::VariableLayoutReflection* globalsLayout) -{ - setElementTypeLayout(globalsLayout->getTypeLayout()); -} - -void RootShaderObjectLayoutImpl::Builder::addEntryPoint( - SlangStage stage, ShaderObjectLayoutImpl* entryPointLayout) -{ - EntryPointInfo info; - info.layout = entryPointLayout; - - info.offset.resource = m_totalCounts.resource; - info.offset.sampler = m_totalCounts.sampler; - info.offset.rootParam = m_childRootParameterCount; - - m_totalCounts.resource += entryPointLayout->getTotalResourceDescriptorCount(); - m_totalCounts.sampler += entryPointLayout->getTotalSamplerDescriptorCount(); - - // TODO(tfoley): Check this to make sure it is reasonable... - m_childRootParameterCount += entryPointLayout->getChildRootParameterCount(); - - m_entryPoints.add(info); -} - -Result RootShaderObjectLayoutImpl::RootSignatureDescBuilder::translateDescriptorRangeType( - slang::BindingType c, D3D12_DESCRIPTOR_RANGE_TYPE* outType) -{ - switch (c) - { - case slang::BindingType::ConstantBuffer: - *outType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - return SLANG_OK; - case slang::BindingType::RawBuffer: - case slang::BindingType::Texture: - case slang::BindingType::TypedBuffer: - case slang::BindingType::RayTracingAccelerationStructure: - *outType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - return SLANG_OK; - case slang::BindingType::MutableRawBuffer: - case slang::BindingType::MutableTexture: - case slang::BindingType::MutableTypedBuffer: - *outType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - return SLANG_OK; - case slang::BindingType::Sampler: - *outType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - return SLANG_OK; - default: - return SLANG_FAIL; - } -} - -/// Add a new descriptor set to the layout being computed. -/// -/// Note that a "descriptor set" in the layout may amount to -/// zero, one, or two different descriptor *tables* in the -/// final D3D12 root signature. Each descriptor set may -/// contain zero or more view ranges (CBV/SRV/UAV) and zero -/// or more sampler ranges. It maps to a view descriptor table -/// if the number of view ranges is non-zero and to a sampler -/// descriptor table if the number of sampler ranges is non-zero. -/// - -uint32_t RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addDescriptorSet() -{ - auto result = (uint32_t)m_descriptorSets.getCount(); - m_descriptorSets.add(DescriptorSetLayout{}); - return result; -} - -Result RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addDescriptorRange( - Index physicalDescriptorSetIndex, - D3D12_DESCRIPTOR_RANGE_TYPE rangeType, - UINT registerIndex, - UINT spaceIndex, - UINT count, - bool isRootParameter) -{ - if (isRootParameter) - { - D3D12_ROOT_PARAMETER rootParam = {}; - switch (rangeType) - { - case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: - rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; - break; - case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: - rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; - break; - default: - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Layer, - "A shader parameter marked as root parameter is neither SRV nor UAV."); - return SLANG_FAIL; - } - rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - rootParam.Descriptor.RegisterSpace = spaceIndex; - rootParam.Descriptor.ShaderRegister = registerIndex; - m_rootParameters.add(rootParam); - return SLANG_OK; - } - - auto& descriptorSet = m_descriptorSets[physicalDescriptorSetIndex]; - - D3D12_DESCRIPTOR_RANGE range = {}; - range.RangeType = rangeType; - range.NumDescriptors = count; - range.BaseShaderRegister = registerIndex; - range.RegisterSpace = spaceIndex; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) - { - descriptorSet.m_samplerRanges.add(range); - descriptorSet.m_samplerCount += range.NumDescriptors; - } - else - { - descriptorSet.m_resourceRanges.add(range); - descriptorSet.m_resourceCount += range.NumDescriptors; - } - - return SLANG_OK; -} - -/// Add one descriptor range as specified in Slang reflection information to the layout. -/// -/// The layout information is taken from `typeLayout` for the descriptor -/// range with the given `descriptorRangeIndex` within the logical -/// descriptor set (reflected by Slang) with the given `logicalDescriptorSetIndex`. -/// -/// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of -/// the descriptor set that the range should be added to. -/// -/// The `offset` encodes information about space and/or register offsets that -/// should be applied to descrptor ranges. -/// -/// This operation can fail if the given descriptor range encodes a range that -/// doesn't map to anything directly supported by D3D12. Higher-level routines -/// will often want to ignore such failures. -/// - -Result RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addDescriptorRange( - slang::TypeLayoutReflection* typeLayout, - Index physicalDescriptorSetIndex, - BindingRegisterOffset const& containerOffset, - BindingRegisterOffset const& elementOffset, - Index logicalDescriptorSetIndex, - Index descriptorRangeIndex, - bool isRootParameter) -{ - auto bindingType = typeLayout->getDescriptorSetDescriptorRangeType( - logicalDescriptorSetIndex, descriptorRangeIndex); - auto count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount( - logicalDescriptorSetIndex, descriptorRangeIndex); - auto index = typeLayout->getDescriptorSetDescriptorRangeIndexOffset( - logicalDescriptorSetIndex, descriptorRangeIndex); - auto space = typeLayout->getDescriptorSetSpaceOffset(logicalDescriptorSetIndex); - - D3D12_DESCRIPTOR_RANGE_TYPE rangeType; - SLANG_RETURN_ON_FAIL(translateDescriptorRangeType(bindingType, &rangeType)); - - return addDescriptorRange( - physicalDescriptorSetIndex, - rangeType, - (UINT)index + elementOffset[rangeType], - (UINT)space + containerOffset.spaceOffset, - (UINT)count, - isRootParameter); -} - -/// Add one binding range to the computed layout. -/// -/// The layout information is taken from `typeLayout` for the binding -/// range with the given `bindingRangeIndex`. -/// -/// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of -/// the descriptor set that the range should be added to. -/// -/// The `offset` encodes information about space and/or register offsets that -/// should be applied to descrptor ranges. -/// -/// Note that a single binding range may encompass zero or more descriptor ranges. -/// - -void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addBindingRange( - slang::TypeLayoutReflection* typeLayout, - Index physicalDescriptorSetIndex, - BindingRegisterOffset const& containerOffset, - BindingRegisterOffset const& elementOffset, - Index bindingRangeIndex) -{ - auto logicalDescriptorSetIndex = - typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex); - auto firstDescriptorRangeIndex = - typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex); - Index descriptorRangeCount = typeLayout->getBindingRangeDescriptorRangeCount(bindingRangeIndex); - bool isRootParameter = isBindingRangeRootParameter( - m_device->slangContext.globalSession, - m_device->m_extendedDesc.rootParameterShaderAttributeName, - typeLayout, - bindingRangeIndex); - for (Index i = 0; i < descriptorRangeCount; ++i) - { - auto descriptorRangeIndex = firstDescriptorRangeIndex + i; - - // Note: we ignore the `Result` returned by `addDescriptorRange()` because we - // want to silently skip any ranges that represent kinds of bindings that - // don't actually exist in D3D12. - // - addDescriptorRange( - typeLayout, - physicalDescriptorSetIndex, - containerOffset, - elementOffset, - logicalDescriptorSetIndex, - descriptorRangeIndex, - isRootParameter); - } -} - -void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( - slang::VariableLayoutReflection* varLayout, Index physicalDescriptorSetIndex) -{ - BindingRegisterOffsetPair offset(varLayout); - addAsValue(varLayout->getTypeLayout(), physicalDescriptorSetIndex, offset, offset); -} - -/// Add binding ranges and parameter blocks to the root signature. -/// -/// The layout information is taken from `typeLayout` which should -/// be a layout for either a program or an entry point. -/// -/// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of -/// the descriptor set that binding ranges not belonging to nested -/// parameter blocks should be added to. -/// -/// The `offset` encodes information about space and/or register offsets that -/// should be applied to descrptor ranges. -/// - -void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsConstantBuffer( - slang::TypeLayoutReflection* typeLayout, - Index physicalDescriptorSetIndex, - BindingRegisterOffsetPair const& containerOffset, - BindingRegisterOffsetPair const& elementOffset) -{ - if (typeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0) - { - auto descriptorRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - auto& offsetForRangeType = containerOffset.primary.offsetForRangeType[descriptorRangeType]; - addDescriptorRange( - physicalDescriptorSetIndex, - descriptorRangeType, - offsetForRangeType, - containerOffset.primary.spaceOffset, - 1, - false); - } - - addAsValue(typeLayout, physicalDescriptorSetIndex, containerOffset, elementOffset); -} - -void RootShaderObjectLayoutImpl::RootSignatureDescBuilder::addAsValue( - slang::TypeLayoutReflection* typeLayout, - Index physicalDescriptorSetIndex, - BindingRegisterOffsetPair const& containerOffset, - BindingRegisterOffsetPair const& elementOffset) -{ - // Our first task is to add the binding ranges for stuff that is - // directly contained in `typeLayout` rather than via sub-objects. - // - // Our goal is to have the descriptors for directly-contained views/samplers - // always be contiguous in CPU and GPU memory, so that we can write - // to them easily with a single operaiton. - // - Index bindingRangeCount = typeLayout->getBindingRangeCount(); - for (Index bindingRangeIndex = 0; bindingRangeIndex < bindingRangeCount; bindingRangeIndex++) - { - // We will look at the type of each binding range and intentionally - // skip those that represent sub-objects. - // - auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex); - switch (bindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - case slang::BindingType::ExistentialValue: - continue; - - default: - break; - } - - // For binding ranges that don't represent sub-objects, we will add - // all of the descriptor ranges they encompass to the root signature. - // - addBindingRange( - typeLayout, - physicalDescriptorSetIndex, - containerOffset.primary, - elementOffset.primary, - bindingRangeIndex); - } - - // Next we need to recursively include everything bound via sub-objects - Index subObjectRangeCount = typeLayout->getSubObjectRangeCount(); - for (Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectRangeCount; - subObjectRangeIndex++) - { - auto bindingRangeIndex = - typeLayout->getSubObjectRangeBindingRangeIndex(subObjectRangeIndex); - auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex); - - auto subObjectTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); - - BindingRegisterOffsetPair subObjectRangeContainerOffset = containerOffset; - subObjectRangeContainerOffset += - BindingRegisterOffsetPair(typeLayout->getSubObjectRangeOffset(subObjectRangeIndex)); - BindingRegisterOffsetPair subObjectRangeElementOffset = elementOffset; - subObjectRangeElementOffset += - BindingRegisterOffsetPair(typeLayout->getSubObjectRangeOffset(subObjectRangeIndex)); - - switch (bindingType) - { - case slang::BindingType::ConstantBuffer: - { - auto containerVarLayout = subObjectTypeLayout->getContainerVarLayout(); - SLANG_ASSERT(containerVarLayout); - - auto elementVarLayout = subObjectTypeLayout->getElementVarLayout(); - SLANG_ASSERT(elementVarLayout); - - auto elementTypeLayout = elementVarLayout->getTypeLayout(); - SLANG_ASSERT(elementTypeLayout); - - BindingRegisterOffsetPair containerOffset = subObjectRangeContainerOffset; - containerOffset += BindingRegisterOffsetPair(containerVarLayout); - - BindingRegisterOffsetPair elementOffset = subObjectRangeElementOffset; - elementOffset += BindingRegisterOffsetPair(elementVarLayout); - - addAsConstantBuffer( - elementTypeLayout, physicalDescriptorSetIndex, containerOffset, elementOffset); - } - break; - - case slang::BindingType::ParameterBlock: - { - auto containerVarLayout = subObjectTypeLayout->getContainerVarLayout(); - SLANG_ASSERT(containerVarLayout); - - auto elementVarLayout = subObjectTypeLayout->getElementVarLayout(); - SLANG_ASSERT(elementVarLayout); - - auto elementTypeLayout = elementVarLayout->getTypeLayout(); - SLANG_ASSERT(elementTypeLayout); - - BindingRegisterOffsetPair subDescriptorSetOffset; - subDescriptorSetOffset.primary.spaceOffset = - subObjectRangeElementOffset.primary.spaceOffset; - subDescriptorSetOffset.pending.spaceOffset = - subObjectRangeElementOffset.pending.spaceOffset; - - auto subPhysicalDescriptorSetIndex = addDescriptorSet(); - - BindingRegisterOffsetPair containerOffset = subDescriptorSetOffset; - containerOffset += BindingRegisterOffsetPair(containerVarLayout); - - BindingRegisterOffsetPair elementOffset = subDescriptorSetOffset; - elementOffset += BindingRegisterOffsetPair(elementVarLayout); - - addAsConstantBuffer( - elementTypeLayout, - subPhysicalDescriptorSetIndex, - containerOffset, - elementOffset); - } - break; - - case slang::BindingType::ExistentialValue: - { - // Any nested binding ranges in the sub-object will "leak" into the - // binding ranges for the surrounding context. - // - auto specializedTypeLayout = subObjectTypeLayout->getPendingDataTypeLayout(); - if (specializedTypeLayout) - { - BindingRegisterOffsetPair pendingOffset; - pendingOffset.primary = subObjectRangeElementOffset.pending; - - addAsValue( - specializedTypeLayout, - physicalDescriptorSetIndex, - pendingOffset, - pendingOffset); - } - } - break; - } - } -} - -D3D12_ROOT_SIGNATURE_DESC& RootShaderObjectLayoutImpl::RootSignatureDescBuilder::build() -{ - for (Index i = 0; i < m_descriptorSets.getCount(); i++) - { - auto& descriptorSet = m_descriptorSets[i]; - if (descriptorSet.m_resourceRanges.getCount()) - { - D3D12_ROOT_PARAMETER rootParam = {}; - rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - rootParam.DescriptorTable.NumDescriptorRanges = - (UINT)descriptorSet.m_resourceRanges.getCount(); - rootParam.DescriptorTable.pDescriptorRanges = - descriptorSet.m_resourceRanges.getBuffer(); - m_rootParameters.add(rootParam); - } - if (descriptorSet.m_samplerRanges.getCount()) - { - D3D12_ROOT_PARAMETER rootParam = {}; - rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - rootParam.DescriptorTable.NumDescriptorRanges = - (UINT)descriptorSet.m_samplerRanges.getCount(); - rootParam.DescriptorTable.pDescriptorRanges = descriptorSet.m_samplerRanges.getBuffer(); - m_rootParameters.add(rootParam); - } - } - - m_rootSignatureDesc.NumParameters = UINT(m_rootParameters.getCount()); - m_rootSignatureDesc.pParameters = m_rootParameters.getBuffer(); - - // TODO: static samplers should be reasonably easy to support... - m_rootSignatureDesc.NumStaticSamplers = 0; - m_rootSignatureDesc.pStaticSamplers = nullptr; - - // TODO: only set this flag if needed (requires creating root - // signature at same time as pipeline state...). - // - m_rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - - return m_rootSignatureDesc; -} - -Result RootShaderObjectLayoutImpl::createRootSignatureFromSlang( - DeviceImpl* device, - RootShaderObjectLayoutImpl* rootLayout, - slang::IComponentType* program, - ID3D12RootSignature** outRootSignature, - ID3DBlob** outError) -{ - // We are going to build up the root signature by adding - // binding/descritpor ranges and nested parameter blocks - // based on the computed layout information for `program`. - // - RootSignatureDescBuilder builder(device); - auto layout = program->getLayout(); - - // The layout information computed by Slang breaks up shader - // parameters into what we can think of as "logical" descriptor - // sets based on whether or not parameters have the same `space`. - // - // We want to basically ignore that decomposition and generate a - // single descriptor set to hold all top-level parameters, and only - // generate distinct descriptor sets when the shader has opted in - // via explicit parameter blocks. - // - // To achieve this goal, we will manually allocate a default descriptor - // set for root parameters in our signature, and then recursively - // add all the binding/descriptor ranges implied by the global-scope - // parameters. - // - auto rootDescriptorSetIndex = builder.addDescriptorSet(); - builder.addAsValue(layout->getGlobalParamsVarLayout(), rootDescriptorSetIndex); - - for (SlangUInt i = 0; i < layout->getEntryPointCount(); i++) - { - // Entry-point parameters should also be added to the default root - // descriptor set. - // - // We add the parameters using the "variable layout" for the entry point - // and not just its type layout, to ensure that any offset information is - // applied correctly to the `register` and `space` information for entry-point - // parameters. - // - // Note: When we start to support DXR we will need to handle entry-point parameters - // differently because they will need to map to local root signatures rather than - // being included in the global root signature as is being done here. - // - auto entryPoint = layout->getEntryPointByIndex(i); - builder.addAsValue(entryPoint->getVarLayout(), rootDescriptorSetIndex); - } - - auto& rootSignatureDesc = builder.build(); - - ComPtr<ID3DBlob> signature; - ComPtr<ID3DBlob> error; - if (SLANG_FAILED(device->m_D3D12SerializeRootSignature( - &rootSignatureDesc, - D3D_ROOT_SIGNATURE_VERSION_1, - signature.writeRef(), - error.writeRef()))) - { - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Layer, - "error: D3D12SerializeRootSignature failed"); - if (error) - { - getDebugCallback()->handleMessage( - DebugMessageType::Error, - DebugMessageSource::Driver, - (const char*)error->GetBufferPointer()); - if (outError) - returnComPtr(outError, error); - } - return SLANG_FAIL; - } - - SLANG_RETURN_ON_FAIL(device->m_device->CreateRootSignature( - 0, - signature->GetBufferPointer(), - signature->GetBufferSize(), - IID_PPV_ARGS(outRootSignature))); - return SLANG_OK; -} - -Result RootShaderObjectLayoutImpl::create( - DeviceImpl* device, - slang::IComponentType* program, - slang::ProgramLayout* programLayout, - RootShaderObjectLayoutImpl** outLayout, - ID3DBlob** outError) -{ - RootShaderObjectLayoutImpl::Builder builder(device, program, programLayout); - builder.addGlobalParams(programLayout->getGlobalParamsVarLayout()); - - SlangInt entryPointCount = programLayout->getEntryPointCount(); - for (SlangInt e = 0; e < entryPointCount; ++e) - { - auto slangEntryPoint = programLayout->getEntryPointByIndex(e); - RefPtr<ShaderObjectLayoutImpl> entryPointLayout; - SLANG_RETURN_ON_FAIL(ShaderObjectLayoutImpl::createForElementType( - device, slangEntryPoint->getTypeLayout(), entryPointLayout.writeRef())); - builder.addEntryPoint(slangEntryPoint->getStage(), entryPointLayout); - } - - RefPtr<RootShaderObjectLayoutImpl> layout; - SLANG_RETURN_ON_FAIL(builder.build(layout.writeRef())); - - if (program->getSpecializationParamCount() == 0) - { - // For root object, we would like know the union of all binding slots - // including all sub-objects in the shader-object hierarchy, so at - // parameter binding time we can easily know how many GPU descriptor tables - // to create without walking through the shader-object hierarchy again. - // We build out this array along with root signature construction and store - // it in `m_gpuDescriptorSetInfos`. - SLANG_RETURN_ON_FAIL(createRootSignatureFromSlang( - device, layout, program, layout->m_rootSignature.writeRef(), outError)); - } - - *outLayout = layout.detach(); - - return SLANG_OK; -} - -Result RootShaderObjectLayoutImpl::init(Builder* builder) -{ - auto renderer = builder->m_renderer; - - SLANG_RETURN_ON_FAIL(Super::init(builder)); - - m_program = builder->m_program; - m_programLayout = builder->m_programLayout; - m_entryPoints = builder->m_entryPoints; - return SLANG_OK; -} - -Result ShaderProgramImpl::createShaderModule( - slang::EntryPointReflection* entryPointInfo, ComPtr<ISlangBlob> kernelCode) -{ - ShaderBinary shaderBin; - shaderBin.stage = entryPointInfo->getStage(); - shaderBin.entryPointInfo = entryPointInfo; - shaderBin.code.addRange( - reinterpret_cast<const uint8_t*>(kernelCode->getBufferPointer()), - (Index)kernelCode->getBufferSize()); - m_shaders.add(_Move(shaderBin)); - return SLANG_OK; -} - -Result ShaderObjectImpl::create( - DeviceImpl* device, ShaderObjectLayoutImpl* layout, ShaderObjectImpl** outShaderObject) -{ - auto object = RefPtr<ShaderObjectImpl>(new ShaderObjectImpl()); - SLANG_RETURN_ON_FAIL( - object->init(device, layout, device->m_cpuViewHeap.Ptr(), device->m_cpuSamplerHeap.Ptr())); - returnRefPtrMove(outShaderObject, object); - return SLANG_OK; -} - -ShaderObjectImpl::~ShaderObjectImpl() { m_descriptorSet.freeIfSupported(); } - -RootShaderObjectLayoutImpl* RootShaderObjectImpl::getLayout() -{ - return static_cast<RootShaderObjectLayoutImpl*>(m_layout.Ptr()); -} - -GfxCount RootShaderObjectImpl::getEntryPointCount() { return (GfxCount)m_entryPoints.getCount(); } - -SlangResult RootShaderObjectImpl::getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) -{ - returnComPtr(outEntryPoint, m_entryPoints[index]); - return SLANG_OK; -} - -Result RootShaderObjectImpl::collectSpecializationArgs(ExtendedShaderObjectTypeList& args) -{ - SLANG_RETURN_ON_FAIL(ShaderObjectImpl::collectSpecializationArgs(args)); - for (auto& entryPoint : m_entryPoints) - { - SLANG_RETURN_ON_FAIL(entryPoint->collectSpecializationArgs(args)); - } - return SLANG_OK; -} - -Result RootShaderObjectImpl::_createSpecializedLayout(ShaderObjectLayoutImpl** outLayout) -{ - ExtendedShaderObjectTypeList specializationArgs; - SLANG_RETURN_ON_FAIL(collectSpecializationArgs(specializationArgs)); - - // Note: There is an important policy decision being made here that we need - // to approach carefully. - // - // We are doing two different things that affect the layout of a program: - // - // 1. We are *composing* one or more pieces of code (notably the shared global/module - // stuff and the per-entry-point stuff). - // - // 2. We are *specializing* code that includes generic/existential parameters - // to concrete types/values. - // - // We need to decide the relative *order* of these two steps, because of how it impacts - // layout. The layout for `specialize(compose(A,B), X, Y)` is potentially different - // form that of `compose(specialize(A,X), speciealize(B,Y))`, even when both are - // semantically equivalent programs. - // - // Right now we are using the first option: we are first generating a full composition - // of all the code we plan to use (global scope plus all entry points), and then - // specializing it to the concatenated specialization argumenst for all of that. - // - // In some cases, though, this model isn't appropriate. For example, when dealing with - // ray-tracing shaders and local root signatures, we really want the parameters of each - // entry point (actually, each entry-point *group*) to be allocated distinct storage, - // which really means we want to compute something like: - // - // SpecializedGlobals = specialize(compose(ModuleA, ModuleB, ...), X, Y, ...) - // - // SpecializedEP1 = compose(SpecializedGlobals, specialize(EntryPoint1, T, U, ...)) - // SpecializedEP2 = compose(SpecializedGlobals, specialize(EntryPoint2, A, B, ...)) - // - // Note how in this case all entry points agree on the layout for the shared/common - // parmaeters, but their layouts are also independent of one another. - // - // Furthermore, in this example, loading another entry point into the system would not - // rquire re-computing the layouts (or generated kernel code) for any of the entry - // points that had already been loaded (in contrast to a compose-then-specialize - // approach). - // - ComPtr<slang::IComponentType> specializedComponentType; - ComPtr<slang::IBlob> diagnosticBlob; - auto result = getLayout()->getSlangProgram()->specialize( - specializationArgs.components.getArrayView().getBuffer(), - specializationArgs.getCount(), - specializedComponentType.writeRef(), - diagnosticBlob.writeRef()); - - if (diagnosticBlob && diagnosticBlob->getBufferSize()) - { - getDebugCallback()->handleMessage( - SLANG_FAILED(result) ? DebugMessageType::Error : DebugMessageType::Info, - DebugMessageSource::Layer, - (const char*)diagnosticBlob->getBufferPointer()); - } - - if (SLANG_FAILED(result)) - return result; - - ComPtr<ID3DBlob> d3dDiagnosticBlob; - auto slangSpecializedLayout = specializedComponentType->getLayout(); - RefPtr<RootShaderObjectLayoutImpl> specializedLayout; - auto rootLayoutResult = RootShaderObjectLayoutImpl::create( - static_cast<DeviceImpl*>(getRenderer()), - specializedComponentType, - slangSpecializedLayout, - specializedLayout.writeRef(), - d3dDiagnosticBlob.writeRef()); - - if (SLANG_FAILED(rootLayoutResult)) - { - return rootLayoutResult; - } - - // Note: Computing the layout for the specialized program will have also computed - // the layouts for the entry points, and we really need to attach that information - // to them so that they don't go and try to compute their own specializations. - // - // TODO: Well, if we move to the specialization model described above then maybe - // we *will* want entry points to do their own specialization work... - // - auto entryPointCount = m_entryPoints.getCount(); - for (Index i = 0; i < entryPointCount; ++i) - { - auto entryPointInfo = specializedLayout->getEntryPoint(i); - auto entryPointVars = m_entryPoints[i]; - - entryPointVars->m_specializedLayout = entryPointInfo.layout; - } - - returnRefPtrMove(outLayout, specializedLayout); - return SLANG_OK; -} - -Result RootShaderObjectImpl::copyFrom(IShaderObject* object, ITransientResourceHeap* transientHeap) -{ - if (auto srcObj = dynamic_cast<MutableRootShaderObjectImpl*>(object)) - { - *this = *srcObj; - return SLANG_OK; - } - return SLANG_FAIL; -} - -Result RootShaderObjectImpl::bindAsRoot( - BindingContext* context, RootShaderObjectLayoutImpl* specializedLayout) -{ - // Pull updates from sub-objects when this is a mutable root shader object. - updateSubObjectsRecursive(); - - // A root shader object always binds as if it were a parameter block, - // insofar as it needs to allocate a descriptor set to hold the bindings - // for its own state and any sub-objects. - // - // Note: We do not direclty use `bindAsParameterBlock` here because we also - // need to bind the entry points into the same descriptor set that is - // being used for the root object. - - BindingOffset rootOffset; - - // Bind all root parameters first. - Super::bindRootArguments(context, rootOffset.rootParam); - - DescriptorSet descriptorSet; - SLANG_RETURN_ON_FAIL(prepareToBindAsParameterBlock( - context, /* inout */ rootOffset, specializedLayout, descriptorSet)); - - SLANG_RETURN_ON_FAIL( - Super::bindAsConstantBuffer(context, descriptorSet, rootOffset, specializedLayout)); - - auto entryPointCount = m_entryPoints.getCount(); - for (Index i = 0; i < entryPointCount; ++i) - { - auto entryPoint = m_entryPoints[i]; - auto& entryPointInfo = specializedLayout->getEntryPoint(i); - - auto entryPointOffset = rootOffset; - entryPointOffset += entryPointInfo.offset; - - entryPoint->updateSubObjectsRecursive(); - - SLANG_RETURN_ON_FAIL(entryPoint->bindAsConstantBuffer( - context, descriptorSet, entryPointOffset, entryPointInfo.layout)); - } - - return SLANG_OK; -} - -Result RootShaderObjectImpl::resetImpl( - DeviceImpl* device, - RootShaderObjectLayoutImpl* layout, - DescriptorHeapReference viewHeap, - DescriptorHeapReference samplerHeap, - bool isMutable) -{ - SLANG_RETURN_ON_FAIL(Super::init(device, layout, viewHeap, samplerHeap)); - m_isMutable = isMutable; - m_specializedLayout = nullptr; - m_entryPoints.clear(); - for (auto entryPointInfo : layout->getEntryPoints()) - { - RefPtr<ShaderObjectImpl> entryPoint; - SLANG_RETURN_ON_FAIL( - ShaderObjectImpl::create(device, entryPointInfo.layout, entryPoint.writeRef())); - entryPoint->m_isMutable = isMutable; - m_entryPoints.add(entryPoint); - } - return SLANG_OK; -} - -Result RootShaderObjectImpl::reset( - DeviceImpl* device, RootShaderObjectLayoutImpl* layout, TransientResourceHeapImpl* heap) -{ - return resetImpl( - device, layout, &heap->m_stagingCpuViewHeap, &heap->m_stagingCpuSamplerHeap, false); -} - -RefPtr<BufferResource> ShaderTableImpl::createDeviceBuffer( - PipelineStateBase* pipeline, - TransientResourceHeapBase* transientHeap, - IResourceCommandEncoder* encoder) -{ - uint32_t raygenTableSize = m_rayGenShaderCount * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - uint32_t missTableSize = m_missShaderCount * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - uint32_t hitgroupTableSize = m_hitGroupCount * D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - m_rayGenTableOffset = 0; - m_missTableOffset = (uint32_t)D3DUtil::calcAligned( - raygenTableSize, D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT); - m_hitGroupTableOffset = (uint32_t)D3DUtil::calcAligned( - m_missTableOffset + missTableSize, D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT); - uint32_t tableSize = m_hitGroupTableOffset + hitgroupTableSize; - - auto pipelineImpl = static_cast<RayTracingPipelineStateImpl*>(pipeline); - ComPtr<IBufferResource> bufferResource; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.memoryType = gfx::MemoryType::DeviceLocal; - bufferDesc.defaultState = ResourceState::General; - bufferDesc.type = IResource::Type::Buffer; - bufferDesc.sizeInBytes = tableSize; - m_device->createBufferResource(bufferDesc, nullptr, bufferResource.writeRef()); - - ComPtr<ID3D12StateObjectProperties> stateObjectProperties; - pipelineImpl->m_stateObject->QueryInterface(stateObjectProperties.writeRef()); - - TransientResourceHeapImpl* transientHeapImpl = - static_cast<TransientResourceHeapImpl*>(transientHeap); - - IBufferResource* stagingBuffer = nullptr; - Offset stagingBufferOffset = 0; - transientHeapImpl->allocateStagingBuffer( - tableSize, stagingBuffer, stagingBufferOffset, MemoryType::Upload); - - assert(stagingBuffer); - void* stagingPtr = nullptr; - stagingBuffer->map(nullptr, &stagingPtr); - - auto copyShaderIdInto = [&](void* dest, String& name, const ShaderRecordOverwrite& overwrite) - { - if (name.getLength()) - { - void* shaderId = stateObjectProperties->GetShaderIdentifier(name.toWString().begin()); - memcpy(dest, shaderId, D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); - } - else - { - memset(dest, 0, D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); - } - if (overwrite.size) - { - memcpy((uint8_t*)dest + overwrite.offset, overwrite.data, overwrite.size); - } - }; - - uint8_t* stagingBufferPtr = (uint8_t*)stagingPtr + stagingBufferOffset; - for (uint32_t i = 0; i < m_rayGenShaderCount; i++) - { - copyShaderIdInto( - stagingBufferPtr + m_rayGenTableOffset + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES * i, - m_shaderGroupNames[i], - m_recordOverwrites[i]); - } - for (uint32_t i = 0; i < m_missShaderCount; i++) - { - copyShaderIdInto( - stagingBufferPtr + m_missTableOffset + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES * i, - m_shaderGroupNames[m_rayGenShaderCount + i], - m_recordOverwrites[m_rayGenShaderCount + i]); - } - for (uint32_t i = 0; i < m_hitGroupCount; i++) - { - copyShaderIdInto( - stagingBufferPtr + m_hitGroupTableOffset + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES * i, - m_shaderGroupNames[m_rayGenShaderCount + m_missShaderCount + i], - m_recordOverwrites[m_rayGenShaderCount + m_missShaderCount + i]); - } - - stagingBuffer->unmap(nullptr); - encoder->copyBuffer(bufferResource, 0, stagingBuffer, stagingBufferOffset, tableSize); - encoder->bufferBarrier( - 1, - bufferResource.readRef(), - gfx::ResourceState::CopyDestination, - gfx::ResourceState::ShaderResource); - RefPtr<BufferResource> resultPtr = static_cast<BufferResource*>(bufferResource.get()); - return _Move(resultPtr); -} - -// There are a pair of cyclic references between a `TransientResourceHeap` and -// a `CommandBuffer` created from the heap. We need to break the cycle upon -// the public reference count of a command buffer dropping to 0. - -ICommandBufferD3D12* CommandBufferImpl::getInterface(const Guid& guid) -{ - if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandBuffer || - guid == GfxGUID::IID_ICommandBufferD3D12) - return static_cast<ICommandBufferD3D12*>(this); - return nullptr; -} - -Result CommandBufferImpl::getNativeHandle(InteropHandle* handle) -{ - handle->api = InteropHandleAPI::D3D12; - handle->handleValue = (uint64_t)m_cmdList.get(); - return SLANG_OK; -} - -void CommandBufferImpl::bindDescriptorHeaps() -{ - if (!m_descriptorHeapsBound) - { - ID3D12DescriptorHeap* heaps[] = { - m_transientHeap->getCurrentViewHeap().getHeap(), - m_transientHeap->getCurrentSamplerHeap().getHeap(), - }; - m_cmdList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps); - m_descriptorHeapsBound = true; - } -} - -void CommandBufferImpl::reinit() -{ - invalidateDescriptorHeapBinding(); - m_rootShaderObject.init(m_renderer); -} - -void CommandBufferImpl::init( - DeviceImpl* renderer, - ID3D12GraphicsCommandList* d3dCommandList, - TransientResourceHeapImpl* transientHeap) -{ - m_transientHeap = transientHeap; - m_renderer = renderer; - m_cmdList = d3dCommandList; - - reinit(); - -#if SLANG_GFX_HAS_DXR_SUPPORT - m_cmdList->QueryInterface<ID3D12GraphicsCommandList4>(m_cmdList4.writeRef()); - if (m_cmdList4) - { - m_cmdList1 = m_cmdList4; - return; - } -#endif - m_cmdList->QueryInterface<ID3D12GraphicsCommandList1>(m_cmdList1.writeRef()); -} - -void CommandBufferImpl::encodeResourceCommands(IResourceCommandEncoder** outEncoder) -{ - m_resourceCommandEncoder.init(this); - *outEncoder = &m_resourceCommandEncoder; -} - -void CommandBufferImpl::encodeRenderCommands( - IRenderPassLayout* renderPass, IFramebuffer* framebuffer, IRenderCommandEncoder** outEncoder) -{ - m_renderCommandEncoder.init( - m_renderer, - m_transientHeap, - this, - static_cast<RenderPassLayoutImpl*>(renderPass), - static_cast<FramebufferImpl*>(framebuffer)); - *outEncoder = &m_renderCommandEncoder; -} - -void CommandBufferImpl::encodeComputeCommands(IComputeCommandEncoder** outEncoder) -{ - m_computeCommandEncoder.init(m_renderer, m_transientHeap, this); - *outEncoder = &m_computeCommandEncoder; -} - -void CommandBufferImpl::encodeRayTracingCommands(IRayTracingCommandEncoder** outEncoder) -{ -#if SLANG_GFX_HAS_DXR_SUPPORT - m_rayTracingCommandEncoder.init(this); - *outEncoder = &m_rayTracingCommandEncoder; -#else - *outEncoder = nullptr; -#endif -} - -void CommandBufferImpl::close() { m_cmdList->Close(); } - -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 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 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); -} - -FenceImpl::~FenceImpl() -{ - if (m_waitEvent) - CloseHandle(m_waitEvent); -} - -HANDLE FenceImpl::getWaitEvent() -{ - if (m_waitEvent) - return m_waitEvent; - m_waitEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS); - return m_waitEvent; -} - -Result FenceImpl::init(DeviceImpl* device, const IFence::Desc& desc) -{ - SLANG_RETURN_ON_FAIL(device->m_device->CreateFence( - desc.initialValue, - desc.isShared ? D3D12_FENCE_FLAG_SHARED : D3D12_FENCE_FLAG_NONE, - IID_PPV_ARGS(m_fence.writeRef()))); - return SLANG_OK; -} - -Result FenceImpl::getCurrentValue(uint64_t* outValue) -{ - *outValue = m_fence->GetCompletedValue(); - return SLANG_OK; -} - -Result FenceImpl::setCurrentValue(uint64_t value) -{ - SLANG_RETURN_ON_FAIL(m_fence->Signal(value)); - return SLANG_OK; -} - -Result FenceImpl::getSharedHandle(InteropHandle* outHandle) -{ - // Check if a shared handle already exists. - if (sharedHandle.handleValue != 0) - { - *outHandle = sharedHandle; - return SLANG_OK; - } - - ComPtr<ID3D12Device> devicePtr; - m_fence->GetDevice(IID_PPV_ARGS(devicePtr.writeRef())); - SLANG_RETURN_ON_FAIL(devicePtr->CreateSharedHandle( - m_fence, NULL, GENERIC_ALL, nullptr, (HANDLE*)&outHandle->handleValue)); - outHandle->api = InteropHandleAPI::D3D12; - sharedHandle = *outHandle; - return SLANG_OK; -} - -Result FenceImpl::getNativeHandle(InteropHandle* outNativeHandle) -{ - outNativeHandle->api = gfx::InteropHandleAPI::D3D12; - outNativeHandle->handleValue = (uint64_t)m_fence.get(); - return SLANG_OK; -} - -} // namespace d3d12 - -Result SLANG_MCALL createD3D12Device(const IDevice::Desc* desc, IDevice** outDevice) -{ - RefPtr<d3d12::DeviceImpl> result = new d3d12::DeviceImpl(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc)); - returnComPtr(outDevice, result); - return SLANG_OK; -} -} // namespace gfx |
