summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/visual-studio/gfx/gfx.vcxproj22
-rw-r--r--build/visual-studio/gfx/gfx.vcxproj.filters58
-rw-r--r--tools/gfx/cpu/cpu-base.h42
-rw-r--r--tools/gfx/cpu/cpu-buffer.cpp54
-rw-r--r--tools/gfx/cpu/cpu-buffer.h36
-rw-r--r--tools/gfx/cpu/cpu-device.cpp293
-rw-r--r--tools/gfx/cpu/cpu-device.h98
-rw-r--r--tools/gfx/cpu/cpu-helper-functions.cpp18
-rw-r--r--tools/gfx/cpu/cpu-helper-functions.h11
-rw-r--r--tools/gfx/cpu/cpu-pipeline-state.cpp27
-rw-r--r--tools/gfx/cpu/cpu-pipeline-state.h21
-rw-r--r--tools/gfx/cpu/cpu-query.cpp28
-rw-r--r--tools/gfx/cpu/cpu-query.h22
-rw-r--r--tools/gfx/cpu/cpu-resource-views.cpp176
-rw-r--r--tools/gfx/cpu/cpu-resource-views.h82
-rw-r--r--tools/gfx/cpu/cpu-shader-object-layout.cpp168
-rw-r--r--tools/gfx/cpu/cpu-shader-object-layout.h97
-rw-r--r--tools/gfx/cpu/cpu-shader-object.cpp314
-rw-r--r--tools/gfx/cpu/cpu-shader-object.h98
-rw-r--r--tools/gfx/cpu/cpu-shader-program.h25
-rw-r--r--tools/gfx/cpu/cpu-texture.cpp231
-rw-r--r--tools/gfx/cpu/cpu-texture.h130
-rw-r--r--tools/gfx/cpu/render-cpu.cpp1427
-rw-r--r--tools/gfx/cpu/render-cpu.h11
-rw-r--r--tools/gfx/render.cpp2
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;