summaryrefslogtreecommitdiff
path: root/tools/gfx/d3d12/render-d3d12.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gfx/d3d12/render-d3d12.cpp')
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp2272
1 files changed, 1325 insertions, 947 deletions
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 4e80ff47a..374a78cdd 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -6,6 +6,7 @@
//WORKING:#include "options.h"
#include "../renderer-shared.h"
#include "../render-graphics-common.h"
+#include "../simple-render-pass-layout.h"
#include "core/slang-blob.h"
#include "core/slang-basic.h"
@@ -62,17 +63,15 @@ struct ID3D12GraphicsCommandList1 {};
namespace gfx {
using namespace Slang;
+static D3D12_RESOURCE_STATES _calcResourceState(IResource::Usage usage);
+
class D3D12Renderer : public GraphicsAPIRenderer
{
public:
// Renderer implementation
virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override;
- virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) override;
- virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override;
- virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override;
- virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- makeSwapchainImagePresentable(ISwapchain* swapchain) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue) override;
virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain(
const ISwapchain::Desc& desc,
WindowHandle window,
@@ -104,6 +103,10 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL
createFramebufferLayout(IFramebufferLayout::Desc const& desc, IFramebufferLayout** outLayout) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createRenderPassLayout(
+ const IRenderPassLayout::Desc& desc,
+ IRenderPassLayout** outRenderPassLayout) override;
+
virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout(
const InputElementDesc* inputElements,
UInt inputElementCount,
@@ -126,49 +129,23 @@ public:
const ComputePipelineStateDesc& desc, IPipelineState** outState) override;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource(
- ITextureResource* resource, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override;
-
- virtual SLANG_NO_THROW void* SLANG_MCALL
- map(IBufferResource* buffer, MapFlavor flavor) override;
- virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) override;
- // virtual void setInputLayout(InputLayout* inputLayout) override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- setPrimitiveTopology(PrimitiveTopology topology) override;
-
- virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet(
- PipelineType pipelineType,
- IPipelineLayout* layout,
- UInt index,
- IDescriptorSet* descriptorSet) override;
-
- virtual SLANG_NO_THROW void SLANG_MCALL setVertexBuffers(
- UInt startSlot,
- UInt slotCount,
- IBufferResource* const* buffers,
- const UInt* strides,
- const UInt* offsets) override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- setViewports(UInt count, Viewport const* viewports) override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- setScissorRects(UInt count, ScissorRect const* rects) override;
- virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) override;
- virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override;
- virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex) override;
- virtual SLANG_NO_THROW void SLANG_MCALL
- drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
- virtual SLANG_NO_THROW void SLANG_MCALL dispatchCompute(int x, int y, int z) override;
- virtual SLANG_NO_THROW void SLANG_MCALL submitGpuWork() override;
- virtual SLANG_NO_THROW void SLANG_MCALL waitForGpu() override;
+ ITextureResource* resource,
+ ResourceState state,
+ ISlangBlob** outBlob,
+ size_t* outRowPitch,
+ size_t* outPixelSize) override;
+
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL readBufferResource(
+ IBufferResource* resource,
+ size_t offset,
+ size_t size,
+ ISlangBlob** outBlob) override;
+
virtual SLANG_NO_THROW RendererType SLANG_MCALL getRendererType() const override
{
return RendererType::DirectX12;
}
- virtual PipelineStateBase* getCurrentPipeline() override
- {
- return m_currentPipelineState;
- }
+
~D3D12Renderer();
protected:
@@ -244,77 +221,23 @@ protected:
public:
typedef BufferResource Parent;
- enum class BackingStyle
- {
- Unknown,
- ResourceBacked, ///< The contents is only held within the resource
- MemoryBacked, ///< The current contents is held in m_memory and copied to GPU every time it's used (typically used for constant buffers)
- };
-
void bindConstantBufferView(D3D12CircularResourceHeap& circularHeap, int index, Submitter* submitter) const
{
- switch (m_backingStyle)
- {
- case BackingStyle::MemoryBacked:
- {
- const size_t bufferSize = m_memory.getCount();
- D3D12CircularResourceHeap::Cursor cursor = circularHeap.allocateConstantBuffer(bufferSize);
- ::memcpy(cursor.m_position, m_memory.getBuffer(), bufferSize);
- // Set the constant buffer
- submitter->setRootConstantBufferView(index, circularHeap.getGpuHandle(cursor));
- break;
- }
- case BackingStyle::ResourceBacked:
- {
- // Set the constant buffer
- submitter->setRootConstantBufferView(index, m_resource.getResource()->GetGPUVirtualAddress());
- break;
- }
- default: break;
- }
+ // Set the constant buffer
+ submitter->setRootConstantBufferView(index, m_resource.getResource()->GetGPUVirtualAddress());
}
BufferResourceImpl(IResource::Usage initialUsage, const Desc& desc):
- Parent(desc),
- m_mapFlavor(MapFlavor::HostRead),
- m_initialUsage(initialUsage)
+ Parent(desc), m_initialUsage(initialUsage)
+ , m_defaultState(_calcResourceState(initialUsage))
{
}
- static BackingStyle _calcResourceBackingStyle(Usage usage)
- {
- // Note: the D3D12 back-end has support for "versioning" of constant buffers,
- // where the same logical `BufferResource` can actually point to different
- // backing storage over its lifetime, to emulate the ability to modify the
- // buffer contents as in D3D11, etc.
- //
- // The VK back-end doesn't have the same behavior, and it is difficult
- // to both support this degree of flexibility *and* efficeintly exploit
- // descriptor tables (since any table referencing the buffer would need
- // to be updated when a new buffer "version" gets allocated).
- //
- // I'm choosing to disable this for now, and make all buffers be memory-backed,
- // although this creates synchronization issues that we'll have to address
- // next.
-
- return BackingStyle::ResourceBacked;
-#if 0
- switch (usage)
- {
- case Usage::ConstantBuffer: return BackingStyle::MemoryBacked;
- default: return BackingStyle::ResourceBacked;
- }
-#endif
- }
-
- BackingStyle m_backingStyle; ///< How the resource is 'backed' - either as a resource or cpu memory. Cpu memory is typically used for constant buffers.
D3D12Resource m_resource; ///< The resource typically in gpu memory
D3D12Resource m_uploadResource; ///< If the resource can be written to, and is in gpu memory (ie not Memory backed), will have upload resource
Usage m_initialUsage;
-
- List<uint8_t> m_memory; ///< Cpu memory buffer, used if the m_backingStyle is MemoryBacked
- MapFlavor m_mapFlavor; ///< If the resource is mapped holds the current mapping flavor
+ D3D12_RESOURCE_STATES m_defaultState;
};
class TextureResourceImpl: public TextureResource
@@ -325,9 +248,11 @@ protected:
TextureResourceImpl(const Desc& desc):
Parent(desc)
{
+ m_defaultState = _calcResourceState(desc.initialUsage);
}
D3D12Resource m_resource;
+ D3D12_RESOURCE_STATES m_defaultState;
};
class SamplerStateImpl : public ISamplerState, public RefObject
@@ -400,151 +325,24 @@ protected:
ShortList<ComPtr<IResourceView>> renderTargetViews;
ComPtr<IResourceView> depthStencilView;
ShortList<D3D12_CPU_DESCRIPTOR_HANDLE> renderTargetDescriptors;
+ struct Color4f
+ {
+ float values[4];
+ };
+ ShortList<Color4f> renderTargetClearValues;
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilDescriptor;
+ DepthStencilClearValue depthStencilClearValue;
};
- class SwapchainImpl
- : public ISwapchain
- , public RefObject
+ class RenderPassLayoutImpl : public SimpleRenderPassLayout
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- ISwapchain* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain)
- return static_cast<ISwapchain*>(this);
- return nullptr;
- }
-
- public:
- Result init(D3D12Renderer* renderer, const ISwapchain::Desc& desc, WindowHandle window)
- {
- // Return fail on non-supported platforms.
- switch (window.type)
- {
- case WindowHandle::Type::Win32Handle:
- break;
- default:
- return SLANG_FAIL;
- }
-
- m_renderer = renderer;
- m_desc = desc;
-
- // Describe the swap chain.
- DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
- swapChainDesc.BufferCount = desc.imageCount;
- swapChainDesc.BufferDesc.Width = desc.width;
- swapChainDesc.BufferDesc.Height = desc.height;
- swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(desc.format);
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
- swapChainDesc.OutputWindow = (HWND)window.handleValues[0];
- swapChainDesc.SampleDesc.Count = 1;
- swapChainDesc.Windowed = TRUE;
-
- if (!desc.enableVSync)
- {
- swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
- }
-
- // Swap chain needs the queue so that it can force a flush on it.
- ComPtr<IDXGISwapChain> swapChain;
- SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->CreateSwapChain(
- m_renderer->m_commandQueue, &swapChainDesc, swapChain.writeRef()));
- SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef()));
-
- if (!desc.enableVSync)
- {
- m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject();
-
- int maxLatency = desc.imageCount - 2;
-
- // Make sure the maximum latency is in the range required by dx12 runtime
- maxLatency = (maxLatency < 1) ? 1 : maxLatency;
- maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS)
- ? DXGI_MAX_SWAP_CHAIN_BUFFERS
- : maxLatency;
-
- m_swapChain->SetMaximumFrameLatency(maxLatency);
- }
-
- // This sample does not support fullscreen transitions.
- SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->MakeWindowAssociation(
- (HWND)window.handleValues[0], DXGI_MWA_NO_ALT_ENTER));
-
- m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex();
-
- for (uint32_t i = 0; i < desc.imageCount; i++)
- {
- ComPtr<ID3D12Resource> d3dResource;
- m_swapChain->GetBuffer(i, IID_PPV_ARGS(d3dResource.writeRef()));
- ITextureResource::Desc imageDesc = {};
- imageDesc.init2D(
- IResource::Type::Texture2D, desc.format, desc.width, desc.height, 0);
- RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc);
- image->m_resource.setResource(d3dResource.get(), D3D12_RESOURCE_STATE_COMMON);
- m_images.add(image);
- }
- return SLANG_OK;
- }
- virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; }
- virtual SLANG_NO_THROW Result getImage(uint32_t index, ITextureResource** outResource) override
+ RefPtr<FramebufferLayoutImpl> m_framebufferLayout;
+ void init(const IRenderPassLayout::Desc& desc)
{
- m_images[index]->addRef();
- *outResource = m_images[index].Ptr();
- return SLANG_OK;
+ SimpleRenderPassLayout::init(desc);
+ m_framebufferLayout = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout);
}
- void makeBackbufferPresentable()
- {
- D3D12BarrierSubmitter submitter(m_renderer->m_commandList);
- m_images[m_renderTargetIndex]->m_resource.transition(
- D3D12_RESOURCE_STATE_PRESENT, submitter);
- }
- virtual SLANG_NO_THROW Result present() override
- {
- if (m_swapChainWaitableObject)
- {
- // check if now is good time to present
- // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it
- // means that no frame is waiting to be be displayed so there is no point doing a
- // present.
- const bool shouldPresent =
- (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT);
- if (shouldPresent)
- {
- m_swapChain->Present(0, 0);
- }
- }
- else
- {
- if (SLANG_FAILED(m_swapChain->Present(1, 0)))
- {
- return SLANG_FAIL;
- }
- }
- // Update the render target index.
- m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex();
- return SLANG_OK;
- }
-
- virtual SLANG_NO_THROW uint32_t acquireNextImage() override
- {
- // `IRenderer::beginFrame()` must be called before `acquireNextImage`.
- SLANG_RELEASE_ASSERT(m_renderer->m_commandListOpenCount == 1);
-
- D3D12BarrierSubmitter submitter(m_renderer->m_commandList);
- m_images[m_renderTargetIndex]->m_resource.transition(
- D3D12_RESOURCE_STATE_RENDER_TARGET, submitter);
- return m_renderTargetIndex;
- }
- public:
- D3D12Renderer* m_renderer = nullptr;
- ISwapchain::Desc m_desc;
- HANDLE m_swapChainWaitableObject = nullptr;
- ComPtr<IDXGISwapChain3> m_swapChain;
- uint32_t m_renderTargetIndex;
- ShortList<RefPtr<TextureResourceImpl>> m_images;
};
class InputLayoutImpl: public IInputLayout, public RefObject
@@ -731,10 +529,10 @@ protected:
~DescriptorSetImpl()
{
- if (m_resourceObjects.getCount())
- m_resourceHeap->free((int)m_resourceTable, (int)m_resourceObjects.getCount());
- if (m_samplerObjects.getCount())
- m_samplerHeap->free((int)m_samplerTable, (int)m_samplerObjects.getCount());
+ if (m_layout->m_resourceCount)
+ m_resourceHeap->free((int)m_resourceTable, (int)m_layout->m_resourceCount);
+ if (m_layout->m_samplerCount)
+ m_samplerHeap->free((int)m_samplerTable, (int)m_layout->m_samplerCount);
}
};
@@ -754,7 +552,6 @@ protected:
class PipelineStateImpl : public PipelineStateBase
{
public:
- RefPtr<PipelineLayoutImpl> m_pipelineLayout;
ComPtr<ID3D12PipelineState> m_pipelineState;
void init(const GraphicsPipelineStateDesc& inDesc)
{
@@ -841,84 +638,1100 @@ protected:
ID3D12GraphicsCommandList* m_commandList;
};
- static PROC loadProc(HMODULE module, char const* name);
- Result createFrameResources();
- /// Blocks until gpu has completed all work
- void releaseFrameResources();
+ static Result _uploadBufferData(
+ ID3D12GraphicsCommandList* cmdList,
+ BufferResourceImpl* buffer,
+ size_t offset,
+ size_t size,
+ void* data)
+ {
+ D3D12_RANGE readRange = {};
+ readRange.Begin = offset;
+ readRange.End = offset + size;
+
+ void* uploadData;
+ SLANG_RETURN_ON_FAIL(buffer->m_uploadResource.getResource()->Map(
+ 0, &readRange, reinterpret_cast<void**>(&uploadData)));
+ memcpy(uploadData, data, size);
+ buffer->m_uploadResource.getResource()->Unmap(0, &readRange);
+ {
+ D3D12BarrierSubmitter submitter(cmdList);
+ submitter.transition(
+ buffer->m_resource, buffer->m_defaultState, D3D12_RESOURCE_STATE_COPY_DEST);
+ }
+ cmdList->CopyBufferRegion(
+ buffer->m_resource.getResource(),
+ offset,
+ buffer->m_uploadResource.getResource(),
+ offset,
+ size);
+ {
+ D3D12BarrierSubmitter submitter(cmdList);
+ submitter.transition(
+ buffer->m_resource, D3D12_RESOURCE_STATE_COPY_DEST, buffer->m_defaultState);
+ }
+ return SLANG_OK;
+ }
+
+ // Use a circular buffer of execution frames to manage in-flight GPU command buffers.
+ // Each call to `executeCommandLists` advances the frame by 1.
+ // If we run out of avaialble frames, wait for the earliest submitted frame to finish.
+ struct ExecutionFrameResources
+ {
+ ComPtr<ID3D12CommandAllocator> m_commandAllocator;
+ List<ComPtr<ID3D12GraphicsCommandList>> m_commandListPool;
+ uint32_t m_commandListAllocId = 0;
+ HANDLE fenceEvent;
- Result createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, size_t srcDataSize, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut);
+ // During command submission, we need all the descriptor tables that get
+ // used to come from a single heap (for each descriptor heap type).
+ //
+ // We will thus keep a single heap of each type that we hope will hold
+ // all the descriptors that actually get needed in a frame.
+ //
+ // TODO: we need an allocation policy to reallocate and resize these
+ // if/when we run out of space during a frame.
+ D3D12DescriptorHeap m_viewHeap; // Cbv, Srv, Uav
+ D3D12DescriptorHeap m_samplerHeap; // Heap for samplers
- void submitGpuWorkAndWait();
- void _resetCommandList();
+ ~ExecutionFrameResources() { CloseHandle(fenceEvent); }
+ Result init(ID3D12Device* device, uint32_t viewHeapSize, uint32_t samplerHeapSize)
+ {
+ SLANG_RETURN_ON_FAIL(device->CreateCommandAllocator(
+ D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(m_commandAllocator.writeRef())));
+ fenceEvent = CreateEventEx(
+ nullptr,
+ false,
+ CREATE_EVENT_INITIAL_SET | CREATE_EVENT_MANUAL_RESET,
+ EVENT_ALL_ACCESS);
+ SLANG_RETURN_ON_FAIL(m_viewHeap.init(
+ device,
+ viewHeapSize,
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
+ D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
+ SLANG_RETURN_ON_FAIL(m_samplerHeap.init(
+ device,
+ samplerHeapSize,
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
+ D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
+ return SLANG_OK;
+ }
+ void reset()
+ {
+ WaitForSingleObject(fenceEvent, INFINITE);
+ m_viewHeap.deallocateAll();
+ m_samplerHeap.deallocateAll();
+ m_commandListAllocId = 0;
+ m_commandAllocator->Reset();
+ for (auto cmdBuffer : m_commandListPool)
+ cmdBuffer->Reset(m_commandAllocator, nullptr);
+ }
+ ComPtr<ID3D12GraphicsCommandList> createCommandList(ID3D12Device* device)
+ {
+ if (m_commandListAllocId == m_commandListPool.getCount())
+ {
+ ComPtr<ID3D12GraphicsCommandList> cmdList;
+ device->CreateCommandList(
+ 0,
+ D3D12_COMMAND_LIST_TYPE_DIRECT,
+ m_commandAllocator,
+ nullptr,
+ IID_PPV_ARGS(cmdList.writeRef()));
+ m_commandListPool.add(cmdList);
+ }
+ assert((Index)m_commandListAllocId < m_commandListPool.getCount());
+ auto& result = m_commandListPool[m_commandListAllocId];
+ ++m_commandListAllocId;
+ return result;
+ }
+ };
- Result captureTextureToSurface(
- D3D12Resource& resource,
- ISlangBlob** blob,
- size_t* outRowPitch,
- size_t* outPixelSize);
+ class CommandBufferImpl
+ : public ICommandBuffer
+ , public RefObject
+ {
+ public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+ ICommandBuffer* getInterface(const Guid& guid)
+ {
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandBuffer)
+ return static_cast<ICommandBuffer*>(this);
+ return nullptr;
+ }
+ public:
+ ComPtr<ID3D12GraphicsCommandList> m_cmdList;
+ ExecutionFrameResources* m_frame;
+ D3D12Renderer* m_renderer;
+ void init(D3D12Renderer* renderer, ExecutionFrameResources* frame)
+ {
+ m_frame = frame;
+ m_renderer = renderer;
+ m_cmdList = m_frame->createCommandList(renderer->m_device);
+ }
+ class PipelineCommandEncoder : public GraphicsComputeCommandEncoderBase
+ {
+ public:
+ bool m_isOpen = false;
+ CommandBufferImpl* m_commandBuffer;
+ ExecutionFrameResources* m_frame;
+ ID3D12Device* m_device;
+ ID3D12GraphicsCommandList* m_d3dCmdList;
+ ID3D12GraphicsCommandList* m_preCmdList = nullptr;
+
+ ID3D12PipelineState* m_boundPipelines[3] = {};
+ RefPtr<DescriptorSetImpl> m_boundDescriptorSets[int(PipelineType::CountOf)]
+ [kMaxDescriptorSetCount];
+ static int 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;
+ }
+ }
- FrameInfo& getFrame() { return m_frameInfos[m_frameIndex]; }
- const FrameInfo& getFrame() const { return m_frameInfos[m_frameIndex]; }
+ RefPtr<PipelineLayoutImpl> m_currentPipelineLayout;
- ID3D12GraphicsCommandList* getCommandList() const { return m_commandList; }
+ void init(CommandBufferImpl* commandBuffer)
+ {
+ m_commandBuffer = commandBuffer;
+ m_rendererBase = static_cast<RendererBase*>(commandBuffer->m_renderer);
+ m_d3dCmdList = m_commandBuffer->m_cmdList;
+ }
- Result _bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter);
+ void endEncodingImpl()
+ {
+ m_isOpen = false;
+ for (int i = 0; i < int(PipelineType::CountOf); i++)
+ {
+ for (auto& descSet : m_boundDescriptorSets[i])
+ {
+ descSet = nullptr;
+ }
+ }
+ }
- Result _createDevice(DeviceCheckFlags deviceCheckFlags, const UnownedStringSlice& nameMatch, D3D_FEATURE_LEVEL featureLevel, DeviceInfo& outDeviceInfo);
-
- int m_commandListOpenCount = 0; ///< If >0 the command list should be open
+ virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSetImpl(
+ PipelineType pipelineType,
+ IPipelineLayout* layout,
+ UInt index,
+ IDescriptorSet* descriptorSet) override
+ {
+ // In D3D12, unlike Vulkan, binding a root signature invalidates *all* descriptor
+ // table
+ // bindings (rather than preserving those that are part of the longest common prefix
+ // between the old and new layout).
+ //
+ // In order to accomodate having descriptor-set bindings that persist across changes
+ // in pipeline state (which may also change pipeline layout), we will shadow the
+ // descriptor-set bindings and only flush them on-demand at draw tiume once the
+ // final pipline layout is known.
+ //
- List<BoundVertexBuffer> m_boundVertexBuffers;
+ auto descriptorSetImpl = (DescriptorSetImpl*)descriptorSet;
+ m_boundDescriptorSets[int(pipelineType)][index] = descriptorSetImpl;
+ }
- RefPtr<BufferResourceImpl> m_boundIndexBuffer;
- DXGI_FORMAT m_boundIndexFormat;
- UINT m_boundIndexOffset;
+ virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferDataImpl(
+ IBufferResource* buffer,
+ size_t offset,
+ size_t size,
+ void* data) override
+ {
+ _uploadBufferData(
+ m_commandBuffer->m_cmdList,
+ static_cast<BufferResourceImpl*>(buffer),
+ offset,
+ size,
+ data);
+ }
- RefPtr<PipelineStateImpl> m_currentPipelineState;
+ void setPipelineStateImpl(IPipelineState* state)
+ {
+ m_currentPipeline = static_cast<PipelineStateImpl*>(state);
+ }
- RefPtr<DescriptorSetImpl> m_boundDescriptorSets[int(PipelineType::CountOf)][kMaxDescriptorSetCount];
+ Result _bindRenderState(
+ PipelineStateImpl* pipelineStateImpl,
+ Submitter* submitter);
+ };
- Desc m_desc;
+ class RenderCommandEncoderImpl
+ : public IRenderCommandEncoder
+ , public PipelineCommandEncoder
+ {
+ public:
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL
+ queryInterface(SlangUUID const& uuid, void** outObject) override
+ {
+ if (uuid == GfxGUID::IID_ISlangUnknown ||
+ uuid == GfxGUID::IID_IRenderCommandEncoder)
+ {
+ *outObject = static_cast<IRenderCommandEncoder*>(this);
+ return SLANG_OK;
+ }
+ *outObject = nullptr;
+ return SLANG_E_NO_INTERFACE;
+ }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() { return 1; }
+ public:
+ RefPtr<RenderPassLayoutImpl> m_renderPass;
+ RefPtr<FramebufferImpl> m_framebuffer;
- bool m_isInitialized = false;
+ List<BoundVertexBuffer> m_boundVertexBuffers;
- D3D12_PRIMITIVE_TOPOLOGY_TYPE m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
- D3D12_PRIMITIVE_TOPOLOGY m_primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ RefPtr<BufferResourceImpl> m_boundIndexBuffer;
- float m_clearColor[4] = { 0, 0, 0, 0 };
+ D3D12_VIEWPORT m_viewports[kMaxRTVCount];
+ D3D12_RECT m_scissorRects[kMaxRTVCount];
- D3D12_VIEWPORT m_viewports[kMaxRTVCount] = {};
+ DXGI_FORMAT m_boundIndexFormat;
+ UINT m_boundIndexOffset;
- ComPtr<ID3D12Debug> m_dxDebug;
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE m_primitiveTopologyType;
+ D3D12_PRIMITIVE_TOPOLOGY m_primitiveTopology;
- DeviceInfo m_deviceInfo;
- ID3D12Device* m_device = nullptr;
+ void init(
+ D3D12Renderer* renderer,
+ ExecutionFrameResources* frame,
+ CommandBufferImpl* cmdBuffer,
+ RenderPassLayoutImpl* renderPass,
+ FramebufferImpl* framebuffer)
+ {
+ m_commandBuffer = cmdBuffer;
+ m_d3dCmdList = cmdBuffer->m_cmdList;
+ m_preCmdList = nullptr;
+ m_device = renderer->m_device;
+ m_rendererBase = renderer;
+ m_renderPass = renderPass;
+ m_framebuffer = framebuffer;
+ m_frame = frame;
+ 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;
+ for (auto& boundPipeline : m_boundPipelines)
+ boundPipeline = nullptr;
+
+ // Set render target states.
+ 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 < renderPass->m_renderTargetAccesses.getCount(); i++)
+ {
+ auto& access = renderPass->m_renderTargetAccesses[i];
- ComPtr<ID3D12CommandQueue> m_commandQueue;
- ComPtr<ID3D12GraphicsCommandList> m_commandList;
+ // Transit resource states.
+ {
+ D3D12BarrierSubmitter submitter(m_d3dCmdList);
+ auto resourceViewImpl =
+ static_cast<ResourceViewImpl*>(framebuffer->renderTargetViews[i].get());
+ auto textureResource =
+ static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr());
+ D3D12_RESOURCE_STATES initialState;
+ if (access.initialState == ResourceState::Undefined)
+ {
+ initialState = textureResource->m_defaultState;
+ }
+ else
+ {
+ initialState = D3DUtil::translateResourceState(access.initialState);
+ }
+ textureResource->m_resource.transition(
+ initialState,
+ D3D12_RESOURCE_STATE_RENDER_TARGET,
+ submitter);
+ }
+ // Clear.
+ if (access.loadOp == IRenderPassLayout::AttachmentLoadOp::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 =
+ static_cast<ResourceViewImpl*>(framebuffer->depthStencilView.get());
+ 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::translateResourceState(
+ 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::AttachmentLoadOp::Clear)
+ {
+ clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
+ }
+ if (renderPass->m_depthStencilAccess.stencilLoadOp ==
+ IRenderPassLayout::AttachmentLoadOp::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);
+ }
+ }
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) override
+ {
+ setPipelineStateImpl(state);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ bindRootShaderObject(IShaderObject* object) override
+ {
+ bindRootShaderObjectImpl(PipelineType::Graphics, object);
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet(
+ IPipelineLayout* layout,
+ UInt index,
+ IDescriptorSet* descriptorSet) override
+ {
+ setDescriptorSetImpl(PipelineType::Graphics, layout, index, descriptorSet);
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setViewports(uint32_t count, const Viewport* viewports) override
+ {
+ static const int kMaxViewports =
+ D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ assert(count <= kMaxViewports && count <= kMaxRTVCount);
+ for (UInt 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);
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setScissorRects(uint32_t count, const ScissorRect* rects) override
+ {
+ static const int kMaxScissorRects =
+ D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ assert(count <= kMaxScissorRects && count <= kMaxRTVCount);
+
+ for (UInt 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);
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setPrimitiveTopology(PrimitiveTopology topology) override
+ {
+ switch (topology)
+ {
+ case PrimitiveTopology::TriangleList:
+ {
+ m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ m_primitiveTopology = D3DUtil::getPrimitiveTopology(topology);
+ break;
+ }
+ default:
+ {
+ assert(!"Unhandled type");
+ }
+ }
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setVertexBuffers(
+ UInt startSlot,
+ UInt slotCount,
+ IBufferResource* const* buffers,
+ const UInt* strides,
+ const UInt* offsets) override
+ {
+ {
+ const Index num = startSlot + slotCount;
+ if (num > m_boundVertexBuffers.getCount())
+ {
+ m_boundVertexBuffers.setCount(num);
+ }
+ }
+
+ for (UInt i = 0; i < slotCount; i++)
+ {
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]);
+ if (buffer)
+ {
+ assert(buffer->m_initialUsage == IResource::Usage::VertexBuffer);
+ }
+
+ BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i];
+ boundBuffer.m_buffer = buffer;
+ boundBuffer.m_stride = int(strides[i]);
+ boundBuffer.m_offset = int(offsets[i]);
+ }
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(
+ IBufferResource* buffer,
+ Format indexFormat,
+ UInt offset = 0) override
+ {
+ m_boundIndexBuffer = (BufferResourceImpl*)buffer;
+ m_boundIndexFormat = D3DUtil::getMapFormat(indexFormat);
+ m_boundIndexOffset = UINT(offset);
+ }
+
+ void 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);
+ _bindRenderState(static_cast<PipelineStateImpl*>(pipelineState), &submitter);
+ }
+
+ m_d3dCmdList->IASetPrimitiveTopology(m_primitiveTopology);
+
+ // Set up vertex buffer views
+ {
+ 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 = UINT(boundVertexBuffer.m_stride);
+ }
+ }
+ 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);
+ }
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ draw(UInt vertexCount, UInt startVertex = 0) override
+ {
+ prepareDraw();
+ m_d3dCmdList->DrawInstanced(UINT(vertexCount), 1, UINT(startVertex), 0);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) override
+ {
+ prepareDraw();
+ m_d3dCmdList->DrawIndexedInstanced(
+ (UINT)indexCount, 1, (UINT)startIndex, (UINT)baseVertex, 0);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override
+ {
+ PipelineCommandEncoder::endEncodingImpl();
+ // 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 = static_cast<ResourceViewImpl*>(
+ m_framebuffer->renderTargetViews[i].get());
+ auto textureResource =
+ static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr());
+ textureResource->m_resource.transition(
+ D3D12_RESOURCE_STATE_RENDER_TARGET,
+ D3DUtil::translateResourceState(access.finalState),
+ submitter);
+ }
+ }
+
+ if (m_renderPass->m_hasDepthStencil)
+ {
+ // Transit resource states.
+ D3D12BarrierSubmitter submitter(m_d3dCmdList);
+ auto resourceViewImpl =
+ static_cast<ResourceViewImpl*>(m_framebuffer->depthStencilView.get());
+ auto textureResource =
+ static_cast<TextureResourceImpl*>(resourceViewImpl->m_resource.Ptr());
+ textureResource->m_resource.transition(
+ D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ D3DUtil::translateResourceState(
+ m_renderPass->m_depthStencilAccess.finalState),
+ submitter);
+ }
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setStencilReference(uint32_t referenceValue) override
+ {
+ m_d3dCmdList->OMSetStencilRef((UINT)referenceValue);
+ }
+ };
+
+ RenderCommandEncoderImpl m_renderCommandEncoder;
+ virtual SLANG_NO_THROW void SLANG_MCALL encodeRenderCommands(
+ IRenderPassLayout* renderPass,
+ IFramebuffer* framebuffer,
+ IRenderCommandEncoder** outEncoder) override
+ {
+ m_renderCommandEncoder.init(
+ m_renderer,
+ m_frame,
+ this,
+ static_cast<RenderPassLayoutImpl*>(renderPass),
+ static_cast<FramebufferImpl*>(framebuffer));
+ *outEncoder = &m_renderCommandEncoder;
+ }
+
+ class ComputeCommandEncoderImpl
+ : public IComputeCommandEncoder
+ , public PipelineCommandEncoder
+ {
+ public:
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL
+ queryInterface(SlangUUID const& uuid, void** outObject) override
+ {
+ if (uuid == GfxGUID::IID_ISlangUnknown ||
+ uuid == GfxGUID::IID_IComputeCommandEncoder)
+ {
+ *outObject = static_cast<IComputeCommandEncoder*>(this);
+ return SLANG_OK;
+ }
+ *outObject = nullptr;
+ return SLANG_E_NO_INTERFACE;
+ }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() { return 1; }
+
+ public:
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override
+ {
+ PipelineCommandEncoder::endEncodingImpl();
+ }
+ void init(
+ D3D12Renderer* renderer,
+ ExecutionFrameResources* frame,
+ CommandBufferImpl* cmdBuffer)
+ {
+ m_rendererBase = renderer;
+ m_commandBuffer = cmdBuffer;
+ m_d3dCmdList = cmdBuffer->m_cmdList;
+ m_preCmdList = nullptr;
+ m_device = renderer->m_device;
+ m_frame = frame;
+ for (auto& boundPipeline : m_boundPipelines)
+ boundPipeline = nullptr;
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) override
+ {
+ setPipelineStateImpl(state);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ bindRootShaderObject(IShaderObject* object) override
+ {
+ bindRootShaderObjectImpl(PipelineType::Compute, object);
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet(
+ IPipelineLayout* layout,
+ UInt index,
+ IDescriptorSet* descriptorSet) override
+ {
+ setDescriptorSetImpl(PipelineType::Compute, layout, index, descriptorSet);
+ }
- D3D12_RECT m_scissorRects[kMaxRTVCount] = {};
+ virtual SLANG_NO_THROW void SLANG_MCALL dispatchCompute(int x, int y, int z) override
+ {
+ auto pipelineStateImpl = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
- UINT m_rtvDescriptorSize = 0;
+ // Submit binding for compute
+ {
+ ComputeSubmitter submitter(m_d3dCmdList);
+ _bindRenderState(pipelineStateImpl, &submitter);
+ }
- UINT m_dsvDescriptorSize = 0;
+ m_d3dCmdList->Dispatch(x, y, z);
+ }
+ };
- // Synchronization objects.
- D3D12CounterFence m_fence;
+ ComputeCommandEncoderImpl m_computeCommandEncoder;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ encodeComputeCommands(IComputeCommandEncoder** outEncoder) override
+ {
+ m_computeCommandEncoder.init(m_renderer, m_frame, this);
+ *outEncoder = &m_computeCommandEncoder;
+ }
- HANDLE m_swapChainWaitableObject;
+ class ResourceCommandEncoderImpl : public IResourceCommandEncoder
+ {
+ public:
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL
+ queryInterface(SlangUUID const& uuid, void** outObject) override
+ {
+ if (uuid == GfxGUID::IID_ISlangUnknown ||
+ uuid == GfxGUID::IID_IResourceCommandEncoder)
+ {
+ *outObject = static_cast<IResourceCommandEncoder*>(this);
+ return SLANG_OK;
+ }
+ *outObject = nullptr;
+ return SLANG_E_NO_INTERFACE;
+ }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() { return 1; }
- // Frame specific data
- int m_numRenderFrames = 0;
- UINT m_frameIndex = 0;
- FrameInfo m_frameInfos[kMaxNumRenderFrames];
+ public:
+ CommandBufferImpl* m_commandBuffer;
+ void init(D3D12Renderer* renderer, CommandBufferImpl* commandBuffer)
+ {
+ m_commandBuffer = commandBuffer;
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer(
+ IBufferResource* dst,
+ size_t dstOffset,
+ IBufferResource* src,
+ size_t srcOffset,
+ size_t size) override
+ {
+ SLANG_UNUSED(dst);
+ SLANG_UNUSED(srcOffset);
+ SLANG_UNUSED(src);
+ SLANG_UNUSED(dstOffset);
+ SLANG_UNUSED(size);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferData(
+ IBufferResource* dst,
+ size_t offset,
+ size_t size,
+ void* data) override
+ {
+ _uploadBufferData(
+ m_commandBuffer->m_cmdList,
+ static_cast<BufferResourceImpl*>(dst),
+ offset,
+ size,
+ data);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() {}
+ };
+
+ ResourceCommandEncoderImpl m_resourceCommandEncoder;
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ encodeResourceCommands(IResourceCommandEncoder** outEncoder) override
+ {
+ m_resourceCommandEncoder.init(m_renderer, this);
+ *outEncoder = &m_resourceCommandEncoder;
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL close() override { m_cmdList->Close(); }
+ };
+
+ class CommandQueueImpl
+ : public ICommandQueue
+ , public RefObject
+ {
+ public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+ ICommandQueue* getInterface(const Guid& guid)
+ {
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandQueue)
+ return static_cast<ICommandQueue*>(this);
+ return nullptr;
+ }
+
+ public:
+ struct CommandBufferPool
+ {
+ List<RefPtr<CommandBufferImpl>> pool;
+ uint32_t allocIndex = 0;
+ RefPtr<CommandBufferImpl> allocCommandBuffer(D3D12Renderer* renderer, ExecutionFrameResources* frame)
+ {
+ if ((Index)allocIndex < pool.getCount())
+ {
+ RefPtr<CommandBufferImpl> result = pool[allocIndex];
+ result->init(renderer, frame);
+ allocIndex++;
+ return result;
+ }
+ RefPtr<CommandBufferImpl> cmdBuffer = new CommandBufferImpl();
+ cmdBuffer->init(renderer, frame);
+ pool.add(cmdBuffer);
+ return cmdBuffer;
+ }
+ void reset()
+ {
+ allocIndex = 0;
+ }
+ };
+ List<CommandBufferPool> m_commandBufferPools;
+ List<ExecutionFrameResources> m_frames;
+ uint32_t m_frameIndex = 0;
+ D3D12Renderer* m_renderer;
+ ComPtr<ID3D12Device> m_device;
+ ComPtr<ID3D12CommandQueue> m_d3dQueue;
+ ComPtr<ID3D12Fence> m_fence;
+ uint64_t m_fenceValue = 0;
+ HANDLE globalWaitHandle;
+ Desc m_desc;
+ Result init(
+ D3D12Renderer* renderer,
+ uint32_t frameCount,
+ uint32_t viewHeapSize,
+ uint32_t samplerHeapSize)
+ {
+ m_renderer = renderer;
+ m_device = renderer->m_device;
+ m_frames.setCount(frameCount);
+ m_commandBufferPools.setCount(frameCount);
+ for (uint32_t i = 0; i < frameCount; i++)
+ {
+ SLANG_RETURN_ON_FAIL(m_frames[i].init(m_device, viewHeapSize, samplerHeapSize));
+ }
+ 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()
+ {
+ wait();
+ CloseHandle(globalWaitHandle);
+ }
+ virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override
+ {
+ return m_desc;
+ }
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createCommandBuffer(ICommandBuffer** outCommandBuffer) override
+ {
+ RefPtr<CommandBufferImpl> result =
+ m_commandBufferPools[m_frameIndex].allocCommandBuffer(
+ m_renderer, &m_frames[m_frameIndex]);
+ *outCommandBuffer = result.detach();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ executeCommandBuffers(uint32_t count, ICommandBuffer* const* commandBuffers) override
+ {
+ ShortList<ID3D12CommandList*> commandLists;
+ for (uint32_t i = 0; i < count; i++)
+ {
+ auto cmdImpl = static_cast<CommandBufferImpl*>(commandBuffers[i]);
+ commandLists.add(cmdImpl->m_cmdList);
+ }
+ m_d3dQueue->ExecuteCommandLists((UINT)count, commandLists.getArrayView().getBuffer());
+
+ auto& frame = m_frames[m_frameIndex];
+ m_fenceValue++;
+ m_d3dQueue->Signal(m_fence, m_fenceValue);
+ ResetEvent(frame.fenceEvent);
+ ResetEvent(globalWaitHandle);
+ m_fence->SetEventOnCompletion(m_fenceValue, frame.fenceEvent);
+ swapExecutionFrame();
+ }
+
+ void swapExecutionFrame()
+ {
+ m_frameIndex = (m_frameIndex + 1) % m_frames.getCount();
+ auto& frame = m_frames[m_frameIndex];
+ frame.reset();
+ m_commandBufferPools[m_frameIndex].reset();
+ }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL wait() override
+ {
+ m_fenceValue++;
+ m_d3dQueue->Signal(m_fence, m_fenceValue);
+ ResetEvent(globalWaitHandle);
+ m_fence->SetEventOnCompletion(m_fenceValue, globalWaitHandle);
+ WaitForSingleObject(globalWaitHandle, INFINITE);
+ }
+ };
+
+ class SwapchainImpl
+ : public ISwapchain
+ , public RefObject
+ {
+ public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+ ISwapchain* getInterface(const Guid& guid)
+ {
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain)
+ return static_cast<ISwapchain*>(this);
+ return nullptr;
+ }
+
+ public:
+ Result init(D3D12Renderer* renderer, const ISwapchain::Desc& desc, WindowHandle window)
+ {
+ // Return fail on non-supported platforms.
+ switch (window.type)
+ {
+ case WindowHandle::Type::Win32Handle:
+ break;
+ default:
+ return SLANG_FAIL;
+ }
+
+ m_renderer = renderer;
+ m_desc = desc;
+ m_queue = static_cast<CommandQueueImpl*>(desc.queue);
+
+ // Describe the swap chain.
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
+ swapChainDesc.BufferCount = desc.imageCount;
+ swapChainDesc.BufferDesc.Width = desc.width;
+ swapChainDesc.BufferDesc.Height = desc.height;
+ swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(desc.format);
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ swapChainDesc.OutputWindow = (HWND)window.handleValues[0];
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.Windowed = TRUE;
+
+ if (!desc.enableVSync)
+ {
+ swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ }
+
+ // Swap chain needs the queue so that it can force a flush on it.
+ ComPtr<IDXGISwapChain> swapChain;
+ SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->CreateSwapChain(
+ m_queue->m_d3dQueue, &swapChainDesc, swapChain.writeRef()));
+ SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef()));
+
+ if (!desc.enableVSync)
+ {
+ m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject();
+
+ int maxLatency = desc.imageCount - 2;
+
+ // Make sure the maximum latency is in the range required by dx12 runtime
+ maxLatency = (maxLatency < 1) ? 1 : maxLatency;
+ maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS)
+ ? DXGI_MAX_SWAP_CHAIN_BUFFERS
+ : maxLatency;
+
+ m_swapChain->SetMaximumFrameLatency(maxLatency);
+ }
+
+ // This sample does not support fullscreen transitions.
+ SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->MakeWindowAssociation(
+ (HWND)window.handleValues[0], DXGI_MWA_NO_ALT_ENTER));
+
+ m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex();
+
+ for (uint32_t i = 0; i < desc.imageCount; i++)
+ {
+ ComPtr<ID3D12Resource> d3dResource;
+ m_swapChain->GetBuffer(i, IID_PPV_ARGS(d3dResource.writeRef()));
+ ITextureResource::Desc imageDesc = {};
+ imageDesc.setDefaults(IResource::Usage::RenderTarget);
+ imageDesc.init2D(
+ IResource::Type::Texture2D, desc.format, desc.width, desc.height, 0);
+ RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc);
+ image->m_resource.setResource(d3dResource.get());
+ image->m_defaultState = D3D12_RESOURCE_STATE_PRESENT;
+ m_images.add(image);
+ }
+ return SLANG_OK;
+ }
+ virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; }
+ virtual SLANG_NO_THROW Result
+ getImage(uint32_t index, ITextureResource** outResource) override
+ {
+ m_images[index]->addRef();
+ *outResource = m_images[index].Ptr();
+ return SLANG_OK;
+ }
+ virtual SLANG_NO_THROW Result present() override
+ {
+ if (m_swapChainWaitableObject)
+ {
+ // check if now is good time to present
+ // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it
+ // means that no frame is waiting to be be displayed so there is no point doing a
+ // present.
+ const bool shouldPresent =
+ (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT);
+ if (shouldPresent)
+ {
+ m_swapChain->Present(0, 0);
+ }
+ }
+ else
+ {
+ if (SLANG_FAILED(m_swapChain->Present(1, 0)))
+ {
+ return SLANG_FAIL;
+ }
+ }
+ // Update the render target index.
+ m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW uint32_t acquireNextImage() override
+ {
+ return m_renderTargetIndex;
+ }
+
+ public:
+ D3D12Renderer* m_renderer = nullptr;
+ ISwapchain::Desc m_desc;
+ HANDLE m_swapChainWaitableObject = nullptr;
+ ComPtr<IDXGISwapChain3> m_swapChain;
+ RefPtr<CommandQueueImpl> m_queue;
+ uint32_t m_renderTargetIndex;
+ ShortList<RefPtr<TextureResourceImpl>> m_images;
+ };
+
+ static PROC loadProc(HMODULE module, char const* name);
+
+ Result createCommandQueueImpl(
+ uint32_t frameCount,
+ uint32_t viewHeapSize,
+ uint32_t samplerHeapSize,
+ CommandQueueImpl** outQueue);
+
+ Result createBuffer(
+ const D3D12_RESOURCE_DESC& resourceDesc,
+ const void* srcData,
+ size_t srcDataSize,
+ D3D12Resource& uploadResource,
+ D3D12_RESOURCE_STATES finalState,
+ D3D12Resource& resourceOut);
+
+ Result captureTextureToSurface(
+ D3D12Resource& resource,
+ ResourceState state,
+ ISlangBlob** blob,
+ size_t* outRowPitch,
+ size_t* outPixelSize);
+
+ Result _createDevice(
+ DeviceCheckFlags deviceCheckFlags,
+ const UnownedStringSlice& nameMatch,
+ D3D_FEATURE_LEVEL featureLevel,
+ DeviceInfo& outDeviceInfo);
- int m_numRenderTargets = 2;
- RefPtr<FramebufferImpl> m_frameBuffer;
+ struct ResourceCommandRecordInfo
+ {
+ ComPtr<ICommandBuffer> commandBuffer;
+ ID3D12GraphicsCommandList* d3dCommandList;
+ };
+ ResourceCommandRecordInfo encodeResourceCommands()
+ {
+ ResourceCommandRecordInfo info;
+ m_resourceCommandQueue->createCommandBuffer(info.commandBuffer.writeRef());
+ info.d3dCommandList = static_cast<CommandBufferImpl*>(info.commandBuffer.get())->m_cmdList;
+ return info;
+ }
+ void submitResourceCommandsAndWait(const ResourceCommandRecordInfo& info)
+ {
+ info.commandBuffer->close();
+ m_resourceCommandQueue->executeCommandBuffer(info.commandBuffer);
+ m_resourceCommandQueue->wait();
+ }
+
+ Desc m_desc;
+
+ bool m_isInitialized = false;
+
+ ComPtr<ID3D12Debug> m_dxDebug;
+
+ DeviceInfo m_deviceInfo;
+ ID3D12Device* m_device = nullptr;
- int32_t m_depthStencilUsageFlags = 0; ///< D3DUtil::UsageFlag combination for depth stencil
- int32_t m_targetUsageFlags = 0; ///< D3DUtil::UsageFlag combination for target
+ RefPtr<CommandQueueImpl> m_resourceCommandQueue;
// Dll entry points
PFN_D3D12_GET_DEBUG_INTERFACE m_D3D12GetDebugInterface = nullptr;
@@ -928,6 +1741,109 @@ protected:
bool m_nvapi = false;
};
+
+Result D3D12Renderer::CommandBufferImpl::PipelineCommandEncoder::_bindRenderState(
+ PipelineStateImpl* pipelineStateImpl,
+ Submitter* submitter)
+{
+ auto commandList = m_commandBuffer->m_cmdList;
+ // TODO: we should only set some of this state as needed...
+
+ auto pipelineTypeIndex = (int)pipelineStateImpl->desc.type;
+ auto pipelineLayout = static_cast<PipelineLayoutImpl*>(pipelineStateImpl->m_pipelineLayout.get());
+
+ submitter->setRootSignature(pipelineLayout->m_rootSignature);
+ commandList->SetPipelineState(pipelineStateImpl->m_pipelineState);
+
+ ID3D12DescriptorHeap* heaps[] = {
+ m_frame->m_viewHeap.getHeap(),
+ m_frame->m_samplerHeap.getHeap(),
+ };
+ commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps);
+
+ // We need to copy descriptors over from the descriptor sets
+ // (where they are stored in CPU-visible heaps) to the GPU-visible
+ // heaps so that they can be accessed by shader code.
+
+ Int descriptorSetCount = pipelineLayout->m_descriptorSetCount;
+ Int rootParameterIndex = 0;
+ for (Int dd = 0; dd < descriptorSetCount; ++dd)
+ {
+ auto descriptorSet = m_boundDescriptorSets[pipelineTypeIndex][dd];
+ auto descriptorSetLayout = descriptorSet->m_layout;
+
+ // TODO: require that `descriptorSetLayout` is compatible with
+ // `pipelineLayout->descriptorSetlayouts[dd]`.
+
+ {
+ if (auto descriptorCount = descriptorSetLayout->m_resourceCount)
+ {
+ auto& gpuHeap = m_frame->m_viewHeap;
+ auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount));
+
+ auto& cpuHeap = *descriptorSet->m_resourceHeap;
+ auto cpuDescriptorTable = descriptorSet->m_resourceTable;
+
+ m_device->CopyDescriptorsSimple(
+ UINT(descriptorCount),
+ gpuHeap.getCpuHandle(gpuDescriptorTable),
+ cpuHeap.getCpuHandle(int(cpuDescriptorTable)),
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+ submitter->setRootDescriptorTable(
+ int(rootParameterIndex++), gpuHeap.getGpuHandle(gpuDescriptorTable));
+ }
+ }
+ {
+ if (auto descriptorCount = descriptorSetLayout->m_samplerCount)
+ {
+ auto& gpuHeap = m_frame->m_samplerHeap;
+ auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount));
+
+ auto& cpuHeap = *descriptorSet->m_samplerHeap;
+ auto cpuDescriptorTable = descriptorSet->m_samplerTable;
+
+ m_device->CopyDescriptorsSimple(
+ UINT(descriptorCount),
+ gpuHeap.getCpuHandle(gpuDescriptorTable),
+ cpuHeap.getCpuHandle(int(cpuDescriptorTable)),
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+
+ submitter->setRootDescriptorTable(
+ int(rootParameterIndex++), gpuHeap.getGpuHandle(gpuDescriptorTable));
+ }
+ }
+ if (auto rootConstantRangeCount = descriptorSetLayout->m_rootConstantRanges.getCount())
+ {
+ auto srcData = descriptorSet->m_rootConstantData.getBuffer();
+
+ for (auto& rootConstantRangeInfo : descriptorSetLayout->m_rootConstantRanges)
+ {
+ auto countOf32bitValues = rootConstantRangeInfo.size / sizeof(uint32_t);
+ submitter->setRootConstants(
+ rootConstantRangeInfo.rootParamIndex,
+ 0,
+ countOf32bitValues,
+ srcData + rootConstantRangeInfo.offset);
+ }
+ }
+ }
+
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createCommandQueueImpl(
+ uint32_t frameCount,
+ uint32_t viewHeapSize,
+ uint32_t samplerHeapSize,
+ D3D12Renderer::CommandQueueImpl** outQueue)
+{
+ RefPtr<D3D12Renderer::CommandQueueImpl> queue = new D3D12Renderer::CommandQueueImpl();
+ SLANG_RETURN_ON_FAIL(queue->init(this, frameCount, viewHeapSize, samplerHeapSize));
+ *outQueue = queue.detach();
+ return SLANG_OK;
+}
+
SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, IRenderer** outRenderer)
{
RefPtr<D3D12Renderer> result = new D3D12Renderer();
@@ -947,29 +1863,8 @@ SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, IRender
return proc;
}
-void D3D12Renderer::releaseFrameResources()
-{
- for (int i = 0; i < m_numRenderFrames; i++)
- {
- FrameInfo& info = m_frameInfos[i];
- info.reset();
- info.m_fenceValue = m_fence.getCurrentValue();
- }
-}
-
-void D3D12Renderer::waitForGpu()
-{
- m_fence.nextSignalAndWait(m_commandQueue);
-}
-
D3D12Renderer::~D3D12Renderer()
{
- if (m_isInitialized)
- {
- // Ensure that the GPU is no longer referencing resources that are about to be
- // cleaned up by the destructor.
- waitForGpu();
- }
}
static void _initSrvDesc(IResource::Type resourceType, const ITextureResource::Desc& textureDesc, const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut)
@@ -1098,105 +1993,22 @@ Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, cons
::memcpy(dstData, srcData, srcDataSize);
dxUploadResource->Unmap(0, nullptr);
- m_commandList->CopyBufferRegion(resourceOut, 0, uploadResource, 0, bufferSize);
-
- // Make sure it's in the right state
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- resourceOut.transition(finalState, submitter);
- }
-
- submitGpuWorkAndWait();
+ auto encodeInfo = encodeResourceCommands();
+ encodeInfo.d3dCommandList->CopyBufferRegion(resourceOut, 0, uploadResource, 0, bufferSize);
+ submitResourceCommandsAndWait(encodeInfo);
}
return SLANG_OK;
}
-void D3D12Renderer::_resetCommandList()
-{
- const FrameInfo& frame = getFrame();
-
- ID3D12GraphicsCommandList* commandList = getCommandList();
- commandList->Reset(frame.m_commandAllocator, nullptr);
-}
-
-void D3D12Renderer::beginFrame()
-{
-}
-
-void D3D12Renderer::makeSwapchainImagePresentable(ISwapchain* swapchain)
-{
- static_cast<SwapchainImpl*>(swapchain)->makeBackbufferPresentable();
-}
-
-void D3D12Renderer::endFrame()
-{
- assert(m_commandListOpenCount == 1);
- SLANG_ASSERT_VOID_ON_FAIL(m_commandList->Close());
- {
- // Execute the command list.
- ID3D12CommandList* commandLists[] = { m_commandList };
- m_commandQueue->ExecuteCommandLists(SLANG_COUNT_OF(commandLists), commandLists);
- }
-
- assert(m_commandListOpenCount == 1);
- // Must be 0
- m_commandListOpenCount = 0;
-
-
- // Increment the fence value. Save on the frame - we'll know that frame is done when the fence
- // value >=
- m_frameInfos[m_frameIndex].m_fenceValue = m_fence.nextSignal(m_commandQueue);
-
- // increment frame index after signal
- m_frameIndex = (m_frameIndex + 1) % m_numRenderFrames;
-
- // On the current frame wait until it is completed
- {
- FrameInfo& frame = m_frameInfos[m_frameIndex];
- // If the next frame is not ready to be rendered yet, wait until it is ready.
- m_fence.waitUntilCompleted(frame.m_fenceValue);
- }
-
- getFrame().m_commandAllocator->Reset();
-
- _resetCommandList();
-
- m_commandListOpenCount = 1;
-
- getFrame().m_viewHeap.deallocateAll();
- getFrame().m_samplerHeap.deallocateAll();
-}
-
-void D3D12Renderer::submitGpuWork()
-{
- assert(m_commandListOpenCount);
- ID3D12GraphicsCommandList* commandList = getCommandList();
-
- SLANG_ASSERT_VOID_ON_FAIL(commandList->Close());
- {
- // Execute the command list.
- ID3D12CommandList* commandLists[] = { commandList };
- m_commandQueue->ExecuteCommandLists(SLANG_COUNT_OF(commandLists), commandLists);
- }
-
- // Reset the render target
- _resetCommandList();
-}
-
-void D3D12Renderer::submitGpuWorkAndWait()
-{
- submitGpuWork();
- waitForGpu();
-}
-
Result D3D12Renderer::captureTextureToSurface(
D3D12Resource& resource,
+ ResourceState state,
ISlangBlob** outBlob,
size_t* outRowPitch,
size_t* outPixelSize)
{
- const D3D12_RESOURCE_STATES initialState = resource.getState();
+ const D3D12_RESOURCE_STATES initialState = D3DUtil::translateResourceState(state);
const D3D12_RESOURCE_DESC desc = resource.getResource()->GetDesc();
@@ -1230,9 +2042,12 @@ Result D3D12Renderer::captureTextureToSurface(
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::translateResourceState(state);
+
{
- D3D12BarrierSubmitter submitter(m_commandList);
- resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter);
+ D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
+ resource.transition(currentState, D3D12_RESOURCE_STATE_COPY_SOURCE, submitter);
}
// Do the copy
@@ -1252,16 +2067,16 @@ Result D3D12Renderer::captureTextureToSurface(
dstLoc.PlacedFootprint.Footprint.Depth = 1;
dstLoc.PlacedFootprint.Footprint.RowPitch = UINT(rowPitch);
- m_commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
+ encodeInfo.d3dCommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
}
{
- D3D12BarrierSubmitter submitter(m_commandList);
- resource.transition(initialState, submitter);
+ D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
+ resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, currentState, submitter);
}
// Submit the copy, and wait for copy to complete
- submitGpuWorkAndWait();
+ submitResourceCommandsAndWait(encodeInfo);
{
ID3D12Resource* dxResource = stagingResource;
@@ -1280,88 +2095,6 @@ Result D3D12Renderer::captureTextureToSurface(
}
}
-Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter)
-{
- // TODO: we should only set some of this state as needed...
-
- auto pipelineTypeIndex = (int) pipelineStateImpl->desc.type;
- auto pipelineLayout = pipelineStateImpl->m_pipelineLayout;
-
- submitter->setRootSignature(pipelineLayout->m_rootSignature);
- commandList->SetPipelineState(pipelineStateImpl->m_pipelineState);
-
- ID3D12DescriptorHeap* heaps[] =
- {
- getFrame().m_viewHeap.getHeap(),
- getFrame().m_samplerHeap.getHeap(),
- };
- commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps);
-
- // We need to copy descriptors over from the descriptor sets
- // (where they are stored in CPU-visible heaps) to the GPU-visible
- // heaps so that they can be accessed by shader code.
-
- Int descriptorSetCount = pipelineLayout->m_descriptorSetCount;
- Int rootParameterIndex = 0;
- for(Int dd = 0; dd < descriptorSetCount; ++dd)
- {
- auto descriptorSet = m_boundDescriptorSets[pipelineTypeIndex][dd];
- auto descriptorSetLayout = descriptorSet->m_layout;
-
- // TODO: require that `descriptorSetLayout` is compatible with
- // `pipelineLayout->descriptorSetlayouts[dd]`.
-
- {
- if(auto descriptorCount = descriptorSetLayout->m_resourceCount)
- {
- auto& gpuHeap = getFrame().m_viewHeap;
- auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount));
-
- auto& cpuHeap = *descriptorSet->m_resourceHeap;
- auto cpuDescriptorTable = descriptorSet->m_resourceTable;
-
- m_device->CopyDescriptorsSimple(
- UINT(descriptorCount),
- gpuHeap.getCpuHandle(gpuDescriptorTable),
- cpuHeap.getCpuHandle(int(cpuDescriptorTable)),
- D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
-
- submitter->setRootDescriptorTable(int(rootParameterIndex++), gpuHeap.getGpuHandle(gpuDescriptorTable));
- }
- }
- {
- if(auto descriptorCount = descriptorSetLayout->m_samplerCount)
- {
- auto& gpuHeap = getFrame().m_samplerHeap;
- auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount));
-
- auto& cpuHeap = *descriptorSet->m_samplerHeap;
- auto cpuDescriptorTable = descriptorSet->m_samplerTable;
-
- m_device->CopyDescriptorsSimple(
- UINT(descriptorCount),
- gpuHeap.getCpuHandle(gpuDescriptorTable),
- cpuHeap.getCpuHandle(int(cpuDescriptorTable)),
- D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
-
- submitter->setRootDescriptorTable(int(rootParameterIndex++), gpuHeap.getGpuHandle(gpuDescriptorTable));
- }
- }
- if(auto rootConstantRangeCount = descriptorSetLayout->m_rootConstantRanges.getCount())
- {
- auto srcData = descriptorSet->m_rootConstantData.getBuffer();
-
- for(auto& rootConstantRangeInfo : descriptorSetLayout->m_rootConstantRanges)
- {
- auto countOf32bitValues = rootConstantRangeInfo.size / sizeof(uint32_t);
- submitter->setRootConstants(rootConstantRangeInfo.rootParamIndex, 0, countOf32bitValues, srcData + rootConstantRangeInfo.offset);
- }
- }
- }
-
- return SLANG_OK;
-}
-
// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
Result D3D12Renderer::_createDevice(DeviceCheckFlags deviceCheckFlags, const UnownedStringSlice& nameMatch, D3D_FEATURE_LEVEL featureLevel, DeviceInfo& outDeviceInfo)
@@ -1616,32 +2349,11 @@ Result D3D12Renderer::initialize(const Desc& desc)
}
}
- m_numRenderFrames = 3;
- m_numRenderTargets = 2;
-
m_desc = desc;
- // Describe and create the command queue.
- D3D12_COMMAND_QUEUE_DESC queueDesc = {};
- queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
- queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+ // Create a command queue for internal resource transfer operations.
+ SLANG_RETURN_ON_FAIL(createCommandQueueImpl(1, 32, 4, m_resourceCommandQueue.writeRef()));
- SLANG_RETURN_ON_FAIL(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_commandQueue.writeRef())));
-
- // Create descriptor heaps.
- for (int i = 0; i < m_numRenderFrames; i++)
- {
- SLANG_RETURN_ON_FAIL(m_frameInfos[i].m_viewHeap.init(
- m_device,
- 256,
- D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
- D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
- SLANG_RETURN_ON_FAIL(m_frameInfos[i].m_samplerHeap.init(
- m_device,
- 16,
- D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
- D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
- }
SLANG_RETURN_ON_FAIL(m_cpuViewHeap.init (m_device, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap.init(m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER));
@@ -1650,59 +2362,18 @@ Result D3D12Renderer::initialize(const Desc& desc)
SLANG_RETURN_ON_FAIL(m_viewAllocator.init (m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
SLANG_RETURN_ON_FAIL(m_samplerAllocator.init(m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER));
- // Setup frame resources
- SLANG_RETURN_ON_FAIL(createFrameResources());
-
- // Setup fence, and close the command list (as default state without begin/endRender is closed)
- {
- SLANG_RETURN_ON_FAIL(m_fence.init(m_device));
- // Create the command list. When command lists are created they are open, so close it.
- FrameInfo& frame = m_frameInfos[m_frameIndex];
- SLANG_RETURN_ON_FAIL(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frame.m_commandAllocator, nullptr, IID_PPV_ARGS(m_commandList.writeRef())));
- m_commandList->Close();
- }
-
- _resetCommandList();
-
- m_commandListOpenCount = 1;
-
m_isInitialized = true;
return SLANG_OK;
}
-Result D3D12Renderer::createFrameResources()
+Result D3D12Renderer::createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue)
{
- // Set up frames
- for (int i = 0; i < m_numRenderFrames; i++)
- {
- FrameInfo& frame = m_frameInfos[i];
- SLANG_RETURN_ON_FAIL(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frame.m_commandAllocator.writeRef())));
- }
-
+ RefPtr<CommandQueueImpl> queue;
+ SLANG_RETURN_ON_FAIL(createCommandQueueImpl(8, 4096, 1024, queue.writeRef()));
+ *outQueue = queue.detach();
return SLANG_OK;
}
-void D3D12Renderer::setClearColor(const float color[4])
-{
- memcpy(m_clearColor, color, sizeof(m_clearColor));
-}
-
-void D3D12Renderer::clearFrame()
-{
- // Record commands
- if (!m_frameBuffer)
- return;
- for (auto rtv : m_frameBuffer->renderTargetDescriptors)
- {
- m_commandList->ClearRenderTargetView(rtv, m_clearColor, 0, nullptr);
- }
- if (m_frameBuffer->depthStencilView)
- {
- m_commandList->ClearDepthStencilView(
- m_frameBuffer->depthStencilDescriptor, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
- }
-}
-
SLANG_NO_THROW Result SLANG_MCALL D3D12Renderer::createSwapchain(
const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain)
{
@@ -1714,11 +2385,17 @@ SLANG_NO_THROW Result SLANG_MCALL D3D12Renderer::createSwapchain(
SlangResult D3D12Renderer::readTextureResource(
ITextureResource* resource,
+ ResourceState state,
ISlangBlob** outBlob,
size_t* outRowPitch,
size_t* outPixelSize)
{
- return captureTextureToSurface(static_cast<TextureResourceImpl*>(resource)->m_resource, outBlob, outRowPitch, outPixelSize);
+ return captureTextureToSurface(
+ static_cast<TextureResourceImpl*>(resource)->m_resource,
+ state,
+ outBlob,
+ outRowPitch,
+ outPixelSize);
}
static D3D12_RESOURCE_STATES _calcResourceState(IResource::Usage usage)
@@ -1736,6 +2413,8 @@ static D3D12_RESOURCE_STATES _calcResourceState(IResource::Usage usage)
case Usage::UnorderedAccess: return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
case Usage::PixelShaderResource: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
case Usage::NonPixelShaderResource: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+ case Usage::ShaderResource: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
+ D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
case Usage::GenericRead: return D3D12_RESOURCE_STATE_GENERIC_READ;
default: return D3D12_RESOURCE_STATES(0);
}
@@ -1859,7 +2538,9 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const
clearValuePtr = nullptr;
}
clearValue.Format = pixelFormat;
- memcpy(clearValue.Color, descIn.optimalClearValue, sizeof(clearValue.Color));
+ 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,
@@ -1960,6 +2641,7 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const
}
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
@@ -1973,21 +2655,23 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const
dst.pResource = texture->m_resource;
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst.SubresourceIndex = subResourceIndex;
- m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
+ encodeInfo.d3dCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
subResourceIndex++;
}
// Block - waiting for copy to complete (so can drop upload texture)
- submitGpuWorkAndWait();
+ submitResourceCommandsAndWait(encodeInfo);
}
}
{
+ auto encodeInfo = encodeResourceCommands();
const D3D12_RESOURCE_STATES finalState = _calcResourceState(initialUsage);
- D3D12BarrierSubmitter submitter(m_commandList);
- texture->m_resource.transition(finalState, submitter);
-
- submitGpuWorkAndWait();
+ {
+ D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
+ texture->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, finalState, submitter);
+ }
+ submitResourceCommandsAndWait(encodeInfo);
}
*outResource = texture.detach();
@@ -1996,8 +2680,6 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const
Result D3D12Renderer::createBufferResource(IResource::Usage initialUsage, const IBufferResource::Desc& descIn, const void* initData, IBufferResource** outResource)
{
- typedef BufferResourceImpl::BackingStyle Style;
-
BufferResource::Desc srcDesc(descIn);
srcDesc.setDefaults(initialUsage);
@@ -2009,37 +2691,13 @@ Result D3D12Renderer::createBufferResource(IResource::Usage initialUsage, const
RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, srcDesc));
- // Save the style
- buffer->m_backingStyle = BufferResourceImpl::_calcResourceBackingStyle(initialUsage);
-
D3D12_RESOURCE_DESC bufferDesc;
_initBufferResourceDesc(alignedSizeInBytes, bufferDesc);
bufferDesc.Flags = _calcResourceBindFlags(initialUsage, srcDesc.bindFlags);
- switch (buffer->m_backingStyle)
- {
- case Style::MemoryBacked:
- {
- // Assume the constant buffer will change every frame. We'll just keep a copy of the contents
- // in regular memory until it needed
- buffer->m_memory.setCount(UInt(alignedSizeInBytes));
- // Initialize
- if (initData)
- {
- ::memcpy(buffer->m_memory.getBuffer(), initData, srcDesc.sizeInBytes);
- }
- break;
- }
- case Style::ResourceBacked:
- {
- const D3D12_RESOURCE_STATES initialState = _calcResourceState(initialUsage);
- SLANG_RETURN_ON_FAIL(createBuffer(bufferDesc, initData, srcDesc.sizeInBytes, buffer->m_uploadResource, initialState, buffer->m_resource));
- break;
- }
- default:
- return SLANG_FAIL;
- }
+ const D3D12_RESOURCE_STATES initialState = _calcResourceState(initialUsage);
+ SLANG_RETURN_ON_FAIL(createBuffer(bufferDesc, initData, srcDesc.sizeInBytes, buffer->m_uploadResource, initialState, buffer->m_resource));
*outResource = buffer.detach();
return SLANG_OK;
@@ -2351,15 +3009,27 @@ Result D3D12Renderer::createFramebuffer(IFramebuffer::Desc const& desc, IFramebu
RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl();
framebuffer->renderTargetViews.setCount(desc.renderTargetCount);
framebuffer->renderTargetDescriptors.setCount(desc.renderTargetCount);
+ framebuffer->renderTargetClearValues.setCount(desc.renderTargetCount);
for (uint32_t i = 0; i < desc.renderTargetCount; i++)
{
framebuffer->renderTargetViews[i] = desc.renderTargetViews[i];
framebuffer->renderTargetDescriptors[i] =
static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_descriptor.cpuHandle;
+ auto clearValue =
+ static_cast<TextureResourceImpl*>(
+ static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_resource.Ptr())
+ ->getDesc()
+ ->optimalClearValue.color;
+ memcpy(&framebuffer->renderTargetClearValues[i], &clearValue, sizeof(ColorClearValue));
}
framebuffer->depthStencilView = 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;
}
@@ -2394,6 +3064,16 @@ Result D3D12Renderer::createFramebufferLayout(
return SLANG_OK;
}
+Result D3D12Renderer::createRenderPassLayout(
+ const IRenderPassLayout::Desc& desc,
+ IRenderPassLayout** outRenderPassLayout)
+{
+ RefPtr<RenderPassLayoutImpl> result = new RenderPassLayoutImpl();
+ result->init(desc);
+ *outRenderPassLayout = result.detach();
+ return SLANG_OK;
+}
+
Result D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, IInputLayout** outLayout)
{
RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
@@ -2429,7 +3109,7 @@ Result D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, U
}
dstEle.SemanticName = semanticName;
- dstEle.SemanticIndex = (UINT)srcEle.semanticIndex;
+ dstEle.SemanticIndex = (UINT)srcEle.semanticIndex;
dstEle.Format = D3DUtil::getMapFormat(srcEle.format);
dstEle.InputSlot = 0;
dstEle.AlignedByteOffset = (UINT)srcEle.offset;
@@ -2441,337 +3121,58 @@ Result D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, U
return SLANG_OK;
}
-void* D3D12Renderer::map(IBufferResource* bufferIn, MapFlavor flavor)
+Result D3D12Renderer::readBufferResource(
+ IBufferResource* bufferIn,
+ size_t offset,
+ size_t size,
+ ISlangBlob** outBlob)
{
- typedef BufferResourceImpl::BackingStyle Style;
+ auto encodeInfo = encodeResourceCommands();
BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
- buffer->m_mapFlavor = flavor;
const size_t bufferSize = buffer->getDesc()->sizeInBytes;
- switch (buffer->m_backingStyle)
- {
- case Style::ResourceBacked:
- {
- // We need this in a state so we can upload
- switch (flavor)
- {
- case MapFlavor::HostWrite:
- case MapFlavor::WriteDiscard:
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter);
- buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter);
-
- const D3D12_RANGE readRange = {};
-
- void* uploadData;
- SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadResource.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&uploadData)));
- return uploadData;
-
- break;
- }
- case MapFlavor::HostRead:
- {
- // This will be slow!!! - it blocks CPU on GPU completion
- D3D12Resource& resource = buffer->m_resource;
-
- // 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(bufferSize, stagingDesc);
-
- D3D12Resource stageBuf;
- SLANG_RETURN_NULL_ON_FAIL(stageBuf.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr));
-
- const D3D12_RESOURCE_STATES initialState = resource.getState();
-
- // Make it a source
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter);
- }
- // Do the copy
- m_commandList->CopyBufferRegion(stageBuf, 0, resource, 0, bufferSize);
- // Switch it back
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- resource.transition(initialState, submitter);
- }
-
- // Wait until complete
- submitGpuWorkAndWait();
-
- // Map and copy
- {
- UINT8* data;
- D3D12_RANGE readRange = { 0, bufferSize };
-
- SLANG_RETURN_NULL_ON_FAIL(stageBuf.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data)));
-
- // Copy to memory buffer
- buffer->m_memory.setCount(bufferSize);
- ::memcpy(buffer->m_memory.getBuffer(), data, bufferSize);
-
- stageBuf.getResource()->Unmap(0, nullptr);
- }
-
- return buffer->m_memory.getBuffer();
- }
- }
- break;
- }
- case Style::MemoryBacked:
- {
- return buffer->m_memory.getBuffer();
- }
- default: return nullptr;
- }
+ // This will be slow!!! - it blocks CPU on GPU completion
+ D3D12Resource& resource = buffer->m_resource;
- return nullptr;
-}
+ // 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;
-void D3D12Renderer::unmap(IBufferResource* bufferIn)
-{
- typedef BufferResourceImpl::BackingStyle Style;
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
+ // Resource to readback to
+ D3D12_RESOURCE_DESC stagingDesc;
+ _initBufferResourceDesc(bufferSize, stagingDesc);
- switch (buffer->m_backingStyle)
- {
- case Style::MemoryBacked:
- {
- // Don't need to do anything, as will be uploaded automatically when used
- break;
- }
- case Style::ResourceBacked:
- {
- // We need this in a state so we can upload
- switch (buffer->m_mapFlavor)
- {
- case MapFlavor::HostWrite:
- case MapFlavor::WriteDiscard:
- {
- // Unmap
- ID3D12Resource* uploadResource = buffer->m_uploadResource;
- ID3D12Resource* resource = buffer->m_resource;
-
- uploadResource->Unmap(0, nullptr);
-
- const D3D12_RESOURCE_STATES initialState = buffer->m_resource.getState();
-
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter);
- buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter);
- }
-
- m_commandList->CopyBufferRegion(resource, 0, uploadResource, 0, buffer->getDesc()->sizeInBytes);
+ D3D12Resource stageBuf;
+ SLANG_RETURN_ON_FAIL(stageBuf.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr));
- {
- D3D12BarrierSubmitter submitter(m_commandList);
- buffer->m_resource.transition(initialState, submitter);
- }
- break;
- }
- case MapFlavor::HostRead:
- {
- break;
- }
- }
- }
- }
-}
-
-#if 0
-void D3D12Renderer::setInputLayout(InputLayout* inputLayout)
-{
- m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
-}
-#endif
-
-void D3D12Renderer::setPrimitiveTopology(PrimitiveTopology topology)
-{
- switch (topology)
- {
- case PrimitiveTopology::TriangleList:
- {
- m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
- m_primitiveTopology = D3DUtil::getPrimitiveTopology(topology);
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- }
- }
-}
-
-void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, IBufferResource*const* buffers, const UInt* strides, const UInt* offsets)
-{
- {
- const Index num = startSlot + slotCount;
- if (num > m_boundVertexBuffers.getCount())
- {
- m_boundVertexBuffers.setCount(num);
- }
- }
-
- for (UInt i = 0; i < slotCount; i++)
- {
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]);
- if (buffer)
- {
- assert(buffer->m_initialUsage == IResource::Usage::VertexBuffer);
- }
-
- BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i];
- boundBuffer.m_buffer = buffer;
- boundBuffer.m_stride = int(strides[i]);
- boundBuffer.m_offset = int(offsets[i]);
- }
-}
-
-void D3D12Renderer::setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset)
-{
- m_boundIndexBuffer = (BufferResourceImpl*) buffer;
- m_boundIndexFormat = D3DUtil::getMapFormat(indexFormat);
- m_boundIndexOffset = UINT(offset);
-}
-
-void D3D12Renderer::setViewports(UInt count, Viewport const* viewports)
-{
- static const int kMaxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
- assert(count <= kMaxViewports && count <= kMaxRTVCount);
- for(UInt 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_commandList->RSSetViewports(UINT(count), m_viewports);
-}
-
-void D3D12Renderer::setScissorRects(UInt count, ScissorRect const* rects)
-{
- static const int kMaxScissorRects = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
- assert(count <= kMaxScissorRects && count <= kMaxRTVCount);
-
- for(UInt 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_commandList->RSSetScissorRects(UINT(count), m_scissorRects);
-}
-
-void D3D12Renderer::setPipelineState(IPipelineState* state)
-{
- m_currentPipelineState = (PipelineStateImpl*)state;
-}
-
-void D3D12Renderer::setFramebuffer(IFramebuffer* frameBuffer)
-{
- ID3D12GraphicsCommandList* commandList = m_commandList;
- auto framebufferImpl = static_cast<FramebufferImpl*>(frameBuffer);
- commandList->OMSetRenderTargets(
- (UINT)framebufferImpl->renderTargetViews.getCount(),
- framebufferImpl->renderTargetDescriptors.getArrayView().getBuffer(),
- FALSE,
- framebufferImpl->depthStencilView ? &framebufferImpl->depthStencilDescriptor : nullptr);
- m_frameBuffer = framebufferImpl;
-}
-
-
-void D3D12Renderer::draw(UInt vertexCount, UInt startVertex)
-{
- ID3D12GraphicsCommandList* commandList = m_commandList;
-
- auto pipelineState = m_currentPipelineState.Ptr();
- if (!pipelineState || (pipelineState->desc.type != PipelineType::Graphics))
- {
- assert(!"No graphics pipeline state set");
- return;
- }
-
- // Submit - setting for graphics
- {
- GraphicsSubmitter submitter(commandList);
- _bindRenderState(pipelineState, commandList, &submitter);
- }
+ // Do the copy
+ encodeInfo.d3dCommandList->CopyBufferRegion(stageBuf, 0, resource, 0, bufferSize);
- commandList->IASetPrimitiveTopology(m_primitiveTopology);
+ // Wait until complete
+ submitResourceCommandsAndWait(encodeInfo);
- // Set up vertex buffer views
+ // Map and copy
+ RefPtr<ListBlob> blob = new ListBlob();
{
- 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 = UINT(boundVertexBuffer.m_stride);
- }
- }
- commandList->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;
-
- commandList->IASetIndexBuffer(&indexBufferView);
- }
-
- commandList->DrawInstanced(UINT(vertexCount), 1, UINT(startVertex), 0);
-}
+ UINT8* data;
+ D3D12_RANGE readRange = { 0, bufferSize };
-void D3D12Renderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
-{
-}
+ SLANG_RETURN_ON_FAIL(stageBuf.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data)));
-void D3D12Renderer::dispatchCompute(int x, int y, int z)
-{
- ID3D12GraphicsCommandList* commandList = m_commandList;
- auto pipelineStateImpl = m_currentPipelineState;
+ // Copy to memory buffer
+ blob->m_data.setCount(bufferSize);
+ ::memcpy(blob->m_data.getBuffer(), data, bufferSize);
- // Submit binding for compute
- {
- ComputeSubmitter submitter(commandList);
- _bindRenderState(pipelineStateImpl, commandList, &submitter);
+ stageBuf.getResource()->Unmap(0, nullptr);
}
-
- commandList->Dispatch(x, y, z);
+ *outBlob = blob.detach();
+ return SLANG_OK;
}
void D3D12Renderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, IBufferResource* buffer)
@@ -2937,22 +3338,6 @@ void D3D12Renderer::DescriptorSetImpl::setRootConstants(
memcpy((char*)m_rootConstantData.getBuffer() + rootConstantRangeInfo.offset + offset, data, size);
}
-void D3D12Renderer::setDescriptorSet(PipelineType pipelineType, IPipelineLayout* layout, UInt index, IDescriptorSet* descriptorSet)
-{
- // In D3D12, unlike Vulkan, binding a root signature invalidates *all* descriptor table
- // bindings (rather than preserving those that are part of the longest common prefix
- // between the old and new layout).
- //
- // In order to accomodate having descriptor-set bindings that persist across changes
- // in pipeline state (which may also change pipeline layout), we will shadow the
- // descriptor-set bindings and only flush them on-demand at draw tiume once the final
- // pipline layout is known.
- //
-
- auto descriptorSetImpl = (DescriptorSetImpl*) descriptorSet;
- m_boundDescriptorSets[int(pipelineType)][index] = descriptorSetImpl;
-}
-
Result D3D12Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
if (desc.slangProgram && desc.slangProgram->getSpecializationParamCount() != 0)
@@ -3656,7 +4041,7 @@ Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes
psoDesc.PS = { programImpl->m_pixelShader .getBuffer(), SIZE_T(programImpl->m_pixelShader .getCount()) };
psoDesc.InputLayout = { inputLayoutImpl->m_elements.getBuffer(), UINT(inputLayoutImpl->m_elements.getCount()) };
- psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
+ psoDesc.PrimitiveTopologyType = D3DUtil::getPrimitiveType(desc.primitiveType);
{
auto framebufferLayout = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout);
@@ -3720,30 +4105,24 @@ Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes
{
auto& ds = psoDesc.DepthStencilState;
- ds.DepthEnable = FALSE;
- ds.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
- ds.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
- //ds.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
- ds.StencilEnable = FALSE;
- ds.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
- ds.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
- const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
- {
- D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS
- };
- ds.FrontFace = defaultStencilOp;
- ds.BackFace = defaultStencilOp;
+ ds.DepthEnable = inDesc.depthStencil.depthTestEnable;
+ ds.DepthWriteMask = inDesc.depthStencil.depthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL
+ : D3D12_DEPTH_WRITE_MASK_ZERO;
+ ds.DepthFunc = D3DUtil::getComparisonFunc(inDesc.depthStencil.depthFunc);
+ ds.StencilEnable = inDesc.depthStencil.stencilEnable;
+ ds.StencilReadMask = (UINT8)inDesc.depthStencil.stencilReadMask;
+ ds.StencilWriteMask = (UINT8)inDesc.depthStencil.stencilWriteMask;
+ ds.FrontFace = D3DUtil::translateStencilOpDesc(inDesc.depthStencil.frontFace);
+ ds.BackFace = D3DUtil::translateStencilOpDesc(inDesc.depthStencil.backFace);
}
- psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
+ psoDesc.PrimitiveTopologyType = D3DUtil::getPrimitiveType(desc.primitiveType);
ComPtr<ID3D12PipelineState> pipelineState;
SLANG_RETURN_ON_FAIL(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(pipelineState.writeRef())));
RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
- pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
pipelineStateImpl->m_pipelineState = pipelineState;
- pipelineStateImpl->m_program = programImpl;
pipelineStateImpl->init(desc);
*outState = pipelineStateImpl.detach();
return SLANG_OK;
@@ -3806,7 +4185,6 @@ Result D3D12Renderer::createComputePipelineState(const ComputePipelineStateDesc&
}
}
RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
- pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
pipelineStateImpl->m_pipelineState = pipelineState;
pipelineStateImpl->init(desc);
*outState = pipelineStateImpl.detach();