diff options
| author | Yong He <yonghe@outlook.com> | 2021-03-04 16:25:58 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-04 16:25:58 -0800 |
| commit | a5ac4999b4dea546a7ef824669ab1809224b6448 (patch) | |
| tree | 15bb22eb98a94f7f81489deef55396461501d3dc /tools/gfx/immediate-renderer-base.cpp | |
| parent | 13ff0bd345990c0fdfb7b52ebd5339cddb04889e (diff) | |
Refactor `gfx` to surface `CommandBuffer` interface. (#1735)
* Refactor `gfx` to surface `CommandBuffer` interface.
* Fixes.
* Fix code review issues, and make vulkan runnable on devices without VK_EXT_extended_dynamic_states.
* Update solution files
* Move out-of-date examples to examples/experimental
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'tools/gfx/immediate-renderer-base.cpp')
| -rw-r--r-- | tools/gfx/immediate-renderer-base.cpp | 551 |
1 files changed, 551 insertions, 0 deletions
diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp new file mode 100644 index 000000000..36d98f957 --- /dev/null +++ b/tools/gfx/immediate-renderer-base.cpp @@ -0,0 +1,551 @@ +#include "immediate-renderer-base.h" +#include "simple-render-pass-layout.h" +#include "command-writer.h" +#include "core/slang-basic.h" +#include "core/slang-blob.h" + +namespace gfx +{ +using Slang::RefPtr; +using Slang::List; +using Slang::ShortList; +using Slang::ListBlob; +using Slang::Index; +using Slang::RefObject; +using Slang::ComPtr; +using Slang::Guid; + +namespace +{ + +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: + CommandWriter m_writer; + ImmediateRendererBase* m_renderer; + + void init(ImmediateRendererBase* renderer) + { + m_renderer = renderer; + } + + void reset() + { m_writer.clear(); + } + + class RenderCommandEncoderImpl + : public IRenderCommandEncoder + { + 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: + CommandWriter* m_writer; + virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override {} + + void init(CommandBufferImpl* cmdBuffer, SimpleRenderPassLayout* renderPass, IFramebuffer* framebuffer) + { + m_writer = &cmdBuffer->m_writer; + + // Encode clear commands. + m_writer->setFramebuffer(framebuffer); + uint32_t clearMask = 0; + for (Index i = 0; i < renderPass->m_renderTargetAccesses.getCount(); i++) + { + auto& access = renderPass->m_renderTargetAccesses[i]; + // Clear. + if (access.loadOp == IRenderPassLayout::AttachmentLoadOp::Clear) + { + clearMask |= (1 << (uint32_t)i); + } + } + bool clearDepth = false; + bool clearStencil = false; + if (renderPass->m_hasDepthStencil) + { + // Clear. + if (renderPass->m_depthStencilAccess.loadOp == + IRenderPassLayout::AttachmentLoadOp::Clear) + { + clearDepth = true; + } + if (renderPass->m_depthStencilAccess.stencilLoadOp == + IRenderPassLayout::AttachmentLoadOp::Clear) + { + clearStencil = true; + } + } + m_writer->clearFrame(clearMask, clearDepth, clearStencil); + } + + virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) + { + m_writer->setPipelineState(state); + } + + virtual SLANG_NO_THROW void SLANG_MCALL + bindRootShaderObject(IShaderObject* object) + { + m_writer->bindRootShaderObject(PipelineType::Graphics, object); + } + + virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet( + IPipelineLayout* layout, + UInt index, + IDescriptorSet* descriptorSet) + { + m_writer->setDescriptorSet(PipelineType::Graphics, layout, index, descriptorSet); + } + + virtual SLANG_NO_THROW void SLANG_MCALL + setViewports(uint32_t count, const Viewport* viewports) + { + m_writer->setViewports(count, viewports); + } + virtual SLANG_NO_THROW void SLANG_MCALL + setScissorRects(uint32_t count, const ScissorRect* scissors) + { + m_writer->setScissorRects(count, scissors); + } + virtual SLANG_NO_THROW void SLANG_MCALL setPrimitiveTopology(PrimitiveTopology topology) + { + m_writer->setPrimitiveTopology(topology); + } + virtual SLANG_NO_THROW void SLANG_MCALL setVertexBuffers( + UInt startSlot, + UInt slotCount, + IBufferResource* const* buffers, + const UInt* strides, + const UInt* offsets) + { + m_writer->setVertexBuffers(startSlot, slotCount, buffers, strides, offsets); + } + + virtual SLANG_NO_THROW void SLANG_MCALL + setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) + { + m_writer->setIndexBuffer(buffer, indexFormat, offset); + } + + virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex) + { + m_writer->draw(vertexCount, startVertex); + } + + virtual SLANG_NO_THROW void SLANG_MCALL + drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) + { + m_writer->drawIndexed(indexCount, startIndex, baseVertex); + } + + virtual SLANG_NO_THROW void SLANG_MCALL setStencilReference(uint32_t referenceValue) + { + m_writer->setStencilReference(referenceValue); + } + }; + + RenderCommandEncoderImpl m_renderCommandEncoder; + virtual SLANG_NO_THROW void SLANG_MCALL encodeRenderCommands( + IRenderPassLayout* renderPass, + IFramebuffer* framebuffer, + IRenderCommandEncoder** outEncoder) override + { + m_renderCommandEncoder.init( + this, + static_cast<SimpleRenderPassLayout*>(renderPass), + framebuffer); + *outEncoder = &m_renderCommandEncoder; + } + + class ComputeCommandEncoderImpl + : public IComputeCommandEncoder + { + 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: + CommandWriter* m_writer; + + virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override + { + } + + void init(CommandBufferImpl* cmdBuffer) + { + m_writer = &cmdBuffer->m_writer; + } + + virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) override + { + m_writer->setPipelineState(state); + } + virtual SLANG_NO_THROW void SLANG_MCALL + bindRootShaderObject(IShaderObject* object) override + { + m_writer->bindRootShaderObject(PipelineType::Compute, object); + } + + virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet( + IPipelineLayout* layout, + UInt index, + IDescriptorSet* descriptorSet) override + { + m_writer->setDescriptorSet(PipelineType::Compute, layout, index, descriptorSet); + } + + virtual SLANG_NO_THROW void SLANG_MCALL dispatchCompute(int x, int y, int z) override + { + m_writer->dispatchCompute(x, y, z); + } + }; + + ComputeCommandEncoderImpl m_computeCommandEncoder; + virtual SLANG_NO_THROW void SLANG_MCALL + encodeComputeCommands(IComputeCommandEncoder** outEncoder) override + { + m_computeCommandEncoder.init(this); + *outEncoder = &m_computeCommandEncoder; + } + + 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; } + + public: + CommandWriter* m_writer; + + void init(CommandBufferImpl* cmdBuffer) + { + m_writer = &cmdBuffer->m_writer; + } + + virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override {} + virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer( + IBufferResource* dst, + size_t dstOffset, + IBufferResource* src, + size_t srcOffset, + size_t size) override + { + m_writer->copyBuffer(dst, dstOffset, src, srcOffset, size); + } + + virtual SLANG_NO_THROW void SLANG_MCALL + uploadBufferData(IBufferResource* dst, size_t offset, size_t size, void* data) + { + m_writer->uploadBufferData(dst, offset, size, data); + } + }; + + ResourceCommandEncoderImpl m_resourceCommandEncoder; + + virtual SLANG_NO_THROW void SLANG_MCALL + encodeResourceCommands(IResourceCommandEncoder** outEncoder) override + { + m_resourceCommandEncoder.init(this); + *outEncoder = &m_resourceCommandEncoder; + } + + virtual SLANG_NO_THROW void SLANG_MCALL close() override { } + + void execute() + { + for (auto& cmd : m_writer.m_commands) + { + auto name = cmd.name; + switch (name) + { + case CommandName::SetPipelineState: + m_renderer->_setPipelineState(m_writer.getObject<IPipelineState>(cmd.operands[0])); + break; + case CommandName::BindRootShaderObject: + m_renderer->bindRootShaderObject( + (PipelineType)cmd.operands[0], + m_writer.getObject<IShaderObject>(cmd.operands[1])); + break; + case CommandName::SetDescriptorSet: + m_renderer->setDescriptorSet( + (gfx::PipelineType)cmd.operands[0], + m_writer.getObject<IPipelineLayout>(cmd.operands[1]), + (UInt)cmd.operands[2], + m_writer.getObject<IDescriptorSet>(cmd.operands[3])); + break; + case CommandName::SetFramebuffer: + m_renderer->setFramebuffer(m_writer.getObject<IFramebuffer>(cmd.operands[0])); + break; + case CommandName::ClearFrame: + m_renderer->clearFrame( + cmd.operands[0], (cmd.operands[1] != 0), (cmd.operands[2] != 0)); + break; + case CommandName::SetViewports: + m_renderer->setViewports( + (UInt)cmd.operands[0], m_writer.getData<Viewport>(cmd.operands[1])); + break; + case CommandName::SetScissorRects: + m_renderer->setScissorRects( + (UInt)cmd.operands[0], m_writer.getData<ScissorRect>(cmd.operands[1])); + break; + case CommandName::SetPrimitiveTopology: + m_renderer->setPrimitiveTopology((PrimitiveTopology)cmd.operands[0]); + break; + case CommandName::SetVertexBuffers: + { + ShortList<IBufferResource*> bufferResources; + for (uint32_t i = 0; i < cmd.operands[1]; i++) + { + bufferResources.add( + m_writer.getObject<IBufferResource>(cmd.operands[2] + i)); + } + m_renderer->setVertexBuffers( + (UInt)cmd.operands[0], + (UInt)cmd.operands[1], + bufferResources.getArrayView().getBuffer(), + m_writer.getData<UInt>(cmd.operands[3]), + m_writer.getData<UInt>(cmd.operands[4])); + } + break; + case CommandName::SetIndexBuffer: + m_renderer->setIndexBuffer( + m_writer.getObject<IBufferResource>(cmd.operands[0]), + (Format)cmd.operands[1], + (UInt)cmd.operands[2]); + break; + case CommandName::Draw: + m_renderer->draw((UInt)cmd.operands[0], (UInt)cmd.operands[1]); + break; + case CommandName::DrawIndexed: + m_renderer->drawIndexed( + (UInt)cmd.operands[0], (UInt)cmd.operands[1], (UInt)cmd.operands[2]); + break; + case CommandName::SetStencilReference: + m_renderer->setStencilReference(cmd.operands[0]); + break; + case CommandName::DispatchCompute: + m_renderer->dispatchCompute( + int(cmd.operands[0]), int(cmd.operands[1]), int(cmd.operands[2])); + break; + case CommandName::UploadBufferData: + m_renderer->uploadBufferData( + m_writer.getObject<IBufferResource>(cmd.operands[0]), + cmd.operands[1], + cmd.operands[2], + m_writer.getData<uint8_t>(cmd.operands[3])); + break; + case CommandName::CopyBuffer: + m_renderer->copyBuffer( + m_writer.getObject<IBufferResource>(cmd.operands[0]), + cmd.operands[1], + m_writer.getObject<IBufferResource>(cmd.operands[2]), + cmd.operands[3], + cmd.operands[4]); + break; + default: + assert(!"unknown command"); + break; + } + } + m_writer.clear(); + } +}; + +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: + ImmediateRendererBase* m_renderer; + ICommandQueue::Desc m_desc; + + CommandQueueImpl(ImmediateRendererBase* renderer) + : m_renderer(renderer) + { + m_desc.type = ICommandQueue::QueueType::Graphics; + } + + ~CommandQueueImpl() + { + m_renderer->m_queueCreateCount--; + } + + 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> newCmdBuffer = new CommandBufferImpl(); + newCmdBuffer->init(m_renderer); + *outCommandBuffer = newCmdBuffer.detach(); + return SLANG_OK; + } + + virtual SLANG_NO_THROW void SLANG_MCALL + executeCommandBuffers(uint32_t count, ICommandBuffer* const* commandBuffers) override + { + for (uint32_t i = 0; i < count; i++) + { + static_cast<CommandBufferImpl*>(commandBuffers[i])->execute(); + } + } + + virtual SLANG_NO_THROW void SLANG_MCALL wait() override + { + m_renderer->waitForGpu(); + } +}; +} + + +ImmediateRendererBase::ImmediateRendererBase() { + m_queue = new CommandQueueImpl(this); +} + +void ImmediateRendererBase::bindRootShaderObject(PipelineType pipelineType, IShaderObject* shaderObject) +{ + class ImmediateCommandEncoder : public GraphicsComputeCommandEncoderBase + { + public: + virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSetImpl( + PipelineType pipelineType, + IPipelineLayout* layout, + UInt index, + IDescriptorSet* descriptorSet) override + { + auto renderer = static_cast<ImmediateRendererBase*>(m_rendererBase); + renderer->setDescriptorSet(pipelineType, layout, index, descriptorSet); + } + + virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferDataImpl( + IBufferResource* buffer, + size_t offset, + size_t size, + void* data) override + { + auto renderer = static_cast<ImmediateRendererBase*>(m_rendererBase); + renderer->uploadBufferData(buffer, offset, size, data); + } + }; + ImmediateCommandEncoder encoder; + encoder.m_rendererBase = this; + encoder.m_currentPipeline = static_cast<PipelineStateBase*>(m_currentPipelineState.get()); + encoder.bindRootShaderObjectImpl(pipelineType, shaderObject); + _setPipelineState(encoder.m_currentPipeline); +} + +SLANG_NO_THROW Result SLANG_MCALL ImmediateRendererBase::createCommandQueue( + const ICommandQueue::Desc& desc, + ICommandQueue** outQueue) +{ + SLANG_UNUSED(desc); + // Only one queue is supported. + if (m_queueCreateCount != 0) + return SLANG_FAIL; + *outQueue = m_queue.get(); + m_queue->addRef(); + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL ImmediateRendererBase::createRenderPassLayout( + const IRenderPassLayout::Desc& desc, + IRenderPassLayout** outRenderPassLayout) +{ + RefPtr<SimpleRenderPassLayout> renderPass = new SimpleRenderPassLayout(); + renderPass->init(desc); + *outRenderPassLayout = renderPass.detach(); + return SLANG_OK; +} + +void ImmediateRendererBase::_setPipelineState(IPipelineState* state) +{ + PipelineStateBase* pipelineImpl = static_cast<PipelineStateBase*>(state); + if (!pipelineImpl->isSpecializable) + { + setPipelineState(state); + } + m_currentPipelineState = state; +} + +void ImmediateRendererBase::uploadBufferData( + IBufferResource* dst, + size_t offset, + size_t size, + void* data) +{ + auto buffer = map(dst, gfx::MapFlavor::WriteDiscard); + memcpy((uint8_t*)buffer + offset, data, size); + unmap(dst); +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ImmediateRendererBase::readBufferResource( + IBufferResource* buffer, + size_t offset, + size_t size, + ISlangBlob** outBlob) +{ + RefPtr<ListBlob> blob = new ListBlob(); + blob->m_data.setCount((Index)size); + auto content = (uint8_t*)map(buffer, gfx::MapFlavor::HostRead); + if (!content) + return SLANG_FAIL; + memcpy(blob->m_data.getBuffer(), content + offset, size); + unmap(buffer); + *outBlob = blob.detach(); + return SLANG_OK; +} + +} |
