diff options
25 files changed, 2048 insertions, 1443 deletions
diff --git a/build/visual-studio/gfx/gfx.vcxproj b/build/visual-studio/gfx/gfx.vcxproj index 25a48c339..18cc24f13 100644 --- a/build/visual-studio/gfx/gfx.vcxproj +++ b/build/visual-studio/gfx/gfx.vcxproj @@ -302,7 +302,17 @@ <ClInclude Include="..\..\..\slang-gfx.h" />
<ClInclude Include="..\..\..\tools\gfx\command-encoder-com-forward.h" />
<ClInclude Include="..\..\..\tools\gfx\command-writer.h" />
- <ClInclude Include="..\..\..\tools\gfx\cpu\render-cpu.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-base.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-buffer.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-device.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-helper-functions.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-pipeline-state.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-query.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-resource-views.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-object-layout.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-object.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-program.h" />
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-texture.h" />
<ClInclude Include="..\..\..\tools\gfx\cuda\cuda-base.h" />
<ClInclude Include="..\..\..\tools\gfx\cuda\cuda-buffer.h" />
<ClInclude Include="..\..\..\tools\gfx\cuda\cuda-command-buffer.h" />
@@ -403,7 +413,15 @@ <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-vertex-layout.h" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\..\..\tools\gfx\cpu\render-cpu.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-buffer.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-device.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-helper-functions.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-pipeline-state.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-query.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-resource-views.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-shader-object-layout.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-shader-object.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-texture.cpp" />
<ClCompile Include="..\..\..\tools\gfx\cuda\cuda-buffer.cpp" />
<ClCompile Include="..\..\..\tools\gfx\cuda\cuda-command-buffer.cpp" />
<ClCompile Include="..\..\..\tools\gfx\cuda\cuda-command-encoder.cpp" />
diff --git a/build/visual-studio/gfx/gfx.vcxproj.filters b/build/visual-studio/gfx/gfx.vcxproj.filters index 61708be0b..2017ff04b 100644 --- a/build/visual-studio/gfx/gfx.vcxproj.filters +++ b/build/visual-studio/gfx/gfx.vcxproj.filters @@ -18,7 +18,37 @@ <ClInclude Include="..\..\..\tools\gfx\command-writer.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\..\..\tools\gfx\cpu\render-cpu.h">
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-base.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-buffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-device.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-helper-functions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-pipeline-state.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-query.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-resource-views.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-object-layout.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-object.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-shader-program.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\cpu\cpu-texture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\tools\gfx\cuda\cuda-base.h">
@@ -317,7 +347,31 @@ </ClInclude>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\..\..\tools\gfx\cpu\render-cpu.cpp">
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-buffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-helper-functions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-pipeline-state.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-query.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-resource-views.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-shader-object-layout.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-shader-object.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\cpu\cpu-texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\tools\gfx\cuda\cuda-buffer.cpp">
diff --git a/tools/gfx/cpu/cpu-base.h b/tools/gfx/cpu/cpu-base.h new file mode 100644 index 000000000..4629686b7 --- /dev/null +++ b/tools/gfx/cpu/cpu-base.h @@ -0,0 +1,42 @@ +// cpu-base.h +// Shared header file for CPU implementation +#pragma once + +#include <chrono> + +#include "slang.h" +#include "slang-com-ptr.h" +#include "slang-com-helper.h" +#include "core/slang-basic.h" +#include "core/slang-blob.h" + +#include "../immediate-renderer-base.h" +#include "../slang-context.h" +#include "../mutable-shader-object.h" +#define SLANG_PRELUDE_NAMESPACE slang_prelude +#include "prelude/slang-cpp-types.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + class BufferResourceImpl; + class TextureResourceImpl; + class ResourceViewImpl; + class BufferResourceViewImpl; + class TextureResourceViewImpl; + class ShaderObjectLayoutImpl; + class EntryPointLayoutImpl; + class RootShaderObjectLayoutImpl; + class ShaderObjectImpl; + class MutableShaderObjectImpl; + class EntryPointShaderObjectImpl; + class RootShaderObjectImpl; + class ShaderProgramImpl; + class PipelineStateImpl; + class QueryPoolImpl; + class DeviceImpl; +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-buffer.cpp b/tools/gfx/cpu/cpu-buffer.cpp new file mode 100644 index 000000000..2c9c3077d --- /dev/null +++ b/tools/gfx/cpu/cpu-buffer.cpp @@ -0,0 +1,54 @@ +// cpu-buffer.cpp +#include "cpu-buffer.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +BufferResourceImpl::~BufferResourceImpl() +{ + if (m_data) + { + free(m_data); + } +} + +Result BufferResourceImpl::init() +{ + m_data = malloc(m_desc.sizeInBytes); + if (!m_data) + return SLANG_E_OUT_OF_MEMORY; + return SLANG_OK; +} + +Result BufferResourceImpl::setData(size_t offset, size_t size, void const* data) +{ + memcpy((char*)m_data + offset, data, size); + return SLANG_OK; +} + +SLANG_NO_THROW DeviceAddress SLANG_MCALL BufferResourceImpl::getDeviceAddress() +{ + return (DeviceAddress)m_data; +} + +SLANG_NO_THROW Result SLANG_MCALL + BufferResourceImpl::map(MemoryRange* rangeToRead, void** outPointer) +{ + SLANG_UNUSED(rangeToRead); + if (outPointer) + *outPointer = m_data; + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL BufferResourceImpl::unmap(MemoryRange* writtenRange) +{ + SLANG_UNUSED(writtenRange); + return SLANG_OK; +} + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-buffer.h b/tools/gfx/cpu/cpu-buffer.h new file mode 100644 index 000000000..6273b18b9 --- /dev/null +++ b/tools/gfx/cpu/cpu-buffer.h @@ -0,0 +1,36 @@ +// cpu-buffer.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class BufferResourceImpl : public BufferResource +{ +public: + BufferResourceImpl(const Desc& _desc) + : BufferResource(_desc) + {} + + ~BufferResourceImpl(); + + Result init(); + + Result setData(size_t offset, size_t size, void const* data); + + void* m_data = nullptr; + + virtual SLANG_NO_THROW DeviceAddress SLANG_MCALL getDeviceAddress() override; + + virtual SLANG_NO_THROW Result SLANG_MCALL + map(MemoryRange* rangeToRead, void** outPointer) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL unmap(MemoryRange* writtenRange) override; +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-device.cpp b/tools/gfx/cpu/cpu-device.cpp new file mode 100644 index 000000000..92c08ef71 --- /dev/null +++ b/tools/gfx/cpu/cpu-device.cpp @@ -0,0 +1,293 @@ +// cpu-device.cpp +#include "cpu-device.h" + +#include "cpu-buffer.h" +#include "cpu-pipeline-state.h" +#include "cpu-query.h" +#include "cpu-resource-views.h" +#include "cpu-shader-object.h" +#include "cpu-shader-program.h" +#include "cpu-texture.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + DeviceImpl::~DeviceImpl() + { + m_currentPipeline = nullptr; + m_currentRootObject = nullptr; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::initialize(const Desc& desc) + { + SLANG_RETURN_ON_FAIL(slangContext.initialize( + desc.slang, + SLANG_SHADER_HOST_CALLABLE, + "sm_5_1", + makeArray(slang::PreprocessorMacroDesc{ "__CPU__", "1" }).getView())); + + SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc)); + + // Initialize DeviceInfo + { + m_info.deviceType = DeviceType::CPU; + m_info.bindingStyle = BindingStyle::CUDA; + m_info.projectionStyle = ProjectionStyle::DirectX; + m_info.apiName = "CPU"; + static const float kIdentity[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity)); + m_info.adapterName = "CPU"; + m_info.timestampFrequency = 1000000000; + } + + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createTextureResource( + const ITextureResource::Desc& desc, + const ITextureResource::SubresourceData* initData, + ITextureResource** outResource) + { + TextureResource::Desc srcDesc = fixupTextureDesc(desc); + + RefPtr<TextureResourceImpl> texture = new TextureResourceImpl(srcDesc); + + SLANG_RETURN_ON_FAIL(texture->init(initData)); + + returnComPtr(outResource, texture); + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createBufferResource( + const IBufferResource::Desc& descIn, + const void* initData, + IBufferResource** outResource) + { + auto desc = fixupBufferDesc(descIn); + RefPtr<BufferResourceImpl> resource = new BufferResourceImpl(desc); + SLANG_RETURN_ON_FAIL(resource->init()); + if (initData) + { + SLANG_RETURN_ON_FAIL(resource->setData(0, desc.sizeInBytes, initData)); + } + returnComPtr(outResource, resource); + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createTextureView( + ITextureResource* inTexture, IResourceView::Desc const& desc, IResourceView** outView) + { + auto texture = static_cast<TextureResourceImpl*>(inTexture); + RefPtr<TextureResourceViewImpl> view = new TextureResourceViewImpl(desc, texture); + returnComPtr(outView, view); + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createBufferView( + IBufferResource* inBuffer, + IBufferResource* counterBuffer, + IResourceView::Desc const& desc, + IResourceView** outView) + { + auto buffer = static_cast<BufferResourceImpl*>(inBuffer); + RefPtr<BufferResourceViewImpl> view = new BufferResourceViewImpl(desc, buffer); + returnComPtr(outView, view); + return SLANG_OK; + } + + Result DeviceImpl::createShaderObjectLayout( + slang::TypeLayoutReflection* typeLayout, + ShaderObjectLayoutBase** outLayout) + { + RefPtr<ShaderObjectLayoutImpl> cpuLayout = new ShaderObjectLayoutImpl(this, typeLayout); + returnRefPtrMove(outLayout, cpuLayout); + + return SLANG_OK; + } + + Result DeviceImpl::createShaderObject( + ShaderObjectLayoutBase* layout, + IShaderObject** outObject) + { + auto cpuLayout = static_cast<ShaderObjectLayoutImpl*>(layout); + + RefPtr<ShaderObjectImpl> result = new ShaderObjectImpl(); + SLANG_RETURN_ON_FAIL(result->init(this, cpuLayout)); + returnComPtr(outObject, result); + + return SLANG_OK; + } + + Result DeviceImpl::createMutableShaderObject( + ShaderObjectLayoutBase* layout, + IShaderObject** outObject) + { + auto cpuLayout = static_cast<ShaderObjectLayoutImpl*>(layout); + + RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl(); + SLANG_RETURN_ON_FAIL(result->init(this, cpuLayout)); + returnComPtr(outObject, result); + + return SLANG_OK; + } + + Result DeviceImpl::createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject) + { + auto cpuProgram = static_cast<ShaderProgramImpl*>(program); + auto cpuProgramLayout = cpuProgram->layout; + + RefPtr<RootShaderObjectImpl> result = new RootShaderObjectImpl(); + SLANG_RETURN_ON_FAIL(result->init(this, cpuProgramLayout)); + returnRefPtrMove(outObject, result); + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createProgram( + const IShaderProgram::Desc& desc, + IShaderProgram** outProgram, + ISlangBlob** outDiagnosticBlob) + { + RefPtr<ShaderProgramImpl> cpuProgram = new ShaderProgramImpl(); + cpuProgram->init(desc); + auto slangGlobalScope = cpuProgram->linkedProgram; + if (slangGlobalScope) + { + auto slangProgramLayout = slangGlobalScope->getLayout(); + if (!slangProgramLayout) + return SLANG_FAIL; + + RefPtr<RootShaderObjectLayoutImpl> cpuProgramLayout = new RootShaderObjectLayoutImpl(this, slangProgramLayout); + cpuProgramLayout->m_programLayout = slangProgramLayout; + + cpuProgram->layout = cpuProgramLayout; + } + + returnComPtr(outProgram, cpuProgram); + return SLANG_OK; + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createComputePipelineState( + const ComputePipelineStateDesc& desc, IPipelineState** outState) + { + RefPtr<PipelineStateImpl> state = new PipelineStateImpl(); + state->init(desc); + returnComPtr(outState, state); + return Result(); + } + + SLANG_NO_THROW Result SLANG_MCALL DeviceImpl::createQueryPool( + const IQueryPool::Desc& desc, IQueryPool** outPool) + { + RefPtr<QueryPoolImpl> pool = new QueryPoolImpl(); + pool->init(desc); + returnComPtr(outPool, pool); + return SLANG_OK; + } + + void DeviceImpl::writeTimestamp(IQueryPool* pool, GfxIndex index) + { + static_cast<QueryPoolImpl*>(pool)->m_queries[index] = + std::chrono::high_resolution_clock::now().time_since_epoch().count(); + } + + SLANG_NO_THROW const DeviceInfo& SLANG_MCALL DeviceImpl::getDeviceInfo() const + { + return m_info; + } + + SLANG_NO_THROW Result SLANG_MCALL + DeviceImpl::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) + { + SLANG_UNUSED(desc); + *outSampler = nullptr; + return SLANG_OK; + } + + void* DeviceImpl::map(IBufferResource* buffer, MapFlavor flavor) + { + SLANG_UNUSED(flavor); + auto bufferImpl = static_cast<BufferResourceImpl*>(buffer); + return bufferImpl->m_data; + } + void DeviceImpl::unmap(IBufferResource* buffer, size_t offsetWritten, size_t sizeWritten) + { + SLANG_UNUSED(buffer); + SLANG_UNUSED(offsetWritten); + SLANG_UNUSED(sizeWritten); + } + + void DeviceImpl::setPipelineState(IPipelineState* state) + { + m_currentPipeline = static_cast<PipelineStateImpl*>(state); + } + + void DeviceImpl::bindRootShaderObject(IShaderObject* object) + { + m_currentRootObject = static_cast<RootShaderObjectImpl*>(object); + } + + void DeviceImpl::dispatchCompute(int x, int y, int z) + { + int entryPointIndex = 0; + int targetIndex = 0; + + // Specialize the compute kernel based on the shader object bindings. + RefPtr<PipelineStateBase> newPipeline; + maybeSpecializePipeline(m_currentPipeline, m_currentRootObject, newPipeline); + m_currentPipeline = static_cast<PipelineStateImpl*>(newPipeline.Ptr()); + + auto program = m_currentPipeline->getProgram(); + auto entryPointLayout = + m_currentRootObject->getLayout()->getEntryPoint(entryPointIndex); + auto entryPointName = entryPointLayout->getEntryPointName(); + + auto entryPointObject = m_currentRootObject->getEntryPoint(entryPointIndex); + + ComPtr<ISlangSharedLibrary> sharedLibrary; + ComPtr<ISlangBlob> diagnostics; + auto compileResult = program->slangGlobalScope->getEntryPointHostCallable( + entryPointIndex, targetIndex, sharedLibrary.writeRef(), diagnostics.writeRef()); + if (diagnostics) + { + getDebugCallback()->handleMessage( + compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error, + DebugMessageSource::Slang, + (char*)diagnostics->getBufferPointer()); + } + if (SLANG_FAILED(compileResult)) return; + + auto func = (slang_prelude::ComputeFunc)sharedLibrary->findSymbolAddressByName(entryPointName); + + slang_prelude::ComputeVaryingInput varyingInput; + varyingInput.startGroupID.x = 0; + varyingInput.startGroupID.y = 0; + varyingInput.startGroupID.z = 0; + varyingInput.endGroupID.x = x; + varyingInput.endGroupID.y = y; + varyingInput.endGroupID.z = z; + + auto globalParamsData = m_currentRootObject->getDataBuffer(); + auto entryPointParamsData = entryPointObject->getDataBuffer(); + func(&varyingInput, entryPointParamsData, globalParamsData); + } + + void DeviceImpl::copyBuffer( + IBufferResource* dst, + size_t dstOffset, + IBufferResource* src, + size_t srcOffset, + size_t size) + { + auto dstImpl = static_cast<BufferResourceImpl*>(dst); + auto srcImpl = static_cast<BufferResourceImpl*>(src); + memcpy( + (uint8_t*)dstImpl->m_data + dstOffset, + (uint8_t*)srcImpl->m_data + srcOffset, + size); + } + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-device.h b/tools/gfx/cpu/cpu-device.h new file mode 100644 index 000000000..d216eb0be --- /dev/null +++ b/tools/gfx/cpu/cpu-device.h @@ -0,0 +1,98 @@ +// cpu-device.h +#pragma once +#include "cpu-base.h" + +#include "cpu-pipeline-state.h" +#include "cpu-shader-object.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class DeviceImpl : public ImmediateComputeDeviceBase +{ +public: + ~DeviceImpl(); + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( + const ITextureResource::Desc& desc, + const ITextureResource::SubresourceData* initData, + ITextureResource** outResource) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource( + const IBufferResource::Desc& descIn, + const void* initData, + IBufferResource** outResource) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView( + ITextureResource* inTexture, IResourceView::Desc const& desc, IResourceView** outView) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView( + IBufferResource* inBuffer, + IBufferResource* counterBuffer, + IResourceView::Desc const& desc, + IResourceView** outView) override; + + virtual Result createShaderObjectLayout( + slang::TypeLayoutReflection* typeLayout, + ShaderObjectLayoutBase** outLayout) override; + + virtual Result createShaderObject( + ShaderObjectLayoutBase* layout, + IShaderObject** outObject) override; + + virtual Result createMutableShaderObject( + ShaderObjectLayoutBase* layout, + IShaderObject** outObject) override; + + virtual Result createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createProgram( + const IShaderProgram::Desc& desc, + IShaderProgram** outProgram, + ISlangBlob** outDiagnosticBlob) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( + const ComputePipelineStateDesc& desc, IPipelineState** outState) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL createQueryPool( + const IQueryPool::Desc& desc, IQueryPool** outPool) override; + + virtual void writeTimestamp(IQueryPool* pool, GfxIndex index) override; + + virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const override; + + virtual SLANG_NO_THROW Result SLANG_MCALL + createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) override; + + virtual void submitGpuWork() override {} + virtual void waitForGpu() override {} + virtual void* map(IBufferResource* buffer, MapFlavor flavor) override; + virtual void unmap(IBufferResource* buffer, size_t offsetWritten, size_t sizeWritten) override; + +private: + RefPtr<PipelineStateImpl> m_currentPipeline = nullptr; + RefPtr<RootShaderObjectImpl> m_currentRootObject = nullptr; + DeviceInfo m_info; + + virtual void setPipelineState(IPipelineState* state) override; + + virtual void bindRootShaderObject(IShaderObject* object) override; + + virtual void dispatchCompute(int x, int y, int z) override; + + virtual void copyBuffer( + IBufferResource* dst, + size_t dstOffset, + IBufferResource* src, + size_t srcOffset, + size_t size) override; +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-helper-functions.cpp b/tools/gfx/cpu/cpu-helper-functions.cpp new file mode 100644 index 000000000..1aa9d82eb --- /dev/null +++ b/tools/gfx/cpu/cpu-helper-functions.cpp @@ -0,0 +1,18 @@ +// cpu-helper-functions.cpp +#include "cpu-helper-functions.h" + +#include "cpu-device.h" + +namespace gfx +{ +using namespace Slang; + +Result SLANG_MCALL createCPUDevice(const IDevice::Desc* desc, IDevice** outDevice) +{ + RefPtr<cpu::DeviceImpl> result = new cpu::DeviceImpl(); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); + returnComPtr(outDevice, result); + return SLANG_OK; +} + +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-helper-functions.h b/tools/gfx/cpu/cpu-helper-functions.h new file mode 100644 index 000000000..1f122b750 --- /dev/null +++ b/tools/gfx/cpu/cpu-helper-functions.h @@ -0,0 +1,11 @@ +// cpu-helper-functions.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +Result SLANG_MCALL createCPUDevice(const IDevice::Desc* desc, IDevice** outDevice); + +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-pipeline-state.cpp b/tools/gfx/cpu/cpu-pipeline-state.cpp new file mode 100644 index 000000000..7d2b6a636 --- /dev/null +++ b/tools/gfx/cpu/cpu-pipeline-state.cpp @@ -0,0 +1,27 @@ +// cpu-pipeline-state.cpp +#include "cpu-pipeline-state.h" + +#include "cpu-shader-program.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + + ShaderProgramImpl* PipelineStateImpl::getProgram() + { + return static_cast<ShaderProgramImpl*>(m_program.Ptr()); + } + + void PipelineStateImpl::init(const ComputePipelineStateDesc& inDesc) + { + PipelineStateDesc pipelineDesc; + pipelineDesc.type = PipelineType::Compute; + pipelineDesc.compute = inDesc; + initializeBase(pipelineDesc); + } + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-pipeline-state.h b/tools/gfx/cpu/cpu-pipeline-state.h new file mode 100644 index 000000000..e5eb41c7c --- /dev/null +++ b/tools/gfx/cpu/cpu-pipeline-state.h @@ -0,0 +1,21 @@ +// cpu-pipeline-state.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class PipelineStateImpl : public PipelineStateBase +{ +public: + ShaderProgramImpl* getProgram(); + + void init(const ComputePipelineStateDesc& inDesc); +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-query.cpp b/tools/gfx/cpu/cpu-query.cpp new file mode 100644 index 000000000..3f87d7a65 --- /dev/null +++ b/tools/gfx/cpu/cpu-query.cpp @@ -0,0 +1,28 @@ +// cpu-query.cpp +#include "cpu-query.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +Result QueryPoolImpl::init(const IQueryPool::Desc& desc) +{ + m_queries.setCount(desc.count); + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL QueryPoolImpl::getResult( + GfxIndex queryIndex, GfxCount count, uint64_t* data) +{ + for (GfxCount i = 0; i < count; i++) + { + data[i] = m_queries[queryIndex + i]; + } + return SLANG_OK; +} + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-query.h b/tools/gfx/cpu/cpu-query.h new file mode 100644 index 000000000..172dcea41 --- /dev/null +++ b/tools/gfx/cpu/cpu-query.h @@ -0,0 +1,22 @@ +// cpu-query.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class QueryPoolImpl : public QueryPoolBase +{ +public: + List<uint64_t> m_queries; + Result init(const IQueryPool::Desc& desc); + virtual SLANG_NO_THROW Result SLANG_MCALL getResult( + GfxIndex queryIndex, GfxCount count, uint64_t* data) override; +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-resource-views.cpp b/tools/gfx/cpu/cpu-resource-views.cpp new file mode 100644 index 000000000..ccf253cab --- /dev/null +++ b/tools/gfx/cpu/cpu-resource-views.cpp @@ -0,0 +1,176 @@ +// cpu-resource-views.cpp +#include "cpu-resource-views.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +ResourceViewImpl::ResourceViewImpl(Kind kind, Desc const& desc) + : m_kind(kind) +{ + m_desc = desc; +} + +BufferResourceImpl* BufferResourceViewImpl::getBuffer() const +{ + return m_buffer; +} + +TextureResourceImpl* TextureResourceViewImpl::getTexture() const +{ + return m_texture; +} + +slang_prelude::TextureDimensions TextureResourceViewImpl::GetDimensions(int mipLevel) +{ + slang_prelude::TextureDimensions dimensions = {}; + + TextureResourceImpl* texture = m_texture; + auto& desc = texture->_getDesc(); + auto baseShape = texture->m_baseShape; + + dimensions.arrayElementCount = desc.arraySize; + dimensions.numberOfLevels = desc.numMipLevels; + dimensions.shape = baseShape->rank; + dimensions.width = desc.size.width; + dimensions.height = desc.size.height; + dimensions.depth = desc.size.depth; + + return dimensions; +} + +void TextureResourceViewImpl::Load(const int32_t* texelCoords, void* outData, size_t dataSize) +{ + void* texelPtr = _getTexelPtr(texelCoords); + + m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize); +} + +void TextureResourceViewImpl::Sample( + slang_prelude::SamplerState samplerState, + const float* coords, + void* outData, + size_t dataSize) +{ + // We have no access to information from fragment quads, so we cannot + // compute the finite-difference derivatives needed from `coords`. + // + // The only reasonable thing to do is to sample mip level zero. + // + SampleLevel(samplerState, coords, 0.0f, outData, dataSize); +} + +void TextureResourceViewImpl::SampleLevel( + slang_prelude::SamplerState samplerState, + const float* coords, + float level, + void* outData, + size_t dataSize) +{ + TextureResourceImpl* texture = m_texture; + auto baseShape = texture->m_baseShape; + auto& desc = texture->_getDesc(); + int32_t rank = baseShape->rank; + int32_t baseCoordCount = baseShape->baseCoordCount; + + int32_t integerMipLevel = int32_t(level + 0.5f); + if (integerMipLevel >= desc.numMipLevels) integerMipLevel = desc.numMipLevels - 1; + if (integerMipLevel < 0) integerMipLevel = 0; + + auto& mipLevelInfo = texture->m_mipLevels[integerMipLevel]; + + bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube); + int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount; + int32_t coordIndex = baseCoordCount; + int32_t elementIndex = 0; + if (isArray) + { + elementIndex = int32_t(coords[coordIndex++] + 0.5f); + } + if (elementIndex >= effectiveArrayElementCount) elementIndex = effectiveArrayElementCount - 1; + if (elementIndex < 0) elementIndex = 0; + + // Note: for now we are just going to do nearest-neighbor sampling + // + int64_t texelOffset = mipLevelInfo.offset; + texelOffset += elementIndex * mipLevelInfo.strides[3]; + for (int32_t axis = 0; axis < rank; ++axis) + { + int32_t extent = mipLevelInfo.extents[axis]; + + float coord = coords[axis]; + + // TODO: deal with wrap/clamp/repeat if `coord < 0` or `coord > 1` + + int32_t integerCoord = int32_t(coord * (extent - 1) + 0.5f); + + if (integerCoord >= extent) integerCoord = extent - 1; + if (integerCoord < 0) integerCoord = 0; + + texelOffset += integerCoord * mipLevelInfo.strides[axis]; + } + + auto texelPtr = (char const*)texture->m_data + texelOffset; + + m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize); +} + +void* TextureResourceViewImpl::refAt(const uint32_t* texelCoords) +{ + return _getTexelPtr((int32_t const*)texelCoords); +} + +void* TextureResourceViewImpl::_getTexelPtr(int32_t const* texelCoords) +{ + TextureResourceImpl* texture = m_texture; + auto baseShape = texture->m_baseShape; + auto& desc = texture->_getDesc(); + + int32_t rank = baseShape->rank; + int32_t baseCoordCount = baseShape->baseCoordCount; + + bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube); + bool isMultisample = desc.sampleDesc.numSamples > 1; + bool isBuffer = desc.type == ITextureResource::Type::Buffer; + bool hasMipLevels = !(isMultisample || isBuffer); + + int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount; + + int32_t coordIndex = baseCoordCount; + int32_t elementIndex = 0; + if (isArray) + { + elementIndex = texelCoords[coordIndex++]; + } + if (elementIndex >= effectiveArrayElementCount) elementIndex = effectiveArrayElementCount - 1; + if (elementIndex < 0) elementIndex = 0; + + int32_t mipLevel = 0; + if (!hasMipLevels) + { + mipLevel = texelCoords[coordIndex++]; + } + if (mipLevel >= desc.numMipLevels) mipLevel = desc.numMipLevels - 1; + if (mipLevel < 0) mipLevel = 0; + + auto& mipLevelInfo = texture->m_mipLevels[mipLevel]; + + int64_t texelOffset = mipLevelInfo.offset; + texelOffset += elementIndex * mipLevelInfo.strides[3]; + for (int32_t axis = 0; axis < rank; ++axis) + { + int32_t coord = texelCoords[axis]; + if (coord >= mipLevelInfo.extents[axis]) coord = mipLevelInfo.extents[axis] - 1; + if (coord < 0) coord = 0; + + texelOffset += texelCoords[axis] * mipLevelInfo.strides[axis]; + } + + return (char*)texture->m_data + texelOffset; +} + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-resource-views.h b/tools/gfx/cpu/cpu-resource-views.h new file mode 100644 index 000000000..bec1339a3 --- /dev/null +++ b/tools/gfx/cpu/cpu-resource-views.h @@ -0,0 +1,82 @@ +// cpu-resource-views.h +#pragma once +#include "cpu-base.h" + +#include "cpu-buffer.h" +#include "cpu-texture.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class ResourceViewImpl : public ResourceViewBase +{ +public: + enum class Kind + { + Buffer, + Texture, + }; + Kind getViewKind() const { return m_kind; } + Desc const& getDesc() const { return m_desc; } + +protected: + ResourceViewImpl(Kind kind, Desc const& desc); + +private: + Kind m_kind; +}; + +class BufferResourceViewImpl : public ResourceViewImpl +{ +public: + BufferResourceViewImpl(Desc const& desc, BufferResourceImpl* buffer) + : ResourceViewImpl(Kind::Buffer, desc) + , m_buffer(buffer) + {} + + BufferResourceImpl* getBuffer() const; + +private: + RefPtr<BufferResourceImpl> m_buffer; +}; + +class TextureResourceViewImpl : public ResourceViewImpl, public slang_prelude::IRWTexture +{ +public: + TextureResourceViewImpl(Desc const& desc, TextureResourceImpl* texture) + : ResourceViewImpl(Kind::Texture, desc) + , m_texture(texture) + {} + + TextureResourceImpl* getTexture() const; + + // + // ITexture interface + // + + slang_prelude::TextureDimensions GetDimensions(int mipLevel = -1) SLANG_OVERRIDE; + + void Load(const int32_t* texelCoords, void* outData, size_t dataSize) SLANG_OVERRIDE; + + void Sample(slang_prelude::SamplerState samplerState, const float* coords, void* outData, size_t dataSize) SLANG_OVERRIDE; + + void SampleLevel(slang_prelude::SamplerState samplerState, const float* coords, float level, void* outData, size_t dataSize) SLANG_OVERRIDE; + + // + // IRWTexture interface + // + + void* refAt(const uint32_t* texelCoords) SLANG_OVERRIDE; + +private: + RefPtr<TextureResourceImpl> m_texture; + + void* _getTexelPtr(int32_t const* texelCoords); +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-shader-object-layout.cpp b/tools/gfx/cpu/cpu-shader-object-layout.cpp new file mode 100644 index 000000000..3b969c9a6 --- /dev/null +++ b/tools/gfx/cpu/cpu-shader-object-layout.cpp @@ -0,0 +1,168 @@ +// cpu-shader-object-layout.cpp +#include "cpu-shader-object-layout.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +ShaderObjectLayoutImpl::ShaderObjectLayoutImpl(RendererBase* renderer, slang::TypeLayoutReflection* layout) +{ + initBase(renderer, layout); + + m_subObjectCount = 0; + m_resourceCount = 0; + + m_elementTypeLayout = _unwrapParameterGroups(layout, m_containerType); + m_size = m_elementTypeLayout->getSize(); + + // Compute the binding ranges that are used to store + // the logical contents of the object in memory. These will relate + // to the descriptor ranges in the various sets, but not always + // in a one-to-one fashion. + + SlangInt bindingRangeCount = m_elementTypeLayout->getBindingRangeCount(); + for (SlangInt r = 0; r < bindingRangeCount; ++r) + { + slang::BindingType slangBindingType = m_elementTypeLayout->getBindingRangeType(r); + SlangInt count = m_elementTypeLayout->getBindingRangeBindingCount(r); + slang::TypeLayoutReflection* slangLeafTypeLayout = + m_elementTypeLayout->getBindingRangeLeafTypeLayout(r); + + SlangInt descriptorSetIndex = m_elementTypeLayout->getBindingRangeDescriptorSetIndex(r); + SlangInt rangeIndexInDescriptorSet = + m_elementTypeLayout->getBindingRangeFirstDescriptorRangeIndex(r); + + // TODO: This logic assumes that for any binding range that might consume + // multiple kinds of resources, the descriptor range for its uniform + // usage will be the first one in the range. + // + // We need to decide whether that assumption is one we intend to support + // applications making, or whether they should be forced to perform a + // linear search over the descriptor ranges for a specific binding range. + // + auto uniformOffset = m_elementTypeLayout->getDescriptorSetDescriptorRangeIndexOffset( + descriptorSetIndex, rangeIndexInDescriptorSet); + + Index baseIndex = 0; + Index subObjectIndex = 0; + switch (slangBindingType) + { + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + case slang::BindingType::ExistentialValue: + baseIndex = m_subObjectCount; + subObjectIndex = baseIndex; + m_subObjectCount += count; + break; + case slang::BindingType::RawBuffer: + case slang::BindingType::MutableRawBuffer: + if (slangLeafTypeLayout->getType()->getElementType() != nullptr) + { + // A structured buffer occupies both a resource slot and + // a sub-object slot. + subObjectIndex = m_subObjectCount; + m_subObjectCount += count; + } + baseIndex = m_resourceCount; + m_resourceCount += count; + break; + default: + baseIndex = m_resourceCount; + m_resourceCount += count; + break; + } + + BindingRangeInfo bindingRangeInfo; + bindingRangeInfo.bindingType = slangBindingType; + bindingRangeInfo.count = count; + bindingRangeInfo.baseIndex = baseIndex; + bindingRangeInfo.uniformOffset = uniformOffset; + bindingRangeInfo.subObjectIndex = subObjectIndex; + m_bindingRanges.add(bindingRangeInfo); + } + + SlangInt subObjectRangeCount = m_elementTypeLayout->getSubObjectRangeCount(); + for (SlangInt r = 0; r < subObjectRangeCount; ++r) + { + SlangInt bindingRangeIndex = m_elementTypeLayout->getSubObjectRangeBindingRangeIndex(r); + auto slangBindingType = m_elementTypeLayout->getBindingRangeType(bindingRangeIndex); + slang::TypeLayoutReflection* slangLeafTypeLayout = + m_elementTypeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); + + // A sub-object range can either represent a sub-object of a known + // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` + // (in which case we can pre-compute a layout to use, based on + // the type `Foo`) *or* it can represent a sub-object of some + // existential type (e.g., `IBar`) in which case we cannot + // know the appropriate type/layout of sub-object to allocate. + // + RefPtr<ShaderObjectLayoutImpl> subObjectLayout; + if (slangBindingType != slang::BindingType::ExistentialValue) + { + subObjectLayout = + new ShaderObjectLayoutImpl(renderer, slangLeafTypeLayout->getElementTypeLayout()); + } + + SubObjectRangeInfo subObjectRange; + subObjectRange.bindingRangeIndex = bindingRangeIndex; + subObjectRange.layout = subObjectLayout; + subObjectRanges.add(subObjectRange); + } +} + +size_t ShaderObjectLayoutImpl::getSize() +{ + return m_size; +} + +Index ShaderObjectLayoutImpl::getResourceCount() const { return m_resourceCount; } +Index ShaderObjectLayoutImpl::getSubObjectCount() const { return m_subObjectCount; } +List<SubObjectRangeInfo>& ShaderObjectLayoutImpl::getSubObjectRanges() { return subObjectRanges; } +BindingRangeInfo ShaderObjectLayoutImpl::getBindingRange(Index index) { return m_bindingRanges[index]; } +Index ShaderObjectLayoutImpl::getBindingRangeCount() const { return m_bindingRanges.getCount(); } + +const char* EntryPointLayoutImpl::getEntryPointName() +{ + return m_entryPointLayout->getName(); +} + +RootShaderObjectLayoutImpl::RootShaderObjectLayoutImpl(RendererBase* renderer, slang::ProgramLayout* programLayout) + : ShaderObjectLayoutImpl(renderer, programLayout->getGlobalParamsTypeLayout()) + , m_programLayout(programLayout) +{ + for (UInt i =0; i< programLayout->getEntryPointCount(); i++) + { + m_entryPointLayouts.add(new EntryPointLayoutImpl( + renderer, + programLayout->getEntryPointByIndex(i))); + } + +} + +int RootShaderObjectLayoutImpl::getKernelIndex(UnownedStringSlice kernelName) +{ + auto entryPointCount = (int) m_programLayout->getEntryPointCount(); + for(int i = 0; i < entryPointCount; i++) + { + auto entryPoint = m_programLayout->getEntryPointByIndex(i); + if (kernelName == entryPoint->getName()) + { + return i; + } + } + return -1; +} + +void RootShaderObjectLayoutImpl::getKernelThreadGroupSize(int kernelIndex, UInt* threadGroupSizes) +{ + auto entryPoint = m_programLayout->getEntryPointByIndex(kernelIndex); + entryPoint->getComputeThreadGroupSize(3, threadGroupSizes); +} + +EntryPointLayoutImpl* RootShaderObjectLayoutImpl::getEntryPoint(Index index) { return m_entryPointLayouts[index]; } + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-shader-object-layout.h b/tools/gfx/cpu/cpu-shader-object-layout.h new file mode 100644 index 000000000..44c225f83 --- /dev/null +++ b/tools/gfx/cpu/cpu-shader-object-layout.h @@ -0,0 +1,97 @@ +// cpu-shader-object-layout.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +struct BindingRangeInfo +{ + slang::BindingType bindingType; + Index count; + Index baseIndex; // Flat index for sub-objects + Index subObjectIndex; + + // TODO: The `uniformOffset` field should be removed, + // since it cannot be supported by the Slang reflection + // API once we fix some design issues. + // + // It is only being used today for pre-allocation of sub-objects + // for constant buffers and parameter blocks (which should be + // deprecated/removed anyway). + // + // Note: We would need to bring this field back, plus + // a lot of other complexity, if we ever want to support + // setting of resources/buffers directly by a binding + // range index and array index. + // + Index uniformOffset; // Uniform offset for a resource typed field. +}; + +struct SubObjectRangeInfo +{ + RefPtr<ShaderObjectLayoutImpl> layout; + Index bindingRangeIndex; +}; + +class ShaderObjectLayoutImpl : public ShaderObjectLayoutBase +{ +public: + + // TODO: Once memory lifetime stuff is handled, there is + // no specific need to even track binding or sub-object + // ranges for CPU. + + size_t m_size = 0; + List<SubObjectRangeInfo> subObjectRanges; + List<BindingRangeInfo> m_bindingRanges; + + Index m_subObjectCount = 0; + Index m_resourceCount = 0; + + ShaderObjectLayoutImpl(RendererBase* renderer, slang::TypeLayoutReflection* layout); + + size_t getSize(); + Index getResourceCount() const; + Index getSubObjectCount() const; + List<SubObjectRangeInfo>& getSubObjectRanges(); + BindingRangeInfo getBindingRange(Index index); + Index getBindingRangeCount() const; +}; + +class EntryPointLayoutImpl : public ShaderObjectLayoutImpl +{ +private: + slang::EntryPointLayout* m_entryPointLayout = nullptr; + +public: + EntryPointLayoutImpl( + RendererBase* renderer, + slang::EntryPointLayout* entryPointLayout) + : ShaderObjectLayoutImpl(renderer, entryPointLayout->getTypeLayout()) + , m_entryPointLayout(entryPointLayout) + {} + + const char* getEntryPointName(); +}; + +class RootShaderObjectLayoutImpl : public ShaderObjectLayoutImpl +{ +public: + slang::ProgramLayout* m_programLayout = nullptr; + List<RefPtr<EntryPointLayoutImpl>> m_entryPointLayouts; + + RootShaderObjectLayoutImpl(RendererBase* renderer, slang::ProgramLayout* programLayout); + + int getKernelIndex(UnownedStringSlice kernelName); + void getKernelThreadGroupSize(int kernelIndex, UInt* threadGroupSizes); + + EntryPointLayoutImpl* getEntryPoint(Index index); +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-shader-object.cpp b/tools/gfx/cpu/cpu-shader-object.cpp new file mode 100644 index 000000000..67ffd6af5 --- /dev/null +++ b/tools/gfx/cpu/cpu-shader-object.cpp @@ -0,0 +1,314 @@ +// cpu-shader-object.cpp +#include "cpu-shader-object.h" + +#include "cpu-buffer.h" +#include "cpu-resource-views.h" +#include "cpu-shader-object-layout.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +Index CPUShaderObjectData::getCount() +{ + return m_ordinaryData.getCount(); +} + +void CPUShaderObjectData::setCount(Index count) +{ + m_ordinaryData.setCount(count); +} + +char* CPUShaderObjectData::getBuffer() +{ + return m_ordinaryData.getBuffer(); +} + +CPUShaderObjectData::~CPUShaderObjectData() +{ + // m_bufferResource's data is managed by m_ordinaryData so we + // set it to null to prevent m_bufferResource from freeing it. + if (m_bufferResource) + m_bufferResource->m_data = nullptr; +} + +/// Returns a StructuredBuffer resource view for GPU access into the buffer content. +/// Creates a StructuredBuffer resource if it has not been created. +ResourceViewBase* CPUShaderObjectData::getResourceView( + RendererBase* device, + slang::TypeLayoutReflection* elementLayout, + slang::BindingType bindingType) +{ + SLANG_UNUSED(device); + if (!m_bufferResource) + { + IBufferResource::Desc desc = {}; + desc.type = IResource::Type::Buffer; + desc.elementSize = (int)elementLayout->getSize(); + m_bufferResource = new BufferResourceImpl(desc); + + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + m_bufferView = new BufferResourceViewImpl(viewDesc, m_bufferResource); + + } + m_bufferResource->getDesc()->sizeInBytes = m_ordinaryData.getCount(); + m_bufferResource->m_data = m_ordinaryData.getBuffer(); + return m_bufferView.Ptr(); +} + +Result ShaderObjectImpl::init(IDevice* device, ShaderObjectLayoutImpl* typeLayout) +{ + m_layout = typeLayout; + + // If the layout tells us that there is any uniform data, + // then we need to allocate a constant buffer to hold that data. + // + // TODO: Do we need to allocate a shadow copy for use from + // the CPU? + // + // TODO: When/where do we bind this constant buffer into + // a descriptor set for later use? + // + auto slangLayout = getLayout()->getElementTypeLayout(); + size_t uniformSize = slangLayout->getSize(); + m_data.setCount(uniformSize); + + // If the layout specifies that we have any resources or sub-objects, + // then we need to size the appropriate arrays to account for them. + // + // Note: the counts here are the *total* number of resources/sub-objects + // and not just the number of resource/sub-object ranges. + // + m_resources.setCount(typeLayout->getResourceCount()); + m_objects.setCount(typeLayout->getSubObjectCount()); + + for (auto subObjectRange : getLayout()->subObjectRanges) + { + RefPtr<ShaderObjectLayoutImpl> subObjectLayout = subObjectRange.layout; + + // In the case where the sub-object range represents an + // existential-type leaf field (e.g., an `IBar`), we + // cannot pre-allocate the object(s) to go into that + // range, since we can't possibly know what to allocate + // at this point. + // + if (!subObjectLayout) + continue; + auto _debugname = subObjectLayout->getElementTypeLayout()->getName(); + + // + // Otherwise, we will allocate a sub-object to fill + // in each entry in this range, based on the layout + // information we already have. + + auto& bindingRangeInfo = getLayout()->m_bindingRanges[subObjectRange.bindingRangeIndex]; + for (Index i = 0; i < bindingRangeInfo.count; ++i) + { + RefPtr<ShaderObjectImpl> subObject = new ShaderObjectImpl(); + SLANG_RETURN_ON_FAIL(subObject->init(device, subObjectLayout)); + + ShaderOffset offset; + offset.uniformOffset = bindingRangeInfo.uniformOffset + sizeof(void*) * i; + offset.bindingRangeIndex = (GfxIndex)subObjectRange.bindingRangeIndex; + offset.bindingArrayIndex = (GfxIndex)i; + + SLANG_RETURN_ON_FAIL(setObject(offset, subObject)); + } + } + return SLANG_OK; +} + +SLANG_NO_THROW GfxCount SLANG_MCALL ShaderObjectImpl::getEntryPointCount() +{ + return 0; +} + +SLANG_NO_THROW Result SLANG_MCALL + ShaderObjectImpl::getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) +{ + *outEntryPoint = nullptr; + return SLANG_OK; +} + +SLANG_NO_THROW const void* SLANG_MCALL ShaderObjectImpl::getRawData() +{ + return m_data.getBuffer(); +} + +SLANG_NO_THROW size_t SLANG_MCALL ShaderObjectImpl::getSize() +{ + return (size_t)m_data.getCount(); +} + +SLANG_NO_THROW Result SLANG_MCALL + ShaderObjectImpl::setData(ShaderOffset const& offset, void const* data, size_t size) +{ + size = Math::Min(size, size_t(m_data.getCount() - offset.uniformOffset)); + memcpy((char*)m_data.getBuffer() + offset.uniformOffset, data, size); + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL + ShaderObjectImpl::setResource(ShaderOffset const& offset, IResourceView* inView) +{ + auto layout = getLayout(); + + auto bindingRangeIndex = offset.bindingRangeIndex; + SLANG_ASSERT(bindingRangeIndex >= 0); + SLANG_ASSERT(bindingRangeIndex < layout->m_bindingRanges.getCount()); + + auto& bindingRange = layout->m_bindingRanges[bindingRangeIndex]; + auto viewIndex = bindingRange.baseIndex + offset.bindingArrayIndex; + + + auto view = static_cast<ResourceViewImpl*>(inView); + m_resources[viewIndex] = view; + + switch (view->getViewKind()) + { + case ResourceViewImpl::Kind::Texture: + { + auto textureView = static_cast<TextureResourceViewImpl*>(view); + + slang_prelude::IRWTexture* textureObj = textureView; + SLANG_RETURN_ON_FAIL(setData(offset, &textureObj, sizeof(textureObj))); + } + break; + + case ResourceViewImpl::Kind::Buffer: + { + auto bufferView = static_cast<BufferResourceViewImpl*>(view); + auto buffer = bufferView->getBuffer(); + auto desc = *buffer->getDesc(); + + void* dataPtr = buffer->m_data; + size_t size = desc.sizeInBytes; + if (desc.elementSize > 1) + size /= desc.elementSize; + + auto ptrOffset = offset; + SLANG_RETURN_ON_FAIL(setData(ptrOffset, &dataPtr, sizeof(dataPtr))); + + auto sizeOffset = offset; + sizeOffset.uniformOffset += sizeof(dataPtr); + SLANG_RETURN_ON_FAIL(setData(sizeOffset, &size, sizeof(size))); + } + break; + } + + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL + ShaderObjectImpl::setObject(ShaderOffset const& offset, IShaderObject* object) +{ + SLANG_RETURN_ON_FAIL(Super::setObject(offset, object)); + + auto bindingRangeIndex = offset.bindingRangeIndex; + auto& bindingRange = getLayout()->m_bindingRanges[bindingRangeIndex]; + + ShaderObjectImpl* subObject = static_cast<ShaderObjectImpl*>(object); + + switch (bindingRange.bindingType) + { + default: + { + void* bufferPtr = subObject->m_data.getBuffer(); + SLANG_RETURN_ON_FAIL(setData(offset, &bufferPtr, sizeof(void*))); + } + break; + case slang::BindingType::ExistentialValue: + case slang::BindingType::RawBuffer: + case slang::BindingType::MutableRawBuffer: + break; + } + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL + ShaderObjectImpl::setSampler(ShaderOffset const& offset, ISamplerState* sampler) +{ + SLANG_UNUSED(sampler); + SLANG_UNUSED(offset); + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL ShaderObjectImpl::setCombinedTextureSampler( + ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) +{ + SLANG_UNUSED(sampler); + setResource(offset, textureView); + return SLANG_OK; +} + +char* ShaderObjectImpl::getDataBuffer() +{ + return m_data.getBuffer(); +} + +EntryPointLayoutImpl* EntryPointShaderObjectImpl::getLayout() +{ + return static_cast<EntryPointLayoutImpl*>(m_layout.Ptr()); +} + +SLANG_NO_THROW uint32_t SLANG_MCALL RootShaderObjectImpl::addRef() +{ + return 1; +} + +SLANG_NO_THROW uint32_t SLANG_MCALL RootShaderObjectImpl::release() +{ + return 1; +} + +Result RootShaderObjectImpl::init(IDevice* device, RootShaderObjectLayoutImpl* programLayout) +{ + SLANG_RETURN_ON_FAIL(ShaderObjectImpl::init(device, programLayout)); + for (auto& entryPoint : programLayout->m_entryPointLayouts) + { + RefPtr<EntryPointShaderObjectImpl> object = new EntryPointShaderObjectImpl(); + SLANG_RETURN_ON_FAIL(object->init(device, entryPoint)); + m_entryPoints.add(object); + } + return SLANG_OK; +} + +RootShaderObjectLayoutImpl* RootShaderObjectImpl::getLayout() +{ + return static_cast<RootShaderObjectLayoutImpl*>(m_layout.Ptr()); +} + +EntryPointShaderObjectImpl* RootShaderObjectImpl::getEntryPoint(Index index) +{ + return m_entryPoints[index]; +} + +SLANG_NO_THROW GfxCount SLANG_MCALL RootShaderObjectImpl::getEntryPointCount() +{ + return (GfxCount)m_entryPoints.getCount(); +} + +SLANG_NO_THROW Result SLANG_MCALL + RootShaderObjectImpl::getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) +{ + returnComPtr(outEntryPoint, m_entryPoints[index]); + return SLANG_OK; +} + +Result RootShaderObjectImpl::collectSpecializationArgs(ExtendedShaderObjectTypeList& args) +{ + SLANG_RETURN_ON_FAIL(ShaderObjectImpl::collectSpecializationArgs(args)); + for (auto& entryPoint : m_entryPoints) + { + SLANG_RETURN_ON_FAIL(entryPoint->collectSpecializationArgs(args)); + } + return SLANG_OK; +} + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-shader-object.h b/tools/gfx/cpu/cpu-shader-object.h new file mode 100644 index 000000000..5d0b5c366 --- /dev/null +++ b/tools/gfx/cpu/cpu-shader-object.h @@ -0,0 +1,98 @@ +// cpu-shader-object.h +#pragma once +#include "cpu-base.h" + +#include "cpu-shader-object-layout.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class CPUShaderObjectData +{ +public: + Slang::List<char> m_ordinaryData; + // Any "ordinary" / uniform data for this object + Slang::RefPtr<BufferResourceImpl> m_bufferResource; + Slang::RefPtr<BufferResourceViewImpl> m_bufferView; + + Index getCount(); + void setCount(Index count); + char* getBuffer(); + + ~CPUShaderObjectData(); + + /// Returns a StructuredBuffer resource view for GPU access into the buffer content. + /// Creates a StructuredBuffer resource if it has not been created. + ResourceViewBase* getResourceView( + RendererBase* device, + slang::TypeLayoutReflection* elementLayout, + slang::BindingType bindingType); +}; + +class ShaderObjectImpl + : public ShaderObjectBaseImpl<ShaderObjectImpl, ShaderObjectLayoutImpl, CPUShaderObjectData> +{ + typedef ShaderObjectBaseImpl<ShaderObjectImpl, ShaderObjectLayoutImpl, CPUShaderObjectData> Super; + +public: + List<RefPtr<ResourceViewImpl>> m_resources; + + virtual SLANG_NO_THROW Result SLANG_MCALL + init(IDevice* device, ShaderObjectLayoutImpl* typeLayout); + + virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override; + virtual SLANG_NO_THROW Result SLANG_MCALL + getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override; + + virtual SLANG_NO_THROW const void* SLANG_MCALL getRawData() override; + + virtual SLANG_NO_THROW size_t SLANG_MCALL getSize() override; + + virtual SLANG_NO_THROW Result SLANG_MCALL + setData(ShaderOffset const& offset, void const* data, size_t size) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + setResource(ShaderOffset const& offset, IResourceView* inView) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + setObject(ShaderOffset const& offset, IShaderObject* object) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + setSampler(ShaderOffset const& offset, ISamplerState* sampler) override; + virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler( + ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) override; + + char* getDataBuffer(); +}; + +class MutableShaderObjectImpl : public MutableShaderObject<MutableShaderObjectImpl, ShaderObjectLayoutImpl> +{}; + +class EntryPointShaderObjectImpl : public ShaderObjectImpl +{ +public: + EntryPointLayoutImpl* getLayout(); +}; + +class RootShaderObjectImpl : public ShaderObjectImpl +{ +public: + virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override; + virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override; + + Result init(IDevice* device, RootShaderObjectLayoutImpl* programLayout); + + RootShaderObjectLayoutImpl* getLayout(); + + EntryPointShaderObjectImpl* getEntryPoint(Index index); + List<RefPtr<EntryPointShaderObjectImpl>> m_entryPoints; + + virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override; + virtual SLANG_NO_THROW Result SLANG_MCALL + getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override; + virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override; +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-shader-program.h b/tools/gfx/cpu/cpu-shader-program.h new file mode 100644 index 000000000..f2f159538 --- /dev/null +++ b/tools/gfx/cpu/cpu-shader-program.h @@ -0,0 +1,25 @@ +// cpu-shader-program.h +#pragma once +#include "cpu-base.h" + +#include "cpu-shader-object-layout.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +class ShaderProgramImpl : public ShaderProgramBase +{ +public: + RefPtr<RootShaderObjectLayoutImpl> layout; + + ~ShaderProgramImpl() + { + } +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-texture.cpp b/tools/gfx/cpu/cpu-texture.cpp new file mode 100644 index 000000000..d5367bd96 --- /dev/null +++ b/tools/gfx/cpu/cpu-texture.cpp @@ -0,0 +1,231 @@ +// cpu-texture.cpp +#include "cpu-texture.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +static CPUTextureBaseShapeInfo const* _getBaseShapeInfo(ITextureResource::Type baseShape) +{ + return &kCPUTextureBaseShapeInfos[(int)baseShape]; +} + +template<int N> +void _unpackFloatTexel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (float const*)texelData; + + float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + for (int i = 0; i < N; ++i) + temp[i] = input[i]; + + memcpy(outData, temp, outSize); +} + +template<int N> +void _unpackFloat16Texel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (int16_t const*)texelData; + + float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + for (int i = 0; i < N; ++i) + temp[i] = HalfToFloat(input[i]); + + memcpy(outData, temp, outSize); +} + +static inline float _unpackUnorm8Value(uint8_t value) +{ + return value / 255.0f; +} + +template<int N> +void _unpackUnorm8Texel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (uint8_t const*)texelData; + + float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + for (int i = 0; i < N; ++i) + temp[i] = _unpackUnorm8Value(input[i]); + + memcpy(outData, temp, outSize); +} + +void _unpackUnormBGRA8Texel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (uint8_t const*)texelData; + + float temp[4]; + temp[0] = _unpackUnorm8Value(input[2]); + temp[1] = _unpackUnorm8Value(input[1]); + temp[2] = _unpackUnorm8Value(input[0]); + temp[3] = _unpackUnorm8Value(input[3]); + + memcpy(outData, temp, outSize); +} + +template<int N> +void _unpackUInt16Texel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (uint16_t const*)texelData; + + uint32_t temp[4] = { 0, 0, 0, 0 }; + for (int i = 0; i < N; ++i) + temp[i] = input[i]; + + memcpy(outData, temp, outSize); +} + +template<int N> +void _unpackUInt32Texel(void const* texelData, void* outData, size_t outSize) +{ + auto input = (uint32_t const*)texelData; + + uint32_t temp[4] = { 0, 0, 0, 0 }; + for (int i = 0; i < N; ++i) + temp[i] = input[i]; + + memcpy(outData, temp, outSize); +} + +TextureResourceImpl::~TextureResourceImpl() +{ + free(m_data); +} + +Result TextureResourceImpl::init(ITextureResource::SubresourceData const* initData) +{ + auto desc = m_desc; + + // The format of the texture will determine the + // size of the texels we allocate. + // + // TODO: Compressed formats usually work in terms + // of a fixed block size, so that we cannot actually + // compute a simple `texelSize` like this. Instead + // we should be computing a `blockSize` and then + // a `blockExtents` value that gives the extent + // in texels of each block. For uncompressed formats + // the block extents would be 1 along each axis. + // + auto format = desc.format; + FormatInfo texelInfo; + gfxGetFormatInfo(format, &texelInfo); + uint32_t texelSize = uint32_t(texelInfo.blockSizeInBytes / texelInfo.pixelsPerBlock); + m_texelSize = texelSize; + + int32_t formatBlockSize[kMaxRank] = { 1, 1, 1 }; + + auto baseShapeInfo = _getBaseShapeInfo(desc.type); + m_baseShape = baseShapeInfo; + if(!baseShapeInfo) + return SLANG_FAIL; + + auto formatInfo = _getFormatInfo(desc.format); + m_formatInfo = formatInfo; + if(!formatInfo) + return SLANG_FAIL; + + int32_t rank = baseShapeInfo->rank; + int32_t effectiveArrayElementCount = desc.arraySize ? desc.arraySize : 1; + effectiveArrayElementCount *= baseShapeInfo->implicitArrayElementCount; + m_effectiveArrayElementCount = effectiveArrayElementCount; + + int32_t extents[kMaxRank]; + extents[0] = desc.size.width; + extents[1] = desc.size.height; + extents[2] = desc.size.depth; + + for(int32_t axis = rank; axis < kMaxRank; ++axis) + extents[axis] = 1; + + int32_t levelCount = desc.numMipLevels; + + m_mipLevels.setCount(levelCount); + + int64_t totalDataSize = 0; + for( int32_t levelIndex = 0; levelIndex < levelCount; ++levelIndex ) + { + auto& level = m_mipLevels[levelIndex]; + + for( int32_t axis = 0; axis < kMaxRank; ++axis ) + { + int32_t extent = extents[axis] >> levelIndex; + if(extent < 1) extent = 1; + level.extents[axis] = extent; + } + + level.strides[0] = texelSize; + for( int32_t axis = 1; axis < kMaxRank+1; ++axis) + { + level.strides[axis] = level.strides[axis-1]*level.extents[axis-1]; + } + + int64_t levelDataSize = texelSize; + levelDataSize *= effectiveArrayElementCount; + for( int32_t axis = 0; axis < rank; ++axis) + levelDataSize *= int64_t(level.extents[axis]); + + level.offset = totalDataSize; + totalDataSize += levelDataSize; + } + + void* textureData = malloc((size_t)totalDataSize); + m_data = textureData; + + if( initData ) + { + int32_t subResourceCounter = 0; + for(int32_t arrayElementIndex = 0; arrayElementIndex < effectiveArrayElementCount; ++arrayElementIndex) + { + for(int32_t mipLevel = 0; mipLevel < m_desc.numMipLevels; ++mipLevel) + { + int32_t subResourceIndex = subResourceCounter++; + + auto dstRowStride = m_mipLevels[mipLevel].strides[1]; + auto dstLayerStride = m_mipLevels[mipLevel].strides[2]; + auto dstArrayStride = m_mipLevels[mipLevel].strides[3]; + + auto textureRowSize = m_mipLevels[mipLevel].extents[0]*texelSize; + + auto rowCount = m_mipLevels[mipLevel].extents[1]; + auto depthLayerCount = m_mipLevels[mipLevel].extents[2]; + + auto& srcImage = initData[subResourceIndex]; + ptrdiff_t srcRowStride = ptrdiff_t(srcImage.strideY); + ptrdiff_t srcLayerStride = ptrdiff_t(srcImage.strideZ); + + char* dstLevel = (char*)textureData + m_mipLevels[mipLevel].offset; + char* dstImage = dstLevel + dstArrayStride*arrayElementIndex; + + const char* srcLayer = (const char*) srcImage.data; + char* dstLayer = dstImage; + + for(int32_t depthLayer = 0; depthLayer < depthLayerCount; ++depthLayer) + { + const char* srcRow = srcLayer; + char* dstRow = dstLayer; + + for(int32_t row = 0; row < rowCount; ++row) + { + memcpy(dstRow, srcRow, textureRowSize); + + srcRow += srcRowStride; + dstRow += dstRowStride; + } + + srcLayer += srcLayerStride; + dstLayer += dstLayerStride; + } + } + } + } + + return SLANG_OK; +} + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/cpu-texture.h b/tools/gfx/cpu/cpu-texture.h new file mode 100644 index 000000000..5ae896d0f --- /dev/null +++ b/tools/gfx/cpu/cpu-texture.h @@ -0,0 +1,130 @@ +// cpu-texture.h +#pragma once +#include "cpu-base.h" + +namespace gfx +{ +using namespace Slang; + +namespace cpu +{ + +struct CPUTextureBaseShapeInfo +{ + int32_t rank; + int32_t baseCoordCount; + int32_t implicitArrayElementCount; +}; + +static const CPUTextureBaseShapeInfo kCPUTextureBaseShapeInfos[(int)ITextureResource::Type::_Count] = +{ + /* Unknown */ { 0, 0, 0 }, + /* Buffer */ { 1, 1, 1 }, + /* Texture1D */ { 1, 1, 1 }, + /* Texture2D */ { 2, 2, 1 }, + /* Texture3D */ { 3, 3, 1 }, + /* TextureCube */ { 2, 3, 6 }, +}; + +static CPUTextureBaseShapeInfo const* _getBaseShapeInfo(ITextureResource::Type baseShape); + +typedef void (*CPUTextureUnpackFunc)(void const* texelData, void* outData, size_t outSize); + +struct CPUTextureFormatInfo +{ + CPUTextureUnpackFunc unpackFunc; +}; + +template<int N> +void _unpackFloatTexel(void const* texelData, void* outData, size_t outSize); + +template<int N> +void _unpackFloat16Texel(void const* texelData, void* outData, size_t outSize); + +static inline float _unpackUnorm8Value(uint8_t value); + +template<int N> +void _unpackUnorm8Texel(void const* texelData, void* outData, size_t outSize); + +void _unpackUnormBGRA8Texel(void const* texelData, void* outData, size_t outSize); + +template<int N> +void _unpackUInt16Texel(void const* texelData, void* outData, size_t outSize); + +template<int N> +void _unpackUInt32Texel(void const* texelData, void* outData, size_t outSize); + +struct CPUFormatInfoMap +{ + CPUFormatInfoMap() + { + memset(m_infos, 0, sizeof(m_infos)); + + set(Format::R32G32B32A32_FLOAT, &_unpackFloatTexel<4>); + set(Format::R32G32B32_FLOAT, &_unpackFloatTexel<3>); + + set(Format::R32G32_FLOAT, &_unpackFloatTexel<2>); + set(Format::R32_FLOAT, &_unpackFloatTexel<1>); + + set(Format::R16G16B16A16_FLOAT, &_unpackFloat16Texel<4>); + set(Format::R16G16_FLOAT, &_unpackFloat16Texel<2>); + set(Format::R16_FLOAT, &_unpackFloat16Texel<1>); + + set(Format::R8G8B8A8_UNORM, &_unpackUnorm8Texel<4>); + set(Format::B8G8R8A8_UNORM, &_unpackUnormBGRA8Texel); + set(Format::R16_UINT, &_unpackUInt16Texel<1>); + set(Format::R32_UINT, &_unpackUInt32Texel<1>); + set(Format::D32_FLOAT, &_unpackFloatTexel<1>); + } + + void set(Format format, CPUTextureUnpackFunc func) + { + auto& info = m_infos[Index(format)]; + info.unpackFunc = func; + } + SLANG_FORCE_INLINE const CPUTextureFormatInfo& get(Format format) const { return m_infos[Index(format)]; } + + CPUTextureFormatInfo m_infos[Index(Format::_Count)]; +}; + +static const CPUFormatInfoMap g_formatInfoMap; + +static CPUTextureFormatInfo const* _getFormatInfo(Format format) +{ + const CPUTextureFormatInfo& info = g_formatInfoMap.get(format); + return info.unpackFunc ? &info : nullptr; +} + +class TextureResourceImpl : public TextureResource +{ + enum { kMaxRank = 3 }; + +public: + TextureResourceImpl(const TextureResource::Desc& desc) + : TextureResource(desc) + {} + ~TextureResourceImpl(); + + Result init(ITextureResource::SubresourceData const* initData); + + Desc const& _getDesc() { return m_desc; } + Format getFormat() { return m_desc.format; } + int32_t getRank() { return m_baseShape->rank; } + + CPUTextureBaseShapeInfo const* m_baseShape; + CPUTextureFormatInfo const* m_formatInfo; + int32_t m_effectiveArrayElementCount = 0; + uint32_t m_texelSize = 0; + + struct MipLevel + { + int32_t extents[kMaxRank]; + int64_t strides[kMaxRank+1]; + int64_t offset; + }; + List<MipLevel> m_mipLevels; + void* m_data = nullptr; +}; + +} // namespace cpu +} // namespace gfx diff --git a/tools/gfx/cpu/render-cpu.cpp b/tools/gfx/cpu/render-cpu.cpp deleted file mode 100644 index 9f3fcfa2e..000000000 --- a/tools/gfx/cpu/render-cpu.cpp +++ /dev/null @@ -1,1427 +0,0 @@ -// render-cpu.cpp -#include "render-cpu.h" - -#include <chrono> - -#include "slang.h" -#include "slang-com-ptr.h" -#include "slang-com-helper.h" -#include "core/slang-basic.h" -#include "core/slang-blob.h" - -#include "../immediate-renderer-base.h" -#include "../slang-context.h" -#include "../mutable-shader-object.h" -#define SLANG_PRELUDE_NAMESPACE slang_prelude -#include "prelude/slang-cpp-types.h" - -namespace gfx -{ -using namespace Slang; - -class CPUBufferResource : public BufferResource -{ -public: - CPUBufferResource(const Desc& _desc) - : BufferResource(_desc) - {} - - ~CPUBufferResource() - { - if (m_data) - { - free(m_data); - } - } - - SlangResult init() - { - m_data = malloc(m_desc.sizeInBytes); - if (!m_data) - return SLANG_E_OUT_OF_MEMORY; - return SLANG_OK; - } - - SlangResult setData(size_t offset, size_t size, void const* data) - { - memcpy((char*)m_data + offset, data, size); - return SLANG_OK; - } - - void* m_data = nullptr; - - virtual SLANG_NO_THROW DeviceAddress SLANG_MCALL getDeviceAddress() override - { - return (DeviceAddress)m_data; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL - map(MemoryRange* rangeToRead, void** outPointer) override - { - SLANG_UNUSED(rangeToRead); - if (outPointer) - *outPointer = m_data; - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL unmap(MemoryRange* writtenRange) override - { - SLANG_UNUSED(writtenRange); - return SLANG_OK; - } -}; - -struct CPUTextureBaseShapeInfo -{ - int32_t rank; - int32_t baseCoordCount; - int32_t implicitArrayElementCount; -}; - -static const CPUTextureBaseShapeInfo kCPUTextureBaseShapeInfos[(int)ITextureResource::Type::_Count] = -{ - /* Unknown */ { 0, 0, 0 }, - /* Buffer */ { 1, 1, 1 }, - /* Texture1D */ { 1, 1, 1 }, - /* Texture2D */ { 2, 2, 1 }, - /* Texture3D */ { 3, 3, 1 }, - /* TextureCube */ { 2, 3, 6 }, -}; - -static CPUTextureBaseShapeInfo const* _getBaseShapeInfo(ITextureResource::Type baseShape) -{ - return &kCPUTextureBaseShapeInfos[(int)baseShape]; -} - -typedef void (*CPUTextureUnpackFunc)(void const* texelData, void* outData, size_t outSize); - -struct CPUTextureFormatInfo -{ - CPUTextureUnpackFunc unpackFunc; -}; - -template<int N> -void _unpackFloatTexel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (float const*) texelData; - - float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for(int i = 0; i < N; ++i) - temp[i] = input[i]; - - memcpy(outData, temp, outSize); -} - -template<int N> -void _unpackFloat16Texel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (int16_t const*)texelData; - - float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for (int i = 0; i < N; ++i) - temp[i] = HalfToFloat(input[i]); - - memcpy(outData, temp, outSize); -} - -static inline float _unpackUnorm8Value(uint8_t value) -{ - return value / 255.0f; -} - -template<int N> -void _unpackUnorm8Texel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (uint8_t const*) texelData; - - float temp[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for(int i = 0; i < N; ++i) - temp[i] = _unpackUnorm8Value(input[i]); - - memcpy(outData, temp, outSize); -} - -void _unpackUnormBGRA8Texel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (uint8_t const*) texelData; - - float temp[4]; - temp[0] = _unpackUnorm8Value(input[2]); - temp[1] = _unpackUnorm8Value(input[1]); - temp[2] = _unpackUnorm8Value(input[0]); - temp[3] = _unpackUnorm8Value(input[3]); - - memcpy(outData, temp, outSize); -} - -template<int N> -void _unpackUInt16Texel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (uint16_t const*) texelData; - - uint32_t temp[4] = { 0, 0, 0, 0 }; - for(int i = 0; i < N; ++i) - temp[i] = input[i]; - - memcpy(outData, temp, outSize); -} - -template<int N> -void _unpackUInt32Texel(void const* texelData, void* outData, size_t outSize) -{ - auto input = (uint32_t const*) texelData; - - uint32_t temp[4] = { 0, 0, 0, 0 }; - for(int i = 0; i < N; ++i) - temp[i] = input[i]; - - memcpy(outData, temp, outSize); -} - -struct CPUFormatInfoMap -{ - CPUFormatInfoMap() - { - memset(m_infos, 0, sizeof(m_infos)); - - set(Format::R32G32B32A32_FLOAT, &_unpackFloatTexel<4>); - set(Format::R32G32B32_FLOAT, &_unpackFloatTexel<3>); - - set(Format::R32G32_FLOAT, &_unpackFloatTexel<2>); - set(Format::R32_FLOAT, &_unpackFloatTexel<1>); - - set(Format::R16G16B16A16_FLOAT, &_unpackFloat16Texel<4>); - set(Format::R16G16_FLOAT, &_unpackFloat16Texel<2>); - set(Format::R16_FLOAT, &_unpackFloat16Texel<1>); - - set(Format::R8G8B8A8_UNORM, &_unpackUnorm8Texel<4>); - set(Format::B8G8R8A8_UNORM, &_unpackUnormBGRA8Texel); - set(Format::R16_UINT, &_unpackUInt16Texel<1>); - set(Format::R32_UINT, &_unpackUInt32Texel<1>); - set(Format::D32_FLOAT, &_unpackFloatTexel<1>); - } - - void set(Format format, CPUTextureUnpackFunc func) - { - auto& info = m_infos[Index(format)]; - info.unpackFunc = func; - } - SLANG_FORCE_INLINE const CPUTextureFormatInfo& get(Format format) const { return m_infos[Index(format)]; } - - CPUTextureFormatInfo m_infos[Index(Format::_Count)]; -}; - -static const CPUFormatInfoMap g_formatInfoMap; - -static CPUTextureFormatInfo const* _getFormatInfo(Format format) -{ - const CPUTextureFormatInfo& info = g_formatInfoMap.get(format); - return info.unpackFunc ? &info : nullptr; -} - -class CPUTextureResource : public TextureResource -{ - enum { kMaxRank = 3 }; - -public: - CPUTextureResource(const TextureResource::Desc& desc) - : TextureResource(desc) - {} - ~CPUTextureResource() - { - free(m_data); - } - - Result init(ITextureResource::SubresourceData const* initData) - { - auto desc = m_desc; - - // The format of the texture will determine the - // size of the texels we allocate. - // - // TODO: Compressed formats usually work in terms - // of a fixed block size, so that we cannot actually - // compute a simple `texelSize` like this. Instead - // we should be computing a `blockSize` and then - // a `blockExtents` value that gives the extent - // in texels of each block. For uncompressed formats - // the block extents would be 1 along each axis. - // - auto format = desc.format; - FormatInfo texelInfo; - gfxGetFormatInfo(format, &texelInfo); - uint32_t texelSize = uint32_t(texelInfo.blockSizeInBytes / texelInfo.pixelsPerBlock); - m_texelSize = texelSize; - - int32_t formatBlockSize[kMaxRank] = { 1, 1, 1 }; - - auto baseShapeInfo = _getBaseShapeInfo(desc.type); - m_baseShape = baseShapeInfo; - if(!baseShapeInfo) - return SLANG_FAIL; - - auto formatInfo = _getFormatInfo(desc.format); - m_formatInfo = formatInfo; - if(!formatInfo) - return SLANG_FAIL; - - int32_t rank = baseShapeInfo->rank; - int32_t effectiveArrayElementCount = desc.arraySize ? desc.arraySize : 1; - effectiveArrayElementCount *= baseShapeInfo->implicitArrayElementCount; - m_effectiveArrayElementCount = effectiveArrayElementCount; - - int32_t extents[kMaxRank]; - extents[0] = desc.size.width; - extents[1] = desc.size.height; - extents[2] = desc.size.depth; - - for(int32_t axis = rank; axis < kMaxRank; ++axis) - extents[axis] = 1; - - int32_t levelCount = desc.numMipLevels; - - m_mipLevels.setCount(levelCount); - - int64_t totalDataSize = 0; - for( int32_t levelIndex = 0; levelIndex < levelCount; ++levelIndex ) - { - auto& level = m_mipLevels[levelIndex]; - - for( int32_t axis = 0; axis < kMaxRank; ++axis ) - { - int32_t extent = extents[axis] >> levelIndex; - if(extent < 1) extent = 1; - level.extents[axis] = extent; - } - - level.strides[0] = texelSize; - for( int32_t axis = 1; axis < kMaxRank+1; ++axis) - { - level.strides[axis] = level.strides[axis-1]*level.extents[axis-1]; - } - - int64_t levelDataSize = texelSize; - levelDataSize *= effectiveArrayElementCount; - for( int32_t axis = 0; axis < rank; ++axis) - levelDataSize *= int64_t(level.extents[axis]); - - level.offset = totalDataSize; - totalDataSize += levelDataSize; - } - - void* textureData = malloc((size_t)totalDataSize); - m_data = textureData; - - if( initData ) - { - int32_t subResourceCounter = 0; - for(int32_t arrayElementIndex = 0; arrayElementIndex < effectiveArrayElementCount; ++arrayElementIndex) - { - for(int32_t mipLevel = 0; mipLevel < m_desc.numMipLevels; ++mipLevel) - { - int32_t subResourceIndex = subResourceCounter++; - - auto dstRowStride = m_mipLevels[mipLevel].strides[1]; - auto dstLayerStride = m_mipLevels[mipLevel].strides[2]; - auto dstArrayStride = m_mipLevels[mipLevel].strides[3]; - - auto textureRowSize = m_mipLevels[mipLevel].extents[0]*texelSize; - - auto rowCount = m_mipLevels[mipLevel].extents[1]; - auto depthLayerCount = m_mipLevels[mipLevel].extents[2]; - - auto& srcImage = initData[subResourceIndex]; - ptrdiff_t srcRowStride = ptrdiff_t(srcImage.strideY); - ptrdiff_t srcLayerStride = ptrdiff_t(srcImage.strideZ); - - char* dstLevel = (char*)textureData + m_mipLevels[mipLevel].offset; - char* dstImage = dstLevel + dstArrayStride*arrayElementIndex; - - const char* srcLayer = (const char*) srcImage.data; - char* dstLayer = dstImage; - - for(int32_t depthLayer = 0; depthLayer < depthLayerCount; ++depthLayer) - { - const char* srcRow = srcLayer; - char* dstRow = dstLayer; - - for(int32_t row = 0; row < rowCount; ++row) - { - memcpy(dstRow, srcRow, textureRowSize); - - srcRow += srcRowStride; - dstRow += dstRowStride; - } - - srcLayer += srcLayerStride; - dstLayer += dstLayerStride; - } - } - } - } - - return SLANG_OK; - } - - Desc const& _getDesc() { return m_desc; } - Format getFormat() { return m_desc.format; } - int32_t getRank() { return m_baseShape->rank; } - - CPUTextureBaseShapeInfo const* m_baseShape; - CPUTextureFormatInfo const* m_formatInfo; - int32_t m_effectiveArrayElementCount = 0; - uint32_t m_texelSize = 0; - - struct MipLevel - { - int32_t extents[kMaxRank]; - int64_t strides[kMaxRank+1]; - int64_t offset; - }; - List<MipLevel> m_mipLevels; - void* m_data = nullptr; -}; - -class CPUResourceView : public ResourceViewBase -{ -public: - enum class Kind - { - Buffer, - Texture, - }; - Kind getViewKind() const { return m_kind; } - Desc const& getDesc() const { return m_desc; } - -protected: - CPUResourceView(Kind kind, Desc const& desc) - : m_kind(kind) - { - m_desc = desc; - } - -private: - Kind m_kind; -}; - -class CPUBufferView : public CPUResourceView -{ -public: - CPUBufferView(Desc const& desc, CPUBufferResource* buffer) - : CPUResourceView(Kind::Buffer, desc) - , m_buffer(buffer) - {} - - CPUBufferResource* getBuffer() const { return m_buffer; } - -private: - RefPtr<CPUBufferResource> m_buffer; -}; - -class CPUTextureView : public CPUResourceView, public slang_prelude::IRWTexture -{ -public: - CPUTextureView(Desc const& desc, CPUTextureResource* texture) - : CPUResourceView(Kind::Texture, desc) - , m_texture(texture) - {} - - CPUTextureResource* getTexture() const { return m_texture; } - - // - // ITexture interface - // - - slang_prelude::TextureDimensions GetDimensions(int mipLevel = -1) SLANG_OVERRIDE - { - slang_prelude::TextureDimensions dimensions = {}; - - CPUTextureResource* texture = m_texture; - auto& desc = texture->_getDesc(); - auto baseShape = texture->m_baseShape; - - dimensions.arrayElementCount = desc.arraySize; - dimensions.numberOfLevels = desc.numMipLevels; - dimensions.shape = baseShape->rank; - dimensions.width = desc.size.width; - dimensions.height = desc.size.height; - dimensions.depth = desc.size.depth; - - return dimensions; - } - - void Load(const int32_t* texelCoords, void* outData, size_t dataSize) SLANG_OVERRIDE - { - void* texelPtr = _getTexelPtr(texelCoords); - - m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize); - } - - void Sample(slang_prelude::SamplerState samplerState, const float* coords, void* outData, size_t dataSize) SLANG_OVERRIDE - { - // We have no access to information from fragment quads, so we cannot - // compute the finite-difference derivatives needed from `coords`. - // - // The only reasonable thing to do is to sample mip level zero. - // - SampleLevel(samplerState, coords, 0.0f, outData, dataSize); - } - - void SampleLevel(slang_prelude::SamplerState samplerState, const float* coords, float level, void* outData, size_t dataSize) SLANG_OVERRIDE - { - CPUTextureResource* texture = m_texture; - auto baseShape = texture->m_baseShape; - auto& desc = texture->_getDesc(); - int32_t rank = baseShape->rank; - int32_t baseCoordCount = baseShape->baseCoordCount; - - int32_t integerMipLevel = int32_t(level + 0.5f); - if(integerMipLevel >= desc.numMipLevels) integerMipLevel = desc.numMipLevels-1; - if(integerMipLevel < 0) integerMipLevel = 0; - - auto& mipLevelInfo = texture->m_mipLevels[integerMipLevel]; - - bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube); - int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount; - int32_t coordIndex = baseCoordCount; - int32_t elementIndex = 0; - if( isArray ) - { - elementIndex = int32_t(coords[coordIndex++] + 0.5f); - } - if(elementIndex >= effectiveArrayElementCount) elementIndex = effectiveArrayElementCount-1; - if(elementIndex < 0) elementIndex = 0; - - // Note: for now we are just going to do nearest-neighbor sampling - // - int64_t texelOffset = mipLevelInfo.offset; - texelOffset += elementIndex * mipLevelInfo.strides[3]; - for(int32_t axis = 0; axis < rank; ++axis) - { - int32_t extent = mipLevelInfo.extents[axis]; - - float coord = coords[axis]; - - // TODO: deal with wrap/clamp/repeat if `coord < 0` or `coord > 1` - - int32_t integerCoord = int32_t(coord*(extent-1) + 0.5f); - - if(integerCoord >= extent) integerCoord = extent-1; - if(integerCoord < 0) integerCoord = 0; - - texelOffset += integerCoord * mipLevelInfo.strides[axis]; - } - - auto texelPtr = (char const*)texture->m_data + texelOffset; - - m_texture->m_formatInfo->unpackFunc(texelPtr, outData, dataSize); - } - - // - // IRWTexture interface - // - - void* refAt(const uint32_t* texelCoords) SLANG_OVERRIDE - { - return _getTexelPtr((int32_t const*)texelCoords); - } - -private: - RefPtr<CPUTextureResource> m_texture; - - void* _getTexelPtr(int32_t const* texelCoords) - { - CPUTextureResource* texture = m_texture; - auto baseShape = texture->m_baseShape; - auto& desc = texture->_getDesc(); - - int32_t rank = baseShape->rank; - int32_t baseCoordCount = baseShape->baseCoordCount; - - bool isArray = (desc.arraySize != 0) || (desc.type == ITextureResource::Type::TextureCube); - bool isMultisample = desc.sampleDesc.numSamples > 1; - bool isBuffer = desc.type == ITextureResource::Type::Buffer; - bool hasMipLevels = !(isMultisample || isBuffer); - - int32_t effectiveArrayElementCount = texture->m_effectiveArrayElementCount; - - int32_t coordIndex = baseCoordCount; - int32_t elementIndex = 0; - if( isArray ) - { - elementIndex = texelCoords[coordIndex++]; - } - if(elementIndex >= effectiveArrayElementCount) elementIndex = effectiveArrayElementCount-1; - if(elementIndex < 0) elementIndex = 0; - - int32_t mipLevel = 0; - if(!hasMipLevels) - { - mipLevel = texelCoords[coordIndex++]; - } - if(mipLevel >= desc.numMipLevels) mipLevel = desc.numMipLevels-1; - if(mipLevel < 0) mipLevel = 0; - - auto& mipLevelInfo = texture->m_mipLevels[mipLevel]; - - int64_t texelOffset = mipLevelInfo.offset; - texelOffset += elementIndex * mipLevelInfo.strides[3]; - for(int32_t axis = 0; axis < rank; ++axis) - { - int32_t coord = texelCoords[axis]; - if(coord >= mipLevelInfo.extents[axis]) coord = mipLevelInfo.extents[axis]-1; - if(coord < 0) coord = 0; - - texelOffset += texelCoords[axis] * mipLevelInfo.strides[axis]; - } - - return (char*)texture->m_data + texelOffset; - } -}; - -class CPUShaderObjectLayout : public ShaderObjectLayoutBase -{ -public: - - // TODO: Once memory lifetime stuff is handled, there is - // no specific need to even track binding or sub-object - // ranges for CPU. - - struct BindingRangeInfo - { - slang::BindingType bindingType; - Index count; - Index baseIndex; // Flat index for sub-ojects - Index subObjectIndex; - - // TODO: The `uniformOffset` field should be removed, - // since it cannot be supported by the Slang reflection - // API once we fix some design issues. - // - // It is only being used today for pre-allocation of sub-objects - // for constant buffers and parameter blocks (which should be - // deprecated/removed anyway). - // - // Note: We would need to bring this field back, plus - // a lot of other complexity, if we ever want to support - // setting of resources/buffers directly by a binding - // range index and array index. - // - Index uniformOffset; // Uniform offset for a resource typed field. - }; - - struct SubObjectRangeInfo - { - RefPtr<CPUShaderObjectLayout> layout; - Index bindingRangeIndex; - }; - - size_t m_size = 0; - List<SubObjectRangeInfo> subObjectRanges; - List<BindingRangeInfo> m_bindingRanges; - - Index m_subObjectCount = 0; - Index m_resourceCount = 0; - - CPUShaderObjectLayout(RendererBase* renderer, slang::TypeLayoutReflection* layout) - { - initBase(renderer, layout); - - m_subObjectCount = 0; - m_resourceCount = 0; - - m_elementTypeLayout = _unwrapParameterGroups(layout, m_containerType); - m_size = m_elementTypeLayout->getSize(); - - // Compute the binding ranges that are used to store - // the logical contents of the object in memory. These will relate - // to the descriptor ranges in the various sets, but not always - // in a one-to-one fashion. - - SlangInt bindingRangeCount = m_elementTypeLayout->getBindingRangeCount(); - for (SlangInt r = 0; r < bindingRangeCount; ++r) - { - slang::BindingType slangBindingType = m_elementTypeLayout->getBindingRangeType(r); - SlangInt count = m_elementTypeLayout->getBindingRangeBindingCount(r); - slang::TypeLayoutReflection* slangLeafTypeLayout = - m_elementTypeLayout->getBindingRangeLeafTypeLayout(r); - - SlangInt descriptorSetIndex = m_elementTypeLayout->getBindingRangeDescriptorSetIndex(r); - SlangInt rangeIndexInDescriptorSet = - m_elementTypeLayout->getBindingRangeFirstDescriptorRangeIndex(r); - - // TODO: This logic assumes that for any binding range that might consume - // multiple kinds of resources, the descriptor range for its uniform - // usage will be the first one in the range. - // - // We need to decide whether that assumption is one we intend to support - // applications making, or whether they should be forced to perform a - // linear search over the descriptor ranges for a specific binding range. - // - auto uniformOffset = m_elementTypeLayout->getDescriptorSetDescriptorRangeIndexOffset( - descriptorSetIndex, rangeIndexInDescriptorSet); - - Index baseIndex = 0; - Index subObjectIndex = 0; - switch (slangBindingType) - { - case slang::BindingType::ConstantBuffer: - case slang::BindingType::ParameterBlock: - case slang::BindingType::ExistentialValue: - baseIndex = m_subObjectCount; - subObjectIndex = baseIndex; - m_subObjectCount += count; - break; - case slang::BindingType::RawBuffer: - case slang::BindingType::MutableRawBuffer: - if (slangLeafTypeLayout->getType()->getElementType() != nullptr) - { - // A structured buffer occupies both a resource slot and - // a sub-object slot. - subObjectIndex = m_subObjectCount; - m_subObjectCount += count; - } - baseIndex = m_resourceCount; - m_resourceCount += count; - break; - default: - baseIndex = m_resourceCount; - m_resourceCount += count; - break; - } - - BindingRangeInfo bindingRangeInfo; - bindingRangeInfo.bindingType = slangBindingType; - bindingRangeInfo.count = count; - bindingRangeInfo.baseIndex = baseIndex; - bindingRangeInfo.uniformOffset = uniformOffset; - bindingRangeInfo.subObjectIndex = subObjectIndex; - m_bindingRanges.add(bindingRangeInfo); - } - - SlangInt subObjectRangeCount = m_elementTypeLayout->getSubObjectRangeCount(); - for (SlangInt r = 0; r < subObjectRangeCount; ++r) - { - SlangInt bindingRangeIndex = m_elementTypeLayout->getSubObjectRangeBindingRangeIndex(r); - auto slangBindingType = m_elementTypeLayout->getBindingRangeType(bindingRangeIndex); - slang::TypeLayoutReflection* slangLeafTypeLayout = - m_elementTypeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); - - // A sub-object range can either represent a sub-object of a known - // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` - // (in which case we can pre-compute a layout to use, based on - // the type `Foo`) *or* it can represent a sub-object of some - // existential type (e.g., `IBar`) in which case we cannot - // know the appropraite type/layout of sub-object to allocate. - // - RefPtr<CPUShaderObjectLayout> subObjectLayout; - if (slangBindingType != slang::BindingType::ExistentialValue) - { - subObjectLayout = - new CPUShaderObjectLayout(renderer, slangLeafTypeLayout->getElementTypeLayout()); - } - - SubObjectRangeInfo subObjectRange; - subObjectRange.bindingRangeIndex = bindingRangeIndex; - subObjectRange.layout = subObjectLayout; - subObjectRanges.add(subObjectRange); - } - } - - size_t getSize() { return m_size; } - Index getResourceCount() const { return m_resourceCount; } - Index getSubObjectCount() const { return m_subObjectCount; } - List<SubObjectRangeInfo>& getSubObjectRanges() { return subObjectRanges; } - BindingRangeInfo getBindingRange(Index index) { return m_bindingRanges[index]; } - Index getBindingRangeCount() const { return m_bindingRanges.getCount(); } -}; - -class CPUEntryPointLayout : public CPUShaderObjectLayout -{ -private: - slang::EntryPointLayout* m_entryPointLayout = nullptr; - -public: - CPUEntryPointLayout( - RendererBase* renderer, - slang::EntryPointLayout* entryPointLayout) - : CPUShaderObjectLayout(renderer, entryPointLayout->getTypeLayout()) - , m_entryPointLayout(entryPointLayout) - {} - - const char* getEntryPointName() { return m_entryPointLayout->getName(); } -}; - -class CPUProgramLayout : public CPUShaderObjectLayout -{ -public: - slang::ProgramLayout* m_programLayout = nullptr; - List<RefPtr<CPUEntryPointLayout>> m_entryPointLayouts; - - CPUProgramLayout(RendererBase* renderer, slang::ProgramLayout* programLayout) - : CPUShaderObjectLayout(renderer, programLayout->getGlobalParamsTypeLayout()) - , m_programLayout(programLayout) - { - for (UInt i =0; i< programLayout->getEntryPointCount(); i++) - { - m_entryPointLayouts.add(new CPUEntryPointLayout( - renderer, - programLayout->getEntryPointByIndex(i))); - } - - } - - int getKernelIndex(UnownedStringSlice kernelName) - { - auto entryPointCount = (int) m_programLayout->getEntryPointCount(); - for(int i = 0; i < entryPointCount; i++) - { - auto entryPoint = m_programLayout->getEntryPointByIndex(i); - if (kernelName == entryPoint->getName()) - { - return i; - } - } - return -1; - } - - void getKernelThreadGroupSize(int kernelIndex, UInt* threadGroupSizes) - { - auto entryPoint = m_programLayout->getEntryPointByIndex(kernelIndex); - entryPoint->getComputeThreadGroupSize(3, threadGroupSizes); - } - - CPUEntryPointLayout* getEntryPoint(Index index) { return m_entryPointLayouts[index]; } -}; - -class CPUShaderObjectData -{ -public: - Slang::List<char> m_ordinaryData; - // Any "ordinary" / uniform data for this object - Slang::RefPtr<CPUBufferResource> m_bufferResource; - Slang::RefPtr<CPUBufferView> m_bufferView; - - Index getCount() { return m_ordinaryData.getCount(); } - void setCount(Index count) { m_ordinaryData.setCount(count); } - char* getBuffer() { return m_ordinaryData.getBuffer(); } - - ~CPUShaderObjectData() - { - // m_bufferResource's data is managed by m_ordinaryData so we - // set it to null to prevent m_bufferResource from freeing it. - if (m_bufferResource) - m_bufferResource->m_data = nullptr; - } - - /// Returns a StructuredBuffer resource view for GPU access into the buffer content. - /// Creates a StructuredBuffer resource if it has not been created. - ResourceViewBase* getResourceView( - RendererBase* device, - slang::TypeLayoutReflection* elementLayout, - slang::BindingType bindingType) - { - SLANG_UNUSED(device); - if (!m_bufferResource) - { - IBufferResource::Desc desc = {}; - desc.type = IResource::Type::Buffer; - desc.elementSize = (int)elementLayout->getSize(); - m_bufferResource = new CPUBufferResource(desc); - - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - m_bufferView = new CPUBufferView(viewDesc, m_bufferResource); - - } - m_bufferResource->getDesc()->sizeInBytes = m_ordinaryData.getCount(); - m_bufferResource->m_data = m_ordinaryData.getBuffer(); - return m_bufferView.Ptr(); - } -}; - -class CPUShaderObject - : public ShaderObjectBaseImpl<CPUShaderObject, CPUShaderObjectLayout, CPUShaderObjectData> -{ - typedef ShaderObjectBaseImpl<CPUShaderObject, CPUShaderObjectLayout, CPUShaderObjectData> Super; - -public: - List<RefPtr<CPUResourceView>> m_resources; - - virtual SLANG_NO_THROW Result SLANG_MCALL - init(IDevice* device, CPUShaderObjectLayout* typeLayout); - - virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override { return 0; } - virtual SLANG_NO_THROW Result SLANG_MCALL - getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override - { - *outEntryPoint = nullptr; - return SLANG_OK; - } - - virtual SLANG_NO_THROW const void* SLANG_MCALL getRawData() override - { - return m_data.getBuffer(); - } - - virtual SLANG_NO_THROW size_t SLANG_MCALL getSize() override - { - return (size_t)m_data.getCount(); - } - - virtual SLANG_NO_THROW Result SLANG_MCALL - setData(ShaderOffset const& offset, void const* data, size_t size) override - { - size = Math::Min(size, size_t(m_data.getCount() - offset.uniformOffset)); - memcpy((char*)m_data.getBuffer() + offset.uniformOffset, data, size); - return SLANG_OK; - } - virtual SLANG_NO_THROW Result SLANG_MCALL - setResource(ShaderOffset const& offset, IResourceView* inView) override - { - auto layout = getLayout(); - - auto bindingRangeIndex = offset.bindingRangeIndex; - SLANG_ASSERT(bindingRangeIndex >= 0); - SLANG_ASSERT(bindingRangeIndex < layout->m_bindingRanges.getCount()); - - auto& bindingRange = layout->m_bindingRanges[bindingRangeIndex]; - auto viewIndex = bindingRange.baseIndex + offset.bindingArrayIndex; - - - auto view = static_cast<CPUResourceView*>(inView); - m_resources[viewIndex] = view; - - switch( view->getViewKind() ) - { - case CPUResourceView::Kind::Texture: - { - auto textureView = static_cast<CPUTextureView*>(view); - - slang_prelude::IRWTexture* textureObj = textureView; - SLANG_RETURN_ON_FAIL(setData(offset, &textureObj, sizeof(textureObj))); - } - break; - - case CPUResourceView::Kind::Buffer: - { - auto bufferView = static_cast<CPUBufferView*>(view); - auto buffer = bufferView->getBuffer(); - auto desc = *buffer->getDesc(); - - void* dataPtr = buffer->m_data; - size_t size = desc.sizeInBytes; - if (desc.elementSize > 1) - size /= desc.elementSize; - - auto ptrOffset = offset; - SLANG_RETURN_ON_FAIL(setData(ptrOffset, &dataPtr, sizeof(dataPtr))); - - auto sizeOffset = offset; - sizeOffset.uniformOffset += sizeof(dataPtr); - SLANG_RETURN_ON_FAIL(setData(sizeOffset, &size, sizeof(size))); - } - break; - } - - return SLANG_OK; - } - virtual SLANG_NO_THROW Result SLANG_MCALL - setObject(ShaderOffset const& offset, IShaderObject* object) override - { - SLANG_RETURN_ON_FAIL(Super::setObject(offset, object)); - - auto bindingRangeIndex = offset.bindingRangeIndex; - auto& bindingRange = getLayout()->m_bindingRanges[bindingRangeIndex]; - - CPUShaderObject* subObject = static_cast<CPUShaderObject*>(object); - - switch (bindingRange.bindingType) - { - default: - { - void* bufferPtr = subObject->m_data.getBuffer(); - SLANG_RETURN_ON_FAIL(setData(offset, &bufferPtr, sizeof(void*))); - } - break; - case slang::BindingType::ExistentialValue: - case slang::BindingType::RawBuffer: - case slang::BindingType::MutableRawBuffer: - break; - } - return SLANG_OK; - } - virtual SLANG_NO_THROW Result SLANG_MCALL - setSampler(ShaderOffset const& offset, ISamplerState* sampler) override - { - SLANG_UNUSED(sampler); - SLANG_UNUSED(offset); - return SLANG_OK; - } - virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler( - ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) override - { - SLANG_UNUSED(sampler); - setResource(offset, textureView); - return SLANG_OK; - } - - char* getDataBuffer() { return m_data.getBuffer(); } -}; - -class CPUMutableShaderObject : public MutableShaderObject<CPUMutableShaderObject, CPUShaderObjectLayout> -{}; - -class CPUEntryPointShaderObject : public CPUShaderObject -{ -public: - CPUEntryPointLayout* getLayout() { return static_cast<CPUEntryPointLayout*>(m_layout.Ptr()); } -}; - -class CPURootShaderObject : public CPUShaderObject -{ -public: - virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; } - virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; } - - SlangResult init(IDevice* device, CPUProgramLayout* programLayout); - - CPUProgramLayout* getLayout() { return static_cast<CPUProgramLayout*>(m_layout.Ptr()); } - - CPUEntryPointShaderObject* getEntryPoint(Index index) { return m_entryPoints[index]; } - - List<RefPtr<CPUEntryPointShaderObject>> m_entryPoints; - - virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override { return (GfxCount)m_entryPoints.getCount(); } - virtual SLANG_NO_THROW Result SLANG_MCALL - getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override - { - returnComPtr(outEntryPoint, m_entryPoints[index]); - return SLANG_OK; - } - virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override - { - SLANG_RETURN_ON_FAIL(CPUShaderObject::collectSpecializationArgs(args)); - for (auto& entryPoint : m_entryPoints) - { - SLANG_RETURN_ON_FAIL(entryPoint->collectSpecializationArgs(args)); - } - return SLANG_OK; - } -}; - -class CPUShaderProgram : public ShaderProgramBase -{ -public: - RefPtr<CPUProgramLayout> layout; - - ~CPUShaderProgram() - { - } -}; - -class CPUPipelineState : public PipelineStateBase -{ -public: - CPUShaderProgram* getProgram() { return static_cast<CPUShaderProgram*>(m_program.Ptr()); } - - void init(const ComputePipelineStateDesc& inDesc) - { - PipelineStateDesc pipelineDesc; - pipelineDesc.type = PipelineType::Compute; - pipelineDesc.compute = inDesc; - initializeBase(pipelineDesc); - } -}; - -class CPUQueryPool : public QueryPoolBase -{ -public: - List<uint64_t> m_queries; - Result init(const IQueryPool::Desc& desc) - { - m_queries.setCount(desc.count); - return SLANG_OK; - } - virtual SLANG_NO_THROW Result SLANG_MCALL getResult( - GfxIndex queryIndex, GfxCount count, uint64_t* data) override - { - for (GfxCount i = 0; i < count; i++) - { - data[i] = m_queries[queryIndex + i]; - } - return SLANG_OK; - } -}; - -class CPUDevice : public ImmediateComputeDeviceBase -{ -private: - RefPtr<CPUPipelineState> m_currentPipeline = nullptr; - RefPtr<CPURootShaderObject> m_currentRootObject = nullptr; - DeviceInfo m_info; - - virtual void setPipelineState(IPipelineState* state) override - { - m_currentPipeline = static_cast<CPUPipelineState*>(state); - } - - virtual void bindRootShaderObject(IShaderObject* object) override - { - m_currentRootObject = static_cast<CPURootShaderObject*>(object); - } - - virtual void dispatchCompute(int x, int y, int z) override - { - int entryPointIndex = 0; - int targetIndex = 0; - - // Specialize the compute kernel based on the shader object bindings. - RefPtr<PipelineStateBase> newPipeline; - maybeSpecializePipeline(m_currentPipeline, m_currentRootObject, newPipeline); - m_currentPipeline = static_cast<CPUPipelineState*>(newPipeline.Ptr()); - - auto program = m_currentPipeline->getProgram(); - auto entryPointLayout = - m_currentRootObject->getLayout()->getEntryPoint(entryPointIndex); - auto entryPointName = entryPointLayout->getEntryPointName(); - - auto entryPointObject = m_currentRootObject->getEntryPoint(entryPointIndex); - - ComPtr<ISlangSharedLibrary> sharedLibrary; - ComPtr<ISlangBlob> diagnostics; - auto compileResult = program->slangGlobalScope->getEntryPointHostCallable( - entryPointIndex, targetIndex, sharedLibrary.writeRef(), diagnostics.writeRef()); - if (diagnostics) - { - getDebugCallback()->handleMessage( - compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error, - DebugMessageSource::Slang, - (char*)diagnostics->getBufferPointer()); - } - if (SLANG_FAILED(compileResult)) return; - - auto func = (slang_prelude::ComputeFunc) sharedLibrary->findSymbolAddressByName(entryPointName); - - slang_prelude::ComputeVaryingInput varyingInput; - varyingInput.startGroupID.x = 0; - varyingInput.startGroupID.y = 0; - varyingInput.startGroupID.z = 0; - varyingInput.endGroupID.x = x; - varyingInput.endGroupID.y = y; - varyingInput.endGroupID.z = z; - - auto globalParamsData = m_currentRootObject->getDataBuffer(); - auto entryPointParamsData = entryPointObject->getDataBuffer(); - func(&varyingInput, entryPointParamsData, globalParamsData); - } - - virtual void copyBuffer( - IBufferResource* dst, - size_t dstOffset, - IBufferResource* src, - size_t srcOffset, - size_t size) override - { - auto dstImpl = static_cast<CPUBufferResource*>(dst); - auto srcImpl = static_cast<CPUBufferResource*>(src); - memcpy( - (uint8_t*)dstImpl->m_data + dstOffset, - (uint8_t*)srcImpl->m_data + srcOffset, - size); - } - -public: - ~CPUDevice() - { - m_currentPipeline = nullptr; - m_currentRootObject = nullptr; - } - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override - { - SLANG_RETURN_ON_FAIL(slangContext.initialize( - desc.slang, - SLANG_SHADER_HOST_CALLABLE, - "sm_5_1", - makeArray(slang::PreprocessorMacroDesc{ "__CPU__", "1" }).getView())); - - SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc)); - - // Initialize DeviceInfo - { - m_info.deviceType = DeviceType::CPU; - m_info.bindingStyle = BindingStyle::CUDA; - m_info.projectionStyle = ProjectionStyle::DirectX; - m_info.apiName = "CPU"; - static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; - ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity)); - m_info.adapterName = "CPU"; - m_info.timestampFrequency = 1000000000; - } - - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( - const ITextureResource::Desc& desc, - const ITextureResource::SubresourceData* initData, - ITextureResource** outResource) override - { - TextureResource::Desc srcDesc = fixupTextureDesc(desc); - - RefPtr<CPUTextureResource> texture = new CPUTextureResource(srcDesc); - - SLANG_RETURN_ON_FAIL(texture->init(initData)); - - returnComPtr(outResource, texture); - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource( - const IBufferResource::Desc& descIn, - const void* initData, - IBufferResource** outResource) override - { - auto desc = fixupBufferDesc(descIn); - RefPtr<CPUBufferResource> resource = new CPUBufferResource(desc); - SLANG_RETURN_ON_FAIL(resource->init()); - if (initData) - { - SLANG_RETURN_ON_FAIL(resource->setData(0, desc.sizeInBytes, initData)); - } - returnComPtr(outResource, resource); - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView( - ITextureResource* inTexture, IResourceView::Desc const& desc, IResourceView** outView) override - { - auto texture = static_cast<CPUTextureResource*>(inTexture); - RefPtr<CPUTextureView> view = new CPUTextureView(desc, texture); - returnComPtr(outView, view); - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView( - IBufferResource* inBuffer, - IBufferResource* counterBuffer, - IResourceView::Desc const& desc, - IResourceView** outView) override - { - auto buffer = static_cast<CPUBufferResource*>(inBuffer); - RefPtr<CPUBufferView> view = new CPUBufferView(desc, buffer); - returnComPtr(outView, view); - return SLANG_OK; - } - - virtual Result createShaderObjectLayout( - slang::TypeLayoutReflection* typeLayout, - ShaderObjectLayoutBase** outLayout) override - { - RefPtr<CPUShaderObjectLayout> cpuLayout = new CPUShaderObjectLayout(this, typeLayout); - returnRefPtrMove(outLayout, cpuLayout); - - return SLANG_OK; - } - - virtual Result createShaderObject( - ShaderObjectLayoutBase* layout, - IShaderObject** outObject) override - { - auto cpuLayout = static_cast<CPUShaderObjectLayout*>(layout); - - RefPtr<CPUShaderObject> result = new CPUShaderObject(); - SLANG_RETURN_ON_FAIL(result->init(this, cpuLayout)); - returnComPtr(outObject, result); - - return SLANG_OK; - } - - virtual Result createMutableShaderObject( - ShaderObjectLayoutBase* layout, - IShaderObject** outObject) override - { - auto cpuLayout = static_cast<CPUShaderObjectLayout*>(layout); - - RefPtr<CPUMutableShaderObject> result = new CPUMutableShaderObject(); - SLANG_RETURN_ON_FAIL(result->init(this, cpuLayout)); - returnComPtr(outObject, result); - - return SLANG_OK; - } - - virtual Result createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject) override - { - auto cpuProgram = static_cast<CPUShaderProgram*>(program); - auto cpuProgramLayout = cpuProgram->layout; - - RefPtr<CPURootShaderObject> result = new CPURootShaderObject(); - SLANG_RETURN_ON_FAIL(result->init(this, cpuProgramLayout)); - returnRefPtrMove(outObject, result); - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createProgram( - const IShaderProgram::Desc& desc, - IShaderProgram** outProgram, - ISlangBlob** outDiagnosticBlob) override - { - RefPtr<CPUShaderProgram> cpuProgram = new CPUShaderProgram(); - cpuProgram->init(desc); - auto slangGlobalScope = cpuProgram->linkedProgram; - if( slangGlobalScope ) - { - auto slangProgramLayout = slangGlobalScope->getLayout(); - if(!slangProgramLayout) - return SLANG_FAIL; - - RefPtr<CPUProgramLayout> cpuProgramLayout = new CPUProgramLayout(this, slangProgramLayout); - cpuProgramLayout->m_programLayout = slangProgramLayout; - - cpuProgram->layout = cpuProgramLayout; - } - - returnComPtr(outProgram, cpuProgram); - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( - const ComputePipelineStateDesc& desc, IPipelineState** outState) override - { - RefPtr<CPUPipelineState> state = new CPUPipelineState(); - state->init(desc); - returnComPtr(outState, state); - return Result(); - } - - virtual SLANG_NO_THROW Result SLANG_MCALL createQueryPool( - const IQueryPool::Desc& desc, IQueryPool** outPool) override - { - RefPtr<CPUQueryPool> pool = new CPUQueryPool(); - pool->init(desc); - returnComPtr(outPool, pool); - return SLANG_OK; - } - - virtual void writeTimestamp(IQueryPool* pool, GfxIndex index) override - { - static_cast<CPUQueryPool*>(pool)->m_queries[index] = - std::chrono::high_resolution_clock::now().time_since_epoch().count(); - } - - virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const override - { - return m_info; - } - -public: - - virtual SLANG_NO_THROW Result SLANG_MCALL - createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) override - { - SLANG_UNUSED(desc); - *outSampler = nullptr; - return SLANG_OK; - } - - virtual void submitGpuWork() override {} - virtual void waitForGpu() override {} - virtual void* map(IBufferResource* buffer, MapFlavor flavor) override - { - SLANG_UNUSED(flavor); - auto bufferImpl = static_cast<CPUBufferResource*>(buffer); - return bufferImpl->m_data; - } - virtual void unmap(IBufferResource* buffer, size_t offsetWritten, size_t sizeWritten) override - { - SLANG_UNUSED(buffer); - SLANG_UNUSED(offsetWritten); - SLANG_UNUSED(sizeWritten); - } -}; - -SlangResult CPUShaderObject::init(IDevice* device, CPUShaderObjectLayout* typeLayout) -{ - m_layout = typeLayout; - - // If the layout tells us that there is any uniform data, - // then we need to allocate a constant buffer to hold that data. - // - // TODO: Do we need to allocate a shadow copy for use from - // the CPU? - // - // TODO: When/where do we bind this constant buffer into - // a descriptor set for later use? - // - auto slangLayout = getLayout()->getElementTypeLayout(); - size_t uniformSize = slangLayout->getSize(); - m_data.setCount(uniformSize); - - // If the layout specifies that we have any resources or sub-objects, - // then we need to size the appropriate arrays to account for them. - // - // Note: the counts here are the *total* number of resources/sub-objects - // and not just the number of resource/sub-object ranges. - // - m_resources.setCount(typeLayout->getResourceCount()); - m_objects.setCount(typeLayout->getSubObjectCount()); - - for (auto subObjectRange : getLayout()->subObjectRanges) - { - RefPtr<CPUShaderObjectLayout> subObjectLayout = subObjectRange.layout; - - // In the case where the sub-object range represents an - // existential-type leaf field (e.g., an `IBar`), we - // cannot pre-allocate the object(s) to go into that - // range, since we can't possibly know what to allocate - // at this point. - // - if (!subObjectLayout) - continue; - auto _debugname = subObjectLayout->getElementTypeLayout()->getName(); - - // - // Otherwise, we will allocate a sub-object to fill - // in each entry in this range, based on the layout - // information we already have. - - auto& bindingRangeInfo = getLayout()->m_bindingRanges[subObjectRange.bindingRangeIndex]; - for (Index i = 0; i < bindingRangeInfo.count; ++i) - { - RefPtr<CPUShaderObject> subObject = new CPUShaderObject(); - SLANG_RETURN_ON_FAIL(subObject->init(device, subObjectLayout)); - - ShaderOffset offset; - offset.uniformOffset = bindingRangeInfo.uniformOffset + sizeof(void*) * i; - offset.bindingRangeIndex = (GfxIndex)subObjectRange.bindingRangeIndex; - offset.bindingArrayIndex = (GfxIndex)i; - - SLANG_RETURN_ON_FAIL(setObject(offset, subObject)); - } - } - return SLANG_OK; -} - -SlangResult CPURootShaderObject::init(IDevice* device, CPUProgramLayout* programLayout) -{ - SLANG_RETURN_ON_FAIL(CPUShaderObject::init(device, programLayout)); - for (auto& entryPoint : programLayout->m_entryPointLayouts) - { - RefPtr<CPUEntryPointShaderObject> object = new CPUEntryPointShaderObject(); - SLANG_RETURN_ON_FAIL(object->init(device, entryPoint)); - m_entryPoints.add(object); - } - return SLANG_OK; -} - -SlangResult SLANG_MCALL createCPUDevice(const IDevice::Desc* desc, IDevice** outDevice) -{ - RefPtr<CPUDevice> result = new CPUDevice(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc)); - returnComPtr(outDevice, result); - return SLANG_OK; -} - -} diff --git a/tools/gfx/cpu/render-cpu.h b/tools/gfx/cpu/render-cpu.h deleted file mode 100644 index fca57aa4d..000000000 --- a/tools/gfx/cpu/render-cpu.h +++ /dev/null @@ -1,11 +0,0 @@ -// render-cpu.h -#pragma once - -#include "../renderer-shared.h" - -namespace gfx -{ - -SlangResult SLANG_MCALL createCPUDevice(const IDevice::Desc* desc, IDevice** outDevice); - -} diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp index 880e61c61..2ec163469 100644 --- a/tools/gfx/render.cpp +++ b/tools/gfx/render.cpp @@ -2,7 +2,6 @@ #include "renderer-shared.h" #include "../../source/core/slang-math.h" #include "open-gl/render-gl.h" -#include "cpu/render-cpu.h" #include "debug-layer.h" #include <cstring> @@ -14,6 +13,7 @@ Result SLANG_MCALL createD3D11Device(const IDevice::Desc* desc, IDevice** outDev Result SLANG_MCALL createD3D12Device(const IDevice::Desc* desc, IDevice** outDevice); Result SLANG_MCALL createVKDevice(const IDevice::Desc* desc, IDevice** outDevice); Result SLANG_MCALL createCUDADevice(const IDevice::Desc* desc, IDevice** outDevice); +Result SLANG_MCALL createCPUDevice(const IDevice::Desc* desc, IDevice** outDevice); static bool debugLayerEnabled = false; |
