summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx-unit-test/compute-smoke.cpp39
-rw-r--r--tools/gfx-unit-test/gfx-test-util.cpp87
-rw-r--r--tools/gfx-unit-test/gfx-test-util.h33
-rw-r--r--tools/gfx-unit-test/mutable-shader-object.cpp135
-rw-r--r--tools/gfx-unit-test/mutable-shader-object.slang68
-rw-r--r--tools/gfx/command-writer.h29
-rw-r--r--tools/gfx/cpu/render-cpu.cpp35
-rw-r--r--tools/gfx/cuda/render-cuda.cpp45
-rw-r--r--tools/gfx/d3d11/render-d3d11.cpp134
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp115
-rw-r--r--tools/gfx/debug-layer.cpp59
-rw-r--r--tools/gfx/debug-layer.h45
-rw-r--r--tools/gfx/immediate-renderer-base.cpp20
-rw-r--r--tools/gfx/mutable-shader-object.h215
-rw-r--r--tools/gfx/open-gl/render-gl.cpp47
-rw-r--r--tools/gfx/renderer-shared.cpp45
-rw-r--r--tools/gfx/renderer-shared.h114
-rw-r--r--tools/gfx/simple-transient-resource-heap.h19
-rw-r--r--tools/gfx/transient-resource-heap-base.h18
-rw-r--r--tools/gfx/vulkan/render-vk.cpp134
-rw-r--r--tools/slang-test/options.cpp4
-rw-r--r--tools/slang-test/options.h3
-rw-r--r--tools/slang-test/slang-test-main.cpp8
-rw-r--r--tools/slang-test/test-reporter.cpp4
24 files changed, 1027 insertions, 428 deletions
diff --git a/tools/gfx-unit-test/compute-smoke.cpp b/tools/gfx-unit-test/compute-smoke.cpp
index 9038cd5b6..9a8298bf8 100644
--- a/tools/gfx-unit-test/compute-smoke.cpp
+++ b/tools/gfx-unit-test/compute-smoke.cpp
@@ -96,49 +96,14 @@ namespace gfx_test
Slang::makeArray<float>(11.0f, 12.0f, 13.0f, 14.0f));
}
- void computeSmokeTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api)
- {
- if ((api & context->enabledApis) == 0)
- {
- SLANG_IGNORE_TEST
- }
- Slang::ComPtr<IDevice> device;
- IDevice::Desc deviceDesc = {};
- switch (api)
- {
- case Slang::RenderApiFlag::D3D11:
- deviceDesc.deviceType = gfx::DeviceType::DirectX11;
- break;
- case Slang::RenderApiFlag::D3D12:
- deviceDesc.deviceType = gfx::DeviceType::DirectX12;
- break;
- case Slang::RenderApiFlag::Vulkan:
- deviceDesc.deviceType = gfx::DeviceType::Vulkan;
- break;
- default:
- SLANG_IGNORE_TEST
- }
- deviceDesc.slang.slangGlobalSession = context->slangGlobalSession;
- const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" };
- deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths);
- deviceDesc.slang.searchPaths = searchPaths;
- auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef());
- if (SLANG_FAILED(createDeviceResult))
- {
- SLANG_IGNORE_TEST
- }
-
- computeSmokeTestImpl(device, context);
- }
-
SLANG_UNIT_TEST(computeSmokeD3D11)
{
- computeSmokeTestAPI(unitTestContext, Slang::RenderApiFlag::D3D11);
+ runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11);
}
SLANG_UNIT_TEST(computeSmokeVulkan)
{
- computeSmokeTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan);
+ runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
}
}
diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp
index 1b23047a1..f1dd6be58 100644
--- a/tools/gfx-unit-test/gfx-test-util.cpp
+++ b/tools/gfx-unit-test/gfx-test-util.cpp
@@ -3,6 +3,14 @@
#include <slang-com-ptr.h>
+#define GFX_ENABLE_RENDERDOC_INTEGRATION 0
+
+#if GFX_ENABLE_RENDERDOC_INTEGRATION
+# include "external/renderdoc_app.h"
+# define WIN32_LEAN_AND_MEAN
+# include <Windows.h>
+#endif
+
using Slang::ComPtr;
namespace gfx_test
@@ -64,23 +72,76 @@ namespace gfx_test
ComPtr<ISlangBlob> resultBlob;
GFX_CHECK_CALL_ABORT(device->readBufferResource(
buffer, 0, expectedBufferSize, resultBlob.writeRef()));
- if (resultBlob->getBufferSize() < expectedBufferSize)
+ SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize);
+ // Compare results.
+ SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), expectedResult, expectedBufferSize) == 0);
+ }
+
+ Slang::ComPtr<gfx::IDevice> createTestingDevice(UnitTestContext* context, Slang::RenderApiFlag::Enum api)
+ {
+ Slang::ComPtr<gfx::IDevice> device;
+ gfx::IDevice::Desc deviceDesc = {};
+ switch (api)
{
- getTestReporter()->addResult(TestResult::Fail);
- return;
+ case Slang::RenderApiFlag::D3D11:
+ deviceDesc.deviceType = gfx::DeviceType::DirectX11;
+ break;
+ case Slang::RenderApiFlag::D3D12:
+ deviceDesc.deviceType = gfx::DeviceType::DirectX12;
+ break;
+ case Slang::RenderApiFlag::Vulkan:
+ deviceDesc.deviceType = gfx::DeviceType::Vulkan;
+ break;
+ case Slang::RenderApiFlag::CPU:
+ deviceDesc.deviceType = gfx::DeviceType::CPU;
+ break;
+ case Slang::RenderApiFlag::CUDA:
+ deviceDesc.deviceType = gfx::DeviceType::CUDA;
+ break;
+ case Slang::RenderApiFlag::OpenGl:
+ deviceDesc.deviceType = gfx::DeviceType::OpenGl;
+ break;
+ default:
+ SLANG_IGNORE_TEST
}
-
- // Compare results.
- auto result = reinterpret_cast<const uint8_t*>(resultBlob->getBufferPointer());
- for (int i = 0; i < expectedBufferSize; i++)
+ deviceDesc.slang.slangGlobalSession = context->slangGlobalSession;
+ const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" };
+ deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths);
+ deviceDesc.slang.searchPaths = searchPaths;
+ auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef());
+ if (SLANG_FAILED(createDeviceResult))
{
- if (expectedResult[i] != result[i])
- {
- getTestReporter()->addResult(TestResult::Fail);
- return;
- }
+ SLANG_IGNORE_TEST
+ }
+ return device;
+ }
+#if GFX_ENABLE_RENDERDOC_INTEGRATION
+ RENDERDOC_API_1_1_2* rdoc_api = NULL;
+ void initializeRenderDoc()
+ {
+ if (HMODULE mod = GetModuleHandleA("renderdoc.dll"))
+ {
+ pRENDERDOC_GetAPI RENDERDOC_GetAPI =
+ (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
+ int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api);
+ assert(ret == 1);
}
- getTestReporter()->addResult(TestResult::Pass);
}
+ void renderDocBeginFrame()
+ {
+ if (!rdoc_api) initializeRenderDoc();
+ if (rdoc_api) rdoc_api->StartFrameCapture(nullptr, nullptr);
+ }
+ void renderDocEndFrame()
+ {
+ if (rdoc_api)
+ rdoc_api->EndFrameCapture(nullptr, nullptr);
+ _fgetchar();
+ }
+#else
+ void initializeRenderDoc() {}
+ void renderDocBeginFrame() {}
+ void renderDocEndFrame() {}
+#endif
}
diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h
index c7db19394..b357a310a 100644
--- a/tools/gfx-unit-test/gfx-test-util.h
+++ b/tools/gfx-unit-test/gfx-test-util.h
@@ -2,6 +2,8 @@
#include "slang-gfx.h"
#include "source/core/slang-basic.h"
+#include "source/core/slang-render-api-util.h"
+#include "tools/unit-test/slang-unit-test.h"
namespace gfx_test
{
@@ -35,6 +37,37 @@ namespace gfx_test
memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize);
return compareComputeResult(device, buffer, expectedBuffer.getBuffer(), bufferSize);
}
+
+ Slang::ComPtr<gfx::IDevice> createTestingDevice(UnitTestContext* context, Slang::RenderApiFlag::Enum api);
+
+ void initializeRenderDoc();
+ void renderDocBeginFrame();
+ void renderDocEndFrame();
+
+ template<typename ImplFunc>
+ void runTestImpl(const ImplFunc& f, UnitTestContext* context, Slang::RenderApiFlag::Enum api)
+ {
+ if ((api & context->enabledApis) == 0)
+ {
+ SLANG_IGNORE_TEST
+ }
+ auto device = createTestingDevice(context, api);
+ if (!device)
+ {
+ SLANG_IGNORE_TEST
+ }
+ try
+ {
+ renderDocBeginFrame();
+ f(device, context);
+ }
+ catch (AbortTestException& e)
+ {
+ renderDocEndFrame();
+ throw e;
+ }
+ renderDocEndFrame();
+ }
#define GFX_CHECK_CALL(x) SLANG_CHECK(!SLANG_FAILED(x))
#define GFX_CHECK_CALL_ABORT(x) SLANG_CHECK_ABORT(!SLANG_FAILED(x))
diff --git a/tools/gfx-unit-test/mutable-shader-object.cpp b/tools/gfx-unit-test/mutable-shader-object.cpp
new file mode 100644
index 000000000..efaf95761
--- /dev/null
+++ b/tools/gfx-unit-test/mutable-shader-object.cpp
@@ -0,0 +1,135 @@
+#include "tools/unit-test/slang-unit-test.h"
+
+#include "slang-gfx.h"
+#include "gfx-test-util.h"
+#include "tools/gfx-util/shader-cursor.h"
+#include "source/core/slang-basic.h"
+
+using namespace gfx;
+
+namespace gfx_test
+{
+ void mutableShaderObjectTestImpl(IDevice* device, UnitTestContext* context)
+ {
+ Slang::ComPtr<ITransientResourceHeap> transientHeap;
+ ITransientResourceHeap::Desc transientHeapDesc = {};
+ transientHeapDesc.constantBufferSize = 4096;
+ GFX_CHECK_CALL_ABORT(
+ device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef()));
+
+ ComPtr<IShaderProgram> shaderProgram;
+ slang::ProgramLayout* slangReflection;
+ GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "mutable-shader-object", "computeMain", slangReflection));
+
+ ComputePipelineStateDesc pipelineDesc = {};
+ pipelineDesc.program = shaderProgram.get();
+ ComPtr<gfx::IPipelineState> pipelineState;
+ GFX_CHECK_CALL_ABORT(
+ device->createComputePipelineState(pipelineDesc, pipelineState.writeRef()));
+
+ float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ const int numberCount = SLANG_COUNT_OF(initialData);
+ IBufferResource::Desc bufferDesc = {};
+ bufferDesc.sizeInBytes = sizeof(initialData);
+ bufferDesc.format = gfx::Format::Unknown;
+ bufferDesc.elementSize = sizeof(float);
+ bufferDesc.allowedStates = ResourceStateSet(
+ ResourceState::ShaderResource,
+ ResourceState::UnorderedAccess,
+ ResourceState::CopyDestination,
+ ResourceState::CopySource);
+ bufferDesc.defaultState = ResourceState::UnorderedAccess;
+ bufferDesc.cpuAccessFlags = AccessFlag::Write | AccessFlag::Read;
+
+ ComPtr<IBufferResource> numbersBuffer;
+ GFX_CHECK_CALL_ABORT(device->createBufferResource(
+ bufferDesc,
+ (void*)initialData,
+ numbersBuffer.writeRef()));
+
+ ComPtr<IResourceView> bufferView;
+ IResourceView::Desc viewDesc = {};
+ viewDesc.type = IResourceView::Type::UnorderedAccess;
+ viewDesc.format = Format::Unknown;
+ GFX_CHECK_CALL_ABORT(device->createBufferView(numbersBuffer, viewDesc, bufferView.writeRef()));
+
+ {
+ slang::TypeReflection* addTransformerType =
+ slangReflection->findTypeByName("AddTransformer");
+
+ ComPtr<IShaderObject> transformer;
+ GFX_CHECK_CALL_ABORT(device->createMutableShaderObject(
+ addTransformerType, ShaderObjectContainerType::None, transformer.writeRef()));
+ // Set the `c` field of the `AddTransformer`.
+ float c = 1.0f;
+ ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float));
+
+ ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics };
+ auto queue = device->createCommandQueue(queueDesc);
+
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto encoder = commandBuffer->encodeComputeCommands();
+
+ auto rootObject = encoder->bindPipeline(pipelineState);
+
+ auto entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0));
+
+ entryPointCursor.getPath("buffer").setResource(bufferView);
+
+ // Bind the previously created transformer object to root object.
+ ComPtr<IShaderObject> transformerVersion;
+ transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef());
+ entryPointCursor.getPath("transformer").setObject(transformerVersion);
+
+ encoder->dispatchCompute(1, 1, 1);
+ encoder->endEncoding();
+
+ auto barrierEncoder = commandBuffer->encodeResourceCommands();
+ barrierEncoder->bufferBarrier(1, numbersBuffer.readRef(), ResourceState::UnorderedAccess, ResourceState::UnorderedAccess);
+ barrierEncoder->endEncoding();
+
+ encoder = commandBuffer->encodeComputeCommands();
+
+ rootObject = encoder->bindPipeline(pipelineState);
+ entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0));
+
+ // Mutate `transformer` object and run again.
+ c = 2.0f;
+ ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float));
+ transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef());
+ entryPointCursor.getPath("buffer").setResource(bufferView);
+ entryPointCursor.getPath("transformer").setObject(transformerVersion);
+ encoder->dispatchCompute(1, 1, 1);
+ encoder->endEncoding();
+
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+ queue->wait();
+ }
+
+ compareComputeResult(
+ device,
+ numbersBuffer,
+ Slang::makeArray<float>(3.0f, 4.0f, 5.0f, 6.0f));
+ }
+
+ //SLANG_UNIT_TEST(mutableShaderObjectCPU)
+ //{
+ // runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::CPU);
+ //}
+
+ SLANG_UNIT_TEST(mutableShaderObjectD3D11)
+ {
+ runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11);
+ }
+
+ SLANG_UNIT_TEST(mutableShaderObjectD3D12)
+ {
+ runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
+ }
+
+ SLANG_UNIT_TEST(mutableShaderObjectVulkan)
+ {
+ runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
+ }
+}
diff --git a/tools/gfx-unit-test/mutable-shader-object.slang b/tools/gfx-unit-test/mutable-shader-object.slang
new file mode 100644
index 000000000..42d520f13
--- /dev/null
+++ b/tools/gfx-unit-test/mutable-shader-object.slang
@@ -0,0 +1,68 @@
+// mutable-shader-object.slang
+
+// This is a copy of `shader-object.slang` in `shader-object` example
+// for use by mutable-shader-object gfx unit test.
+
+// This file implements a simple compute shader that transforms
+// input floating point numbers stored in a `RWStructuredBuffer`.
+// Specifically, for each number x from input buffer, compute
+// f(x) and store the result back in the same buffer.
+
+// The compute shader supports multiple transformation functions,
+// such add(x, c) which returns x+c, or mul(x, c) which returns x*c.
+// This functions are implemented as types that conforms to the
+// `ITransformer` interface.
+
+// The main entry point function takes a parameter of `ITransformer`
+// type, and applies the transformation to numbers in the input
+// buffer. By defining the shader parameter using interfaces,
+// we enable the flexiblity to generate either specialized compute
+// kernels that performs specific transformation or a general
+// kernel that can perform any transformations encoded by the
+// parameter at run-time, without changing any shader code or
+// host-application logic for setting and preparing shader parameters.
+
+// Defines the transformer interface, which implements a single
+// `transform` operation.
+interface ITransformer
+{
+ float transform(float x);
+}
+
+// Represents a transform function f(x) = x + c.
+struct AddTransformer : ITransformer
+{
+ float c;
+ float transform(float x) { return x + c; }
+};
+
+// Represents a transform function f(x) = x * c.
+struct MulTransformer : ITransformer
+{
+ float c;
+ float transform(float x) { return x * c; }
+};
+
+// Represents a composite function f(x) = f0(f1(x));
+struct CompositeTransformer : ITransformer
+{
+ ITransformer func0;
+ ITransformer func1;
+ float transform(float x)
+ {
+ return func0.transform(func1.transform(x));
+ }
+};
+
+// Main entry-point. Applies the transformation encoded by `transformer`
+// to all elements in `buffer`.
+[shader("compute")]
+[numthreads(4,1,1)]
+void computeMain(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform RWStructuredBuffer<float> buffer,
+ uniform ITransformer transformer)
+{
+ var input = buffer[sv_dispatchThreadID.x];
+ buffer[sv_dispatchThreadID.x] = transformer.transform(input);
+}
diff --git a/tools/gfx/command-writer.h b/tools/gfx/command-writer.h
index adbb53d7a..04be1be86 100644
--- a/tools/gfx/command-writer.h
+++ b/tools/gfx/command-writer.h
@@ -3,6 +3,7 @@
#include "slang-gfx.h"
#include "slang-com-ptr.h"
#include "core/slang-basic.h"
+#include "renderer-shared.h"
namespace gfx
{
@@ -81,7 +82,7 @@ class CommandWriter
{
public:
Slang::List<Command> m_commands;
- Slang::List<Slang::ComPtr<ISlangUnknown>> m_objects;
+ Slang::List<Slang::RefPtr<Slang::RefObject>> m_objects;
Slang::List<uint8_t> m_data;
bool m_hasWriteTimestamps = false;
@@ -105,18 +106,16 @@ public:
return offset;
}
- uint32_t encodeObject(ISlangUnknown* obj)
+ uint32_t encodeObject(Slang::RefObject* obj)
{
uint32_t offset = (uint32_t)m_objects.getCount();
- ComPtr<ISlangUnknown> ptr;
- ptr = obj;
- m_objects.add(ptr);
+ m_objects.add(obj);
return offset;
}
template <typename T> T* getObject(uint32_t offset)
{
- return static_cast<T*>(m_objects[offset].get());
+ return static_cast<T*>(m_objects[offset].Ptr());
}
template <typename T> T* getData(uint32_t offset)
@@ -126,19 +125,19 @@ public:
void setPipelineState(IPipelineState* state)
{
- auto offset = encodeObject(state);
+ auto offset = encodeObject(static_cast<PipelineStateBase*>(state));
m_commands.add(Command(CommandName::SetPipelineState, offset));
}
void bindRootShaderObject(IShaderObject* object)
{
- auto rootOffset = encodeObject(object);
+ auto rootOffset = encodeObject(static_cast<ShaderObjectBase*>(object));
m_commands.add(Command(CommandName::BindRootShaderObject, rootOffset));
}
void uploadBufferData(IBufferResource* buffer, size_t offset, size_t size, void* data)
{
- auto bufferOffset = encodeObject(buffer);
+ auto bufferOffset = encodeObject(static_cast<BufferResource*>(buffer));
auto dataOffset = encodeData(data, size);
m_commands.add(Command(
CommandName::UploadBufferData,
@@ -155,8 +154,8 @@ public:
size_t srcOffset,
size_t size)
{
- auto dstBuffer = encodeObject(dst);
- auto srcBuffer = encodeObject(src);
+ auto dstBuffer = encodeObject(static_cast<BufferResource*>(dst));
+ auto srcBuffer = encodeObject(static_cast<BufferResource*>(src));
m_commands.add(Command(
CommandName::CopyBuffer,
dstBuffer,
@@ -168,7 +167,7 @@ public:
void setFramebuffer(IFramebuffer* frameBuffer)
{
- uint32_t framebufferOffset = encodeObject(frameBuffer);
+ uint32_t framebufferOffset = encodeObject(static_cast<FramebufferBase*>(frameBuffer));
m_commands.add(Command(CommandName::SetFramebuffer, framebufferOffset));
}
@@ -205,7 +204,7 @@ public:
uint32_t bufferOffset = 0;
for (UInt i = 0; i < slotCount; i++)
{
- auto offset = encodeObject(buffers[i]);
+ auto offset = encodeObject(static_cast<BufferResource*>(buffers[i]));
if (i == 0)
bufferOffset = offset;
}
@@ -222,7 +221,7 @@ public:
void setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset)
{
- auto bufferOffset = encodeObject(buffer);
+ auto bufferOffset = encodeObject(static_cast<BufferResource*>(buffer));
m_commands.add(Command(
CommandName::SetIndexBuffer, bufferOffset, (uint32_t)indexFormat, (uint32_t)offset));
}
@@ -254,7 +253,7 @@ public:
void writeTimestamp(IQueryPool* pool, SlangInt index)
{
- auto poolOffset = encodeObject(pool);
+ auto poolOffset = encodeObject(static_cast<QueryPoolBase*>(pool));
m_commands.add(
Command(CommandName::WriteTimestamp, poolOffset, (uint32_t)index));
m_hasWriteTimestamps = true;
diff --git a/tools/gfx/cpu/render-cpu.cpp b/tools/gfx/cpu/render-cpu.cpp
index 56804f15e..c6662b851 100644
--- a/tools/gfx/cpu/render-cpu.cpp
+++ b/tools/gfx/cpu/render-cpu.cpp
@@ -11,7 +11,7 @@
#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"
@@ -942,6 +942,9 @@ public:
char* getDataBuffer() { return m_data.getBuffer(); }
};
+class CPUMutableShaderObject : public MutableShaderObject<CPUMutableShaderObject, CPUShaderObjectLayout>
+{};
+
class CPUEntryPointShaderObject : public CPUShaderObject
{
public:
@@ -951,12 +954,9 @@ public:
class CPURootShaderObject : public CPUShaderObject
{
public:
- // Override default reference counting behavior to disable lifetime management via ComPtr.
- // Root objects are managed by command buffer and does not need to be freed by the user.
- SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
- SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
-public:
SlangResult init(IDevice* device, CPUProgramLayout* programLayout);
CPUProgramLayout* getLayout() { return static_cast<CPUProgramLayout*>(m_layout.Ptr()); }
@@ -1007,17 +1007,9 @@ public:
}
};
-class CPUQueryPool : public IQueryPool, public ComObject
+class CPUQueryPool : public QueryPoolBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL;
- IQueryPool* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
- return static_cast<IQueryPool*>(this);
- return nullptr;
- }
-public:
List<uint64_t> m_queries;
Result init(const IQueryPool::Desc& desc)
{
@@ -1216,6 +1208,19 @@ public:
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);
diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp
index fccc1e3f0..ed22495cb 100644
--- a/tools/gfx/cuda/render-cuda.cpp
+++ b/tools/gfx/cuda/render-cuda.cpp
@@ -12,6 +12,7 @@
#include "slang-com-helper.h"
#include "../command-writer.h"
#include "../renderer-shared.h"
+#include "../mutable-shader-object.h"
#include "../simple-transient-resource-heap.h"
#include "../slang-context.h"
@@ -659,6 +660,9 @@ public:
}
};
+class CUDAMutableShaderObject : public MutableShaderObject< CUDAMutableShaderObject, CUDAShaderObjectLayout>
+{};
+
class CUDAEntryPointShaderObject : public CUDAShaderObject
{
public:
@@ -668,11 +672,8 @@ public:
class CUDARootShaderObject : public CUDAShaderObject
{
public:
- // Override default reference counting behavior to disable lifetime management.
- // Root objects are managed by command buffer and does not need to be freed by the user.
- SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
- SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
-
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
public:
List<RefPtr<CUDAEntryPointShaderObject>> entryPointObjects;
virtual SLANG_NO_THROW Result SLANG_MCALL
@@ -723,17 +724,9 @@ public:
}
};
-class CUDAQueryPool : public IQueryPool, public ComObject
+class CUDAQueryPool : public QueryPoolBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL;
- IQueryPool* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
- return static_cast<IQueryPool*>(this);
- return nullptr;
- }
-public:
// The event object for each query. Owned by the pool.
List<CUevent> m_events;
@@ -1001,7 +994,6 @@ public:
ResourceState src,
ResourceState dst) override
{
- assert(!"Unimplemented");
}
virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier(
@@ -1010,7 +1002,6 @@ public:
ResourceState src,
ResourceState dst) override
{
- assert(!"Unimplemented");
}
virtual SLANG_NO_THROW void SLANG_MCALL
@@ -1236,11 +1227,11 @@ public:
switch (cmd.name)
{
case CommandName::SetPipelineState:
- setPipelineState(commandBuffer->getObject<IPipelineState>(cmd.operands[0]));
+ setPipelineState(commandBuffer->getObject<PipelineStateBase>(cmd.operands[0]));
break;
case CommandName::BindRootShaderObject:
bindRootShaderObject(
- commandBuffer->getObject<IShaderObject>(cmd.operands[0]));
+ commandBuffer->getObject<ShaderObjectBase>(cmd.operands[0]));
break;
case CommandName::DispatchCompute:
dispatchCompute(
@@ -1248,22 +1239,22 @@ public:
break;
case CommandName::CopyBuffer:
copyBuffer(
- commandBuffer->getObject<IBufferResource>(cmd.operands[0]),
+ commandBuffer->getObject<BufferResource>(cmd.operands[0]),
cmd.operands[1],
- commandBuffer->getObject<IBufferResource>(cmd.operands[2]),
+ commandBuffer->getObject<BufferResource>(cmd.operands[2]),
cmd.operands[3],
cmd.operands[4]);
break;
case CommandName::UploadBufferData:
uploadBufferData(
- commandBuffer->getObject<IBufferResource>(cmd.operands[0]),
+ commandBuffer->getObject<BufferResource>(cmd.operands[0]),
cmd.operands[1],
cmd.operands[2],
commandBuffer->getData<uint8_t>(cmd.operands[3]));
break;
case CommandName::WriteTimestamp:
writeTimestamp(
- commandBuffer->getObject<IQueryPool>(cmd.operands[0]),
+ commandBuffer->getObject<QueryPoolBase>(cmd.operands[0]),
(SlangInt)cmd.operands[1]);
}
}
@@ -1816,6 +1807,16 @@ public:
return SLANG_OK;
}
+ virtual Result createMutableShaderObject(
+ ShaderObjectLayoutBase* layout,
+ IShaderObject** outObject) override
+ {
+ RefPtr<CUDAMutableShaderObject> result = new CUDAMutableShaderObject();
+ SLANG_RETURN_ON_FAIL(result->init(this, dynamic_cast<CUDAShaderObjectLayout*>(layout)));
+ returnComPtr(outObject, result);
+ return SLANG_OK;
+ }
+
Result createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
{
auto cudaProgram = dynamic_cast<CUDAShaderProgram*>(program);
diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp
index 8c1c6be1e..ec89c0879 100644
--- a/tools/gfx/d3d11/render-d3d11.cpp
+++ b/tools/gfx/d3d11/render-d3d11.cpp
@@ -10,6 +10,7 @@
#include "../d3d/d3d-util.h"
#include "../d3d/d3d-swapchain.h"
#include "../nvapi/nvapi-util.h"
+#include "../mutable-shader-object.h"
// In order to use the Slang API, we need to include its header
@@ -108,6 +109,7 @@ public:
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 void bindRootShaderObject(IShaderObject* shaderObject) override;
@@ -229,17 +231,9 @@ protected:
};
- class SamplerStateImpl : public ISamplerState, public ComObject
+ class SamplerStateImpl : public SamplerStateBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- ISamplerState* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISamplerState)
- return static_cast<ISamplerState*>(this);
- return nullptr;
- }
- public:
ComPtr<ID3D11SamplerState> m_sampler;
};
@@ -291,20 +285,9 @@ protected:
IFramebufferLayout::AttachmentLayout m_depthStencil;
};
- class FramebufferImpl
- : public IFramebuffer
- , public ComObject
+ class FramebufferImpl : public FramebufferBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IFramebuffer* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer)
- return static_cast<IFramebuffer*>(this);
- return nullptr;
- }
-
- public:
ShortList<RefPtr<RenderTargetViewImpl>, kMaxRTVs> renderTargetViews;
ShortList<ID3D11RenderTargetView*, kMaxRTVs> d3dRenderTargetViews;
RefPtr<DepthStencilViewImpl> depthStencilView;
@@ -367,17 +350,9 @@ protected:
ComPtr<ID3D11InputLayout> m_layout;
};
- class QueryPoolImpl : public IQueryPool, public ComObject
+ class QueryPoolImpl : public QueryPoolBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL;
- IQueryPool* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
- return static_cast<IQueryPool*>(this);
- return nullptr;
- }
- public:
List<ComPtr<ID3D11Query>> m_queries;
RefPtr<D3D11Device> m_device;
D3D11_QUERY_DESC m_queryDesc;
@@ -1290,6 +1265,8 @@ protected:
memcpy(dest + offset, data, size);
+ m_isConstantBufferDirty = true;
+
return SLANG_OK;
}
@@ -1510,49 +1487,43 @@ protected:
D3D11Device* device,
ShaderObjectLayoutImpl* specializedLayout)
{
- // If we have already created a buffer to hold ordinary data, then we should
- // simply re-use that buffer rather than re-create it.
- //
- // TODO: Simply re-using the buffer without any kind of validation checks
- // means that we are assuming that users cannot or will not perform any `set`
- // operations on a shader object once an operation has requested this buffer
- // be created. We need to enforce that rule if we want to rely on it.
- //
- if (m_ordinaryDataBuffer)
- return SLANG_OK;
-
auto specializedOrdinaryDataSize = specializedLayout->getTotalOrdinaryDataSize();
if (specializedOrdinaryDataSize == 0)
return SLANG_OK;
- // Once we have computed how large the buffer should be, we can allocate
- // it using the existing public `IDevice` API.
- //
+ // If we have already created a buffer to hold ordinary data, then we should
+ // simply re-use that buffer rather than re-create it.
+ if (!m_ordinaryDataBuffer)
+ {
+ ComPtr<IBufferResource> bufferResourcePtr;
+ IBufferResource::Desc bufferDesc = {};
+ bufferDesc.type = IResource::Type::Buffer;
+ bufferDesc.sizeInBytes = specializedOrdinaryDataSize;
+ bufferDesc.defaultState = ResourceState::ConstantBuffer;
+ bufferDesc.allowedStates =
+ ResourceStateSet(ResourceState::ConstantBuffer, ResourceState::CopyDestination);
+ bufferDesc.cpuAccessFlags |= AccessFlag::Write;
+ SLANG_RETURN_ON_FAIL(
+ device->createBufferResource(bufferDesc, nullptr, bufferResourcePtr.writeRef()));
+ m_ordinaryDataBuffer = static_cast<BufferResourceImpl*>(bufferResourcePtr.get());
+ }
- ComPtr<IBufferResource> bufferResourcePtr;
- IBufferResource::Desc bufferDesc = {};
- bufferDesc.type = IResource::Type::Buffer;
- bufferDesc.sizeInBytes = specializedOrdinaryDataSize;
- bufferDesc.defaultState = ResourceState::ConstantBuffer;
- bufferDesc.allowedStates =
- ResourceStateSet(ResourceState::ConstantBuffer, ResourceState::CopyDestination);
- bufferDesc.cpuAccessFlags |= AccessFlag::Write;
- SLANG_RETURN_ON_FAIL(
- device->createBufferResource(bufferDesc, nullptr, bufferResourcePtr.writeRef()));
- m_ordinaryDataBuffer = static_cast<BufferResourceImpl*>(bufferResourcePtr.get());
-
- // Once the buffer is allocated, we can use `_writeOrdinaryData` to fill it in.
- //
- // Note that `_writeOrdinaryData` is potentially recursive in the case
- // where this object contains interface/existential-type fields, so we
- // don't need or want to inline it into this call site.
- //
+ if (m_isConstantBufferDirty)
+ {
+ // Once the buffer is allocated, we can use `_writeOrdinaryData` to fill it in.
+ //
+ // Note that `_writeOrdinaryData` is potentially recursive in the case
+ // where this object contains interface/existential-type fields, so we
+ // don't need or want to inline it into this call site.
+ //
- auto ordinaryData = device->map(m_ordinaryDataBuffer, gfx::MapFlavor::WriteDiscard);
- auto result = _writeOrdinaryData(ordinaryData, specializedOrdinaryDataSize, specializedLayout);
- device->unmap(m_ordinaryDataBuffer, 0, specializedOrdinaryDataSize);
-
- return result;
+ auto ordinaryData = device->map(m_ordinaryDataBuffer, gfx::MapFlavor::WriteDiscard);
+ auto result = _writeOrdinaryData(ordinaryData, specializedOrdinaryDataSize, specializedLayout);
+ device->unmap(m_ordinaryDataBuffer, 0, specializedOrdinaryDataSize);
+ m_isConstantBufferDirty = false;
+ return result;
+ }
+ return SLANG_OK;
}
/// Bind the buffer for ordinary/uniform data, if needed
@@ -1776,6 +1747,8 @@ protected:
/// Created on demand with `_createOrdinaryDataBufferIfNeeded()`
RefPtr<BufferResourceImpl> m_ordinaryDataBuffer;
+ bool m_isConstantBufferDirty = true;
+
/// Get the layout of this shader object with specialization arguments considered
///
/// This operation should only be called after the shader object has been
@@ -1814,16 +1787,20 @@ protected:
RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
};
+ class MutableShaderObjectImpl
+ : public MutableShaderObject<
+ MutableShaderObjectImpl,
+ ShaderObjectLayoutImpl>
+ {};
+
class RootShaderObjectImpl : public ShaderObjectImpl
{
typedef ShaderObjectImpl Super;
public:
- // Override default reference counting behavior to disable lifetime management via ComPtr.
- // Root objects are managed by command buffer and does not need to be freed by the user.
- SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
- SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
- 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; }
+
static Result create(IDevice* device, RootShaderObjectLayoutImpl* layout, RootShaderObjectImpl** outShaderObject)
{
RefPtr<RootShaderObjectImpl> object = new RootShaderObjectImpl();
@@ -3567,6 +3544,19 @@ Result D3D11Device::createShaderObject(ShaderObjectLayoutBase* layout, IShaderOb
return SLANG_OK;
}
+Result D3D11Device::createMutableShaderObject(
+ ShaderObjectLayoutBase* layout,
+ IShaderObject** outObject)
+{
+ auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
+
+ RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
+ SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
+ returnComPtr(outObject, result);
+
+ return SLANG_OK;
+}
+
Result D3D11Device::createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
{
auto programImpl = static_cast<ShaderProgramImpl*>(program);
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 28c00d08e..4d5dfda80 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -8,6 +8,7 @@
#include "../transient-resource-heap-base.h"
#include "../simple-render-pass-layout.h"
#include "../d3d/d3d-swapchain.h"
+#include "../mutable-shader-object.h"
#include "core/slang-blob.h"
#include "core/slang-basic.h"
#include "core/slang-chunked-list.h"
@@ -117,6 +118,8 @@ public:
ShaderObjectLayoutBase** outLayout) override;
virtual Result createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
override;
+ virtual Result createMutableShaderObject(
+ ShaderObjectLayoutBase* layout, IShaderObject** outObject) override;
virtual SLANG_NO_THROW Result SLANG_MCALL
createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override;
@@ -248,18 +251,9 @@ public:
}
};
- class SamplerStateImpl : public ISamplerState, public ComObject
+ class SamplerStateImpl : public SamplerStateBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
-
- ISamplerState* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISamplerState)
- return static_cast<ISamplerState*>(this);
- return nullptr;
- }
- public:
D3D12Descriptor m_descriptor;
Slang::RefPtr<D3D12GeneralDescriptorHeap> m_allocator;
~SamplerStateImpl()
@@ -292,20 +286,9 @@ public:
IFramebufferLayout::AttachmentLayout m_depthStencil;
};
- class FramebufferImpl
- : public IFramebuffer
- , public ComObject
+ class FramebufferImpl : public FramebufferBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IFramebuffer* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer)
- return static_cast<IFramebuffer*>(this);
- return nullptr;
- }
-
- public:
ShortList<RefPtr<ResourceViewImpl>> renderTargetViews;
RefPtr<ResourceViewImpl> depthStencilView;
ShortList<D3D12_CPU_DESCRIPTOR_HANDLE> renderTargetDescriptors;
@@ -381,17 +364,9 @@ public:
};
#endif
- class QueryPoolImpl : public IQueryPool, public ComObject
+ class QueryPoolImpl : public QueryPoolBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IQueryPool* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
- return static_cast<IQueryPool*>(this);
- return nullptr;
- }
- public:
Result init(const IQueryPool::Desc& desc, D3D12Device* device);
virtual SLANG_NO_THROW Result SLANG_MCALL getResult(SlangInt queryIndex, SlangInt count, uint64_t* data) override
@@ -604,10 +579,10 @@ public:
}
class TransientResourceHeapImpl
- : public TransientResourceHeapBase<D3D12Device, BufferResourceImpl>
+ : public TransientResourceHeapBaseImpl<D3D12Device, BufferResourceImpl>
{
private:
- typedef TransientResourceHeapBase<D3D12Device, BufferResourceImpl> Super;
+ typedef TransientResourceHeapBaseImpl<D3D12Device, BufferResourceImpl> Super;
public:
ComPtr<ID3D12CommandAllocator> m_commandAllocator;
List<ComPtr<ID3D12GraphicsCommandList>> m_d3dCommandListPool;
@@ -1280,6 +1255,7 @@ public:
uint32_t getResourceSlotCount() { return m_ownCounts.resource; }
uint32_t getSamplerSlotCount() { return m_ownCounts.sampler; }
Index getSubObjectSlotCount() { return m_subObjectCount; }
+ Index getSubObjectCount() { return m_subObjectCount; }
uint32_t getTotalResourceDescriptorCount() { return m_totalCounts.resource; }
uint32_t getTotalSamplerDescriptorCount() { return m_totalCounts.sampler; }
@@ -2012,9 +1988,9 @@ public:
class ShaderObjectImpl
: public ShaderObjectBaseImpl<
- ShaderObjectImpl,
- ShaderObjectLayoutImpl,
- SimpleShaderObjectData>
+ ShaderObjectImpl,
+ ShaderObjectLayoutImpl,
+ SimpleShaderObjectData>
{
public:
static Result create(
@@ -2070,6 +2046,8 @@ public:
memcpy(dest + offset, data, size);
+ m_isConstantBufferDirty = true;
+
return SLANG_OK;
}
@@ -2145,7 +2123,9 @@ public:
m_layout = layout;
- m_upToDateConstantBufferHeapVersion = 0;
+ m_constantBufferTransientHeap = nullptr;
+ m_constantBufferTransientHeapVersion = 0;
+ m_isConstantBufferDirty = true;
// If the layout tells us that there is any uniform data,
// then we will allocate a CPU memory buffer to hold that data
@@ -2172,7 +2152,7 @@ public:
// but does *not* include any descriptors that are managed
// as part of sub-objects.
//
- if(auto resourceCount = layout->getResourceSlotCount())
+ if (auto resourceCount = layout->getResourceSlotCount())
{
m_descriptorSet.resourceTable.allocate(viewHeap, resourceCount);
@@ -2182,7 +2162,7 @@ public:
//
m_boundResources.setCount(resourceCount);
}
- if(auto samplerCount = layout->getSamplerSlotCount())
+ if (auto samplerCount = layout->getSamplerSlotCount())
{
m_descriptorSet.samplerTable.allocate(samplerHeap, samplerCount);
}
@@ -2331,24 +2311,27 @@ public:
return SLANG_OK;
}
+ bool shouldAllocateConstantBuffer(TransientResourceHeapImpl* transientHeap)
+ {
+ return m_isConstantBufferDirty || m_constantBufferTransientHeap != transientHeap ||
+ m_constantBufferTransientHeapVersion != transientHeap->getVersion();
+ }
+
/// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed
Result _ensureOrdinaryDataBufferCreatedIfNeeded(
PipelineCommandEncoder* encoder,
ShaderObjectLayoutImpl* specializedLayout)
{
- // If we have already created a buffer to hold ordinary data, then we should
- // simply re-use that buffer rather than re-create it.
- //
- // TODO: Simply re-using the buffer without any kind of validation checks
- // means that we are assuming that users cannot or will not perform any `set`
- // operations on a shader object once an operation has requested this buffer
- // be created. We need to enforce that rule if we want to rely on it.
+ // If data has been changed since last allocation/filling of constant buffer,
+ // we will need to allocate a new one.
//
- if (m_upToDateConstantBufferHeapVersion ==
- encoder->m_commandBuffer->m_transientHeap->getVersion())
+ if (!shouldAllocateConstantBuffer(encoder->m_transientHeap))
{
return SLANG_OK;
}
+ m_isConstantBufferDirty = false;
+ m_constantBufferTransientHeap = encoder->m_transientHeap;
+ m_constantBufferTransientHeapVersion = encoder->m_transientHeap->getVersion();
// Computing the size of the ordinary data buffer is *not* just as simple
// as using the size of the `m_ordinayData` array that we store. The reason
@@ -2360,8 +2343,6 @@ public:
m_constantBufferSize = specializedLayout->getTotalOrdinaryDataSize();
if (m_constantBufferSize == 0)
{
- m_upToDateConstantBufferHeapVersion =
- encoder->m_commandBuffer->m_transientHeap->getVersion();
return SLANG_OK;
}
@@ -2385,11 +2366,6 @@ public:
m_constantBufferSize,
specializedLayout));
- // Update version tracker so that we don't redundantly alloc and fill in
- // constant buffers for the same transient heap.
- m_upToDateConstantBufferHeapVersion =
- encoder->m_commandBuffer->m_transientHeap->getVersion();
-
{
// We also create and store a descriptor for our root constant buffer
// into the descriptor table allocation that was reserved for them.
@@ -2689,12 +2665,12 @@ public:
size_t m_constantBufferOffset = 0;
size_t m_constantBufferSize = 0;
- /// The version number of the transient resource heap that contains up-to-date
- /// constant buffer content for this shader object. If this is equal to the version number
- /// of currently active transient heap, then the current set-up of constant buffer contents
- /// as defined by the above `m_constantBuffer*` fields is valid and up-to-date so we can
- /// use them directly.
- uint64_t m_upToDateConstantBufferHeapVersion;
+ /// Dirty bit tracking whether the constant buffer needs to be updated.
+ bool m_isConstantBufferDirty = true;
+ /// The transient heap from which the constant buffer is allocated.
+ TransientResourceHeapImpl* m_constantBufferTransientHeap;
+ /// The version of the transient heap when the constant buffer is allocated.
+ uint64_t m_constantBufferTransientHeapVersion;
/// Get the layout of this shader object with specialization arguments considered
///
@@ -2734,6 +2710,9 @@ public:
RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
};
+ class MutableShaderObjectImpl : public MutableShaderObject<MutableShaderObjectImpl, ShaderObjectLayoutImpl>
+ {};
+
class RootShaderObjectImpl : public ShaderObjectImpl
{
typedef ShaderObjectImpl Super;
@@ -3455,7 +3434,6 @@ public:
ResourceState src,
ResourceState dst) override
{
- assert(!"Unimplemented");
}
virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() {}
virtual SLANG_NO_THROW void SLANG_MCALL writeTimestamp(IQueryPool* pool, SlangInt index) override
@@ -5380,6 +5358,19 @@ Result D3D12Device::createShaderObject(
return SLANG_OK;
}
+Result D3D12Device::createMutableShaderObject(
+ ShaderObjectLayoutBase* layout,
+ IShaderObject** outObject)
+{
+ auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
+
+ RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
+ SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
+ returnComPtr(outObject, result);
+
+ return SLANG_OK;
+}
+
Result D3D12Device::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, IPipelineState** outState)
{
GraphicsPipelineStateDesc desc = inDesc;
diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp
index bab564f14..5f5b0505e 100644
--- a/tools/gfx/debug-layer.cpp
+++ b/tools/gfx/debug-layer.cpp
@@ -563,6 +563,26 @@ Result DebugDevice::createShaderObject(
return result;
}
+Result DebugDevice::createMutableShaderObject(
+ slang::TypeReflection* type,
+ ShaderObjectContainerType containerType,
+ IShaderObject** outShaderObject)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugShaderObject> outObject = new DebugShaderObject();
+ auto typeName = type->getName();
+ auto result =
+ baseObject->createMutableShaderObject(type, containerType, outObject->baseObject.writeRef());
+ outObject->m_typeName = typeName;
+ outObject->m_device = this;
+ outObject->m_slangType = type;
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outShaderObject, outObject);
+ return result;
+}
+
Result DebugDevice::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
SLANG_GFX_API_FUNC;
@@ -863,8 +883,10 @@ Result DebugComputeCommandEncoder::bindPipeline(
SLANG_GFX_API_FUNC;
auto innerState = static_cast<DebugPipelineState*>(state)->baseObject;
- auto result =
- baseObject->bindPipeline(innerState, commandBuffer->rootObject.baseObject.writeRef());
+ IShaderObject* innerRootObject = nullptr;
+ commandBuffer->rootObject.reset();
+ auto result = baseObject->bindPipeline(innerState, &innerRootObject);
+ commandBuffer->rootObject.baseObject.attach(innerRootObject);
*outRootShaderObject = &commandBuffer->rootObject;
return result;
}
@@ -895,8 +917,10 @@ Result DebugRenderCommandEncoder::bindPipeline(
SLANG_GFX_API_FUNC;
auto innerState = static_cast<DebugPipelineState*>(state)->baseObject;
- auto result =
- baseObject->bindPipeline(innerState, commandBuffer->rootObject.baseObject.writeRef());
+ IShaderObject* innerRootObject = nullptr;
+ commandBuffer->rootObject.reset();
+ auto result = baseObject->bindPipeline(innerState, &innerRootObject);
+ commandBuffer->rootObject.baseObject.attach(innerRootObject);
*outRootShaderObject = &commandBuffer->rootObject;
return result;
}
@@ -1142,7 +1166,10 @@ void DebugRayTracingCommandEncoder::bindPipeline(
{
SLANG_GFX_API_FUNC;
auto innerPipeline = getInnerObj(state);
- baseObject->bindPipeline(innerPipeline, commandBuffer->rootObject.baseObject.writeRef());
+ IShaderObject* innerRootObject = nullptr;
+ commandBuffer->rootObject.reset();
+ baseObject->bindPipeline(innerPipeline, &innerRootObject);
+ commandBuffer->rootObject.baseObject.attach(innerRootObject);
*outRootObject = &commandBuffer->rootObject;
}
@@ -1393,10 +1420,21 @@ Result DebugShaderObject::setSpecializationArgs(
const slang::SpecializationArg* args,
uint32_t count)
{
-
return baseObject->setSpecializationArgs(offset, args, count);
}
+Result DebugShaderObject::getCurrentVersion(
+ ITransientResourceHeap* transientHeap, IShaderObject** outObject)
+{
+ ComPtr<IShaderObject> innerObject;
+ SLANG_RETURN_ON_FAIL(baseObject->getCurrentVersion(getInnerObj(transientHeap), innerObject.writeRef()));
+ RefPtr<DebugShaderObject> debugShaderObject = new DebugShaderObject();
+ debugShaderObject->baseObject = innerObject;
+ debugShaderObject->m_typeName = innerObject->getElementTypeLayout()->getName();
+ returnComPtr(outObject, debugShaderObject);
+ return SLANG_OK;
+}
+
DebugObjectBase::DebugObjectBase()
{
static uint64_t uidCounter = 0;
@@ -1413,6 +1451,15 @@ Result DebugRootShaderObject::setSpecializationArgs(
return baseObject->setSpecializationArgs(offset, args, count);
}
+void DebugRootShaderObject::reset()
+{
+ m_entryPoints.clear();
+ m_objects.Clear();
+ m_resources.Clear();
+ m_samplers.Clear();
+ baseObject.detach();
+}
+
Result DebugQueryPool::getResult(SlangInt index, SlangInt count, uint64_t* data)
{
SLANG_GFX_API_FUNC;
diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h
index d25fbd453..aa56e5530 100644
--- a/tools/gfx/debug-layer.h
+++ b/tools/gfx/debug-layer.h
@@ -95,6 +95,10 @@ public:
slang::TypeReflection* type,
ShaderObjectContainerType container,
IShaderObject** outObject) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObject(
+ slang::TypeReflection* type,
+ ShaderObjectContainerType container,
+ IShaderObject** outObject) override;
virtual SLANG_NO_THROW Result SLANG_MCALL
createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override;
virtual SLANG_NO_THROW Result SLANG_MCALL createGraphicsPipelineState(
@@ -189,6 +193,25 @@ public:
ISamplerState* getInterface(const Slang::Guid& guid);
};
+struct ShaderOffsetKey
+{
+ ShaderOffset offset;
+ bool operator==(ShaderOffsetKey other)
+ {
+ return offset.bindingArrayIndex == other.offset.bindingArrayIndex &&
+ offset.bindingRangeIndex == other.offset.bindingRangeIndex &&
+ offset.uniformOffset == other.offset.uniformOffset;
+ }
+ Slang::HashCode getHashCode()
+ {
+ return Slang::combineHash(
+ (Slang::HashCode)offset.uniformOffset,
+ Slang::combineHash(
+ (Slang::HashCode)offset.bindingArrayIndex,
+ (Slang::HashCode)offset.bindingRangeIndex));
+ }
+};
+
class DebugShaderObject : public DebugObject<IShaderObject>
{
public:
@@ -220,25 +243,10 @@ public:
const slang::SpecializationArg* args,
uint32_t count) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentVersion(
+ ITransientResourceHeap* transientHeap, IShaderObject** outObject) override;
+
public:
- struct ShaderOffsetKey
- {
- ShaderOffset offset;
- bool operator==(ShaderOffsetKey other)
- {
- return offset.bindingArrayIndex == other.offset.bindingArrayIndex &&
- offset.bindingRangeIndex == other.offset.bindingRangeIndex &&
- offset.uniformOffset == other.offset.uniformOffset;
- }
- Slang::HashCode getHashCode()
- {
- return Slang::combineHash(
- (Slang::HashCode)offset.uniformOffset,
- Slang::combineHash(
- (Slang::HashCode)offset.bindingArrayIndex,
- (Slang::HashCode)offset.bindingRangeIndex));
- }
- };
Slang::String m_typeName;
slang::TypeReflection* m_slangType = nullptr;
DebugDevice* m_device;
@@ -257,6 +265,7 @@ public:
ShaderOffset const& offset,
const slang::SpecializationArg* args,
uint32_t count) override;
+ void reset();
};
class DebugCommandBuffer;
diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp
index eb5450746..8e2e6be0c 100644
--- a/tools/gfx/immediate-renderer-base.cpp
+++ b/tools/gfx/immediate-renderer-base.cpp
@@ -255,7 +255,6 @@ public:
ResourceState src,
ResourceState dst) override
{
- assert(!"Unimplemented");
}
virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier(
@@ -264,7 +263,6 @@ public:
ResourceState src,
ResourceState dst) override
{
- assert(!"Unimplemented");
}
};
@@ -300,13 +298,13 @@ public:
switch (name)
{
case CommandName::SetPipelineState:
- m_renderer->setPipelineState(m_writer.getObject<IPipelineState>(cmd.operands[0]));
+ m_renderer->setPipelineState(m_writer.getObject<PipelineStateBase>(cmd.operands[0]));
break;
case CommandName::BindRootShaderObject:
- m_renderer->bindRootShaderObject(m_writer.getObject<IShaderObject>(cmd.operands[0]));
+ m_renderer->bindRootShaderObject(m_writer.getObject<ShaderObjectBase>(cmd.operands[0]));
break;
case CommandName::SetFramebuffer:
- m_renderer->setFramebuffer(m_writer.getObject<IFramebuffer>(cmd.operands[0]));
+ m_renderer->setFramebuffer(m_writer.getObject<FramebufferBase>(cmd.operands[0]));
break;
case CommandName::ClearFrame:
m_renderer->clearFrame(
@@ -329,7 +327,7 @@ public:
for (uint32_t i = 0; i < cmd.operands[1]; i++)
{
bufferResources.add(
- m_writer.getObject<IBufferResource>(cmd.operands[2] + i));
+ m_writer.getObject<BufferResource>(cmd.operands[2] + i));
}
m_renderer->setVertexBuffers(
(UInt)cmd.operands[0],
@@ -341,7 +339,7 @@ public:
break;
case CommandName::SetIndexBuffer:
m_renderer->setIndexBuffer(
- m_writer.getObject<IBufferResource>(cmd.operands[0]),
+ m_writer.getObject<BufferResource>(cmd.operands[0]),
(Format)cmd.operands[1],
(UInt)cmd.operands[2]);
break;
@@ -361,21 +359,21 @@ public:
break;
case CommandName::UploadBufferData:
m_renderer->uploadBufferData(
- m_writer.getObject<IBufferResource>(cmd.operands[0]),
+ m_writer.getObject<BufferResource>(cmd.operands[0]),
cmd.operands[1],
cmd.operands[2],
m_writer.getData<uint8_t>(cmd.operands[3]));
break;
case CommandName::CopyBuffer:
m_renderer->copyBuffer(
- m_writer.getObject<IBufferResource>(cmd.operands[0]),
+ m_writer.getObject<BufferResource>(cmd.operands[0]),
cmd.operands[1],
- m_writer.getObject<IBufferResource>(cmd.operands[2]),
+ m_writer.getObject<BufferResource>(cmd.operands[2]),
cmd.operands[3],
cmd.operands[4]);
break;
case CommandName::WriteTimestamp:
- m_renderer->writeTimestamp(m_writer.getObject<IQueryPool>(cmd.operands[0]), (SlangInt)cmd.operands[1]);
+ m_renderer->writeTimestamp(m_writer.getObject<QueryPoolBase>(cmd.operands[0]), (SlangInt)cmd.operands[1]);
break;
default:
assert(!"unknown command");
diff --git a/tools/gfx/mutable-shader-object.h b/tools/gfx/mutable-shader-object.h
new file mode 100644
index 000000000..17c025580
--- /dev/null
+++ b/tools/gfx/mutable-shader-object.h
@@ -0,0 +1,215 @@
+#pragma once
+
+#include "slang-gfx.h"
+#include "core/slang-basic.h"
+#include "core/slang-com-object.h"
+#include "renderer-shared.h"
+
+namespace gfx
+{
+ class ShaderObjectLayoutBase;
+
+ template<typename T>
+ class VersionedObjectPool
+ {
+ public:
+ struct ObjectVersion
+ {
+ Slang::RefPtr<T> object;
+ Slang::RefPtr<TransientResourceHeapBase> transientHeap;
+ uint64_t transientHeapVersion;
+ bool canRecycle()
+ {
+ return (transientHeap->getVersion() != transientHeapVersion);
+ }
+ };
+ Slang::List<ObjectVersion> objects;
+ SlangInt lastAllocationIndex = -1;
+ ObjectVersion& allocate(TransientResourceHeapBase* currentTransientHeap)
+ {
+ for (SlangInt i = 0; i < objects.getCount(); i++)
+ {
+ auto& object = objects[i];
+ if (object.canRecycle())
+ {
+ object.transientHeap = currentTransientHeap;
+ object.transientHeapVersion = currentTransientHeap->getVersion();
+ lastAllocationIndex = i;
+ return object;
+ }
+ }
+ ObjectVersion v;
+ v.transientHeap = currentTransientHeap;
+ v.transientHeapVersion = currentTransientHeap->getVersion();
+ objects.add(v);
+ lastAllocationIndex = objects.getCount() - 1;
+ return objects.getLast();
+ }
+ ObjectVersion& getLastAllocation() { return objects[lastAllocationIndex]; }
+ };
+
+ class MutableShaderObjectData
+ {
+ public:
+ // Any "ordinary" / uniform data for this object
+ Slang::List<char> m_ordinaryData;
+
+ bool m_dirty = true;
+
+ Slang::Index getCount() { return m_ordinaryData.getCount(); }
+ void setCount(Slang::Index count) { m_ordinaryData.setCount(count); }
+ char* getBuffer() { return m_ordinaryData.getBuffer(); }
+ void markDirty() { m_dirty = true; }
+
+ // We don't actually create any GPU buffers here, since they will be handled
+ // by the immutable shader objects once the user calls `getCurrentVersion`.
+ ResourceViewBase* getResourceView(
+ RendererBase* device,
+ slang::TypeLayoutReflection* elementLayout,
+ slang::BindingType bindingType)
+ {
+ return nullptr;
+ }
+ };
+
+ template<typename TShaderObject, typename TShaderObjectLayoutImpl>
+ class MutableShaderObject : public ShaderObjectBaseImpl<
+ TShaderObject,
+ TShaderObjectLayoutImpl,
+ MutableShaderObjectData>
+ {
+ typedef ShaderObjectBaseImpl<
+ TShaderObject,
+ TShaderObjectLayoutImpl,
+ MutableShaderObjectData> Super;
+ protected:
+ Slang::OrderedDictionary<ShaderOffset, Slang::RefPtr<ResourceViewBase>> m_resources;
+ Slang::OrderedDictionary<ShaderOffset, Slang::RefPtr<SamplerStateBase>> m_samplers;
+ Slang::OrderedHashSet<ShaderOffset> m_objectOffsets;
+ VersionedObjectPool<ShaderObjectBase> m_shaderObjectVersions;
+ bool m_dirty = true;
+ bool isDirty()
+ {
+ if (m_dirty) return true;
+ if (this->m_data.m_dirty) return true;
+ for (auto& object : this->m_objects)
+ {
+ if (object && object->isDirty())
+ return true;
+ }
+ return false;
+ }
+
+ void markDirty()
+ {
+ m_dirty = true;
+ }
+ public:
+ Result init(RendererBase* device, ShaderObjectLayoutBase* layout)
+ {
+ this->m_device = device;
+ auto layoutImpl = static_cast<TShaderObjectLayoutImpl*>(layout);
+ this->m_layout = layoutImpl;
+ Slang::Index subObjectCount = layoutImpl->getSubObjectCount();
+ this->m_objects.setCount(subObjectCount);
+ return SLANG_OK;
+ }
+ public:
+ virtual SLANG_NO_THROW Result SLANG_MCALL setData(ShaderOffset const& offset, void const* data, size_t size) override
+ {
+ if (!size) return SLANG_OK;
+ if (SlangInt(offset.uniformOffset + size) > this->m_data.getCount())
+ this->m_data.setCount(offset.uniformOffset + size);
+ memcpy(this->m_data.getBuffer() + offset.uniformOffset, data, size);
+ this->m_data.markDirty();
+ markDirty();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ setObject(ShaderOffset const& offset, IShaderObject* object) override
+ {
+ Super::setObject(offset, object);
+ m_objectOffsets.Add(offset);
+ markDirty();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL setResource(ShaderOffset const& offset, IResourceView* resourceView) override
+ {
+ m_resources[offset] = static_cast<ResourceViewBase*>(resourceView);
+ markDirty();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL setSampler(ShaderOffset const& offset, ISamplerState* sampler) override
+ {
+ m_samplers[offset] = static_cast<SamplerStateBase*>(sampler);
+ markDirty();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler(ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) override
+ {
+ m_samplers[offset] = static_cast<SamplerStateBase*>(sampler);
+ m_resources[offset] = static_cast<ResourceViewBase*>(textureView);
+ markDirty();
+ return SLANG_OK;
+ }
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentVersion(
+ ITransientResourceHeap* transientHeap, IShaderObject** outObject) override
+ {
+ if (!isDirty())
+ {
+ returnComPtr(outObject, getLastAllocatedShaderObject());
+ return SLANG_OK;
+ }
+
+ Slang::RefPtr<ShaderObjectBase> object =
+ allocateShaderObject(static_cast<TransientResourceHeapBase*>(transientHeap));
+ SLANG_RETURN_ON_FAIL(object->setData(ShaderOffset(), this->m_data.getBuffer(), this->m_data.getCount()));
+ for (auto res : m_resources)
+ SLANG_RETURN_ON_FAIL(object->setResource(res.Key, res.Value));
+ for (auto sampler : m_samplers)
+ SLANG_RETURN_ON_FAIL(object->setSampler(sampler.Key, sampler.Value));
+ for (auto offset : m_objectOffsets)
+ {
+ if (offset.bindingRangeIndex < 0)
+ return SLANG_E_INVALID_ARG;
+ auto layout = this->getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
+ return SLANG_E_INVALID_ARG;
+ auto bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
+
+ auto subObject = this->m_objects[bindingRange.subObjectIndex + offset.bindingArrayIndex];
+ if (subObject)
+ {
+ ComPtr<IShaderObject> subObjectVersion;
+ SLANG_RETURN_ON_FAIL(subObject->getCurrentVersion(transientHeap, subObjectVersion.writeRef()));
+ SLANG_RETURN_ON_FAIL(object->setObject(offset, subObjectVersion));
+ }
+ }
+ m_dirty = false;
+ this->m_data.m_dirty = false;
+ returnComPtr(outObject, object);
+ return SLANG_OK;
+ }
+ public:
+ Slang::RefPtr<ShaderObjectBase> allocateShaderObject(TransientResourceHeapBase* transientHeap)
+ {
+ auto& version = m_shaderObjectVersions.allocate(transientHeap);
+ if (!version.object)
+ {
+ ComPtr<IShaderObject> shaderObject;
+ SLANG_RETURN_NULL_ON_FAIL(this->m_device->createShaderObject(this->m_layout, shaderObject.writeRef()));
+ version.object = static_cast<ShaderObjectBase*>(shaderObject.get());
+ }
+ return version.object;
+ }
+ Slang::RefPtr<ShaderObjectBase> getLastAllocatedShaderObject()
+ {
+ return m_shaderObjectVersions.getLastAllocation().object;
+ }
+ };
+}
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp
index 9ad24146d..a5d5ae368 100644
--- a/tools/gfx/open-gl/render-gl.cpp
+++ b/tools/gfx/open-gl/render-gl.cpp
@@ -4,6 +4,7 @@
#include "../nvapi/nvapi-util.h"
#include "../immediate-renderer-base.h"
+#include "../mutable-shader-object.h"
#include "core/slang-basic.h"
#include "core/slang-blob.h"
@@ -140,6 +141,7 @@ public:
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 void bindRootShaderObject(IShaderObject* shaderObject) override;
@@ -283,17 +285,9 @@ public:
GLuint m_handle;
};
- class SamplerStateImpl : public ISamplerState, public ComObject
+ class SamplerStateImpl : public SamplerStateBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- ISamplerState* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISamplerState)
- return static_cast<ISamplerState*>(this);
- return nullptr;
- }
- public:
GLuint m_samplerID;
};
@@ -340,20 +334,9 @@ public:
IFramebufferLayout::AttachmentLayout m_depthStencil;
};
- class FramebufferImpl
- : public IFramebuffer
- , public ComObject
+ class FramebufferImpl : public FramebufferBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IFramebuffer* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer)
- return static_cast<IFramebuffer*>(this);
- return nullptr;
- }
-
- public:
GLuint m_framebuffer;
ShortList<GLenum> m_drawBuffers;
RefPtr<WeakSink<GLDevice>> m_renderer;
@@ -1394,16 +1377,15 @@ public:
RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
};
+ class MutableShaderObjectImpl : public MutableShaderObject<MutableShaderObjectImpl, ShaderObjectLayoutImpl>
+ {};
+
class RootShaderObjectImpl : public ShaderObjectImpl
{
typedef ShaderObjectImpl Super;
-
public:
- // Override default reference counting behavior to disable lifetime management via ComPtr.
- // Root objects are managed by command buffer and does not need to be freed by the user.
- SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
- SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
-
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
public:
static Result create(IDevice* device, RootShaderObjectLayoutImpl* layout, RootShaderObjectImpl** outShaderObject)
{
@@ -2845,6 +2827,17 @@ Result GLDevice::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObjec
return SLANG_OK;
}
+Result GLDevice::createMutableShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
+{
+ auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
+
+ RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
+ SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
+ returnComPtr(outObject, result);
+
+ return SLANG_OK;
+}
+
Result GLDevice::createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
{
auto programImpl = static_cast<ShaderProgramImpl*>(program);
diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp
index c5a0c826d..791cb1859 100644
--- a/tools/gfx/renderer-shared.cpp
+++ b/tools/gfx/renderer-shared.cpp
@@ -1,4 +1,5 @@
#include "renderer-shared.h"
+#include "mutable-shader-object.h"
#include "core/slang-io.h"
#include "core/slang-token-reader.h"
@@ -128,22 +129,22 @@ IResourceView* ResourceViewBase::getInterface(const Guid& guid)
return nullptr;
}
-IAccelerationStructure* AccelerationStructureBase::getInterface(const Slang::Guid& guid)
+ISamplerState* SamplerStateBase::getInterface(const Slang::Guid& guid)
{
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IResourceView ||
- guid == GfxGUID::IID_IAccelerationStructure)
- return static_cast<IAccelerationStructure*>(this);
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISamplerState)
+ return static_cast<ISamplerState*>(this);
return nullptr;
}
-IShaderObject* ShaderObjectBase::getInterface(const Guid& guid)
+IAccelerationStructure* AccelerationStructureBase::getInterface(const Slang::Guid& guid)
{
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderObject)
- return static_cast<IShaderObject*>(this);
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IResourceView ||
+ guid == GfxGUID::IID_IAccelerationStructure)
+ return static_cast<IAccelerationStructure*>(this);
return nullptr;
}
-bool ShaderObjectBase::_doesValueFitInExistentialPayload(
+bool _doesValueFitInExistentialPayload(
slang::TypeLayoutReflection* concreteTypeLayout,
slang::TypeLayoutReflection* existentialTypeLayout)
{
@@ -223,6 +224,20 @@ IFramebufferLayout* FramebufferLayoutBase::getInterface(const Guid& guid)
return nullptr;
}
+IFramebuffer* FramebufferBase::getInterface(const Guid& guid)
+{
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer)
+ return static_cast<IFramebuffer*>(this);
+ return nullptr;
+}
+
+IQueryPool* QueryPoolBase::getInterface(const Guid& guid)
+{
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
+ return static_cast<IQueryPool*>(this);
+ return nullptr;
+}
+
IPipelineState* gfx::PipelineStateBase::getInterface(const Guid& guid)
{
if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IPipelineState)
@@ -298,10 +313,20 @@ SLANG_NO_THROW Result SLANG_MCALL RendererBase::createShaderObject(
IShaderObject** outObject)
{
RefPtr<ShaderObjectLayoutBase> shaderObjectLayout;
- SLANG_RETURN_FALSE_ON_FAIL(getShaderObjectLayout(type, container, shaderObjectLayout.writeRef()));
+ SLANG_RETURN_ON_FAIL(getShaderObjectLayout(type, container, shaderObjectLayout.writeRef()));
return createShaderObject(shaderObjectLayout, outObject);
}
+SLANG_NO_THROW Result SLANG_MCALL RendererBase::createMutableShaderObject(
+ slang::TypeReflection* type,
+ ShaderObjectContainerType containerType,
+ IShaderObject** outObject)
+{
+ RefPtr<ShaderObjectLayoutBase> shaderObjectLayout;
+ SLANG_RETURN_ON_FAIL(getShaderObjectLayout(type, containerType, shaderObjectLayout.writeRef()));
+ return createMutableShaderObject(shaderObjectLayout, outObject);
+}
+
Result RendererBase::getAccelerationStructurePrebuildInfo(
const IAccelerationStructure::BuildInputs& buildInputs,
IAccelerationStructure::PrebuildInfo* outPrebuildInfo)
@@ -452,7 +477,7 @@ Result ShaderObjectBase::_getSpecializedShaderObjectType(ExtendedShaderObjectTyp
else
{
shaderObjectType.slangType = getRenderer()->slangContext.session->specializeType(
- getElementTypeLayout()->getType(),
+ _getElementTypeLayout()->getType(),
specializationArgs.components.getArrayView().getBuffer(), specializationArgs.getCount());
shaderObjectType.componentID = getRenderer()->shaderCache.getComponentId(shaderObjectType.slangType);
}
diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h
index 5df3ee92b..51db601c9 100644
--- a/tools/gfx/renderer-shared.h
+++ b/tools/gfx/renderer-shared.h
@@ -261,6 +261,13 @@ public:
virtual SLANG_NO_THROW Desc* SLANG_MCALL getViewDesc() override { return &m_desc; }
};
+class SamplerStateBase : public ISamplerState, public Slang::ComObject
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL
+ ISamplerState* getInterface(const Slang::Guid& guid);
+};
+
class AccelerationStructureBase
: public IAccelerationStructure
, public ResourceViewInternalBase
@@ -423,8 +430,20 @@ public:
slang::BindingType bindingType);
};
+bool _doesValueFitInExistentialPayload(
+ slang::TypeLayoutReflection* concreteTypeLayout,
+ slang::TypeLayoutReflection* existentialFieldLayout);
+
class ShaderObjectBase : public IShaderObject, public Slang::ComObject
{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL
+ IShaderObject* getInterface(const Slang::Guid& guid)
+ {
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderObject)
+ return static_cast<IShaderObject *>(this);
+ return nullptr;
+ }
protected:
// A strong reference to `IDevice` to make sure the weak device reference in
// `ShaderObjectLayout`s are valid whenever they might be used.
@@ -436,17 +455,14 @@ protected:
// The specialized shader object type.
ExtendedShaderObjectType shaderObjectType = { nullptr, kInvalidComponentID };
- static bool _doesValueFitInExistentialPayload(
- slang::TypeLayoutReflection* concreteTypeLayout,
- slang::TypeLayoutReflection* existentialFieldLayout);
Result _getSpecializedShaderObjectType(ExtendedShaderObjectType* outType);
-
+ slang::TypeLayoutReflection* _getElementTypeLayout()
+ {
+ return m_layout->getElementTypeLayout();
+ }
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IShaderObject* getInterface(const Slang::Guid& guid);
void breakStrongReferenceToDevice() { m_device.breakStrongReference(); }
-
public:
ShaderComponentID getComponentID()
{
@@ -461,6 +477,15 @@ public:
RendererBase* getRenderer() { return m_layout->getDevice(); }
+ ShaderObjectLayoutBase* getLayoutBase() { return m_layout; }
+
+ /// Sets the RTTI ID and RTTI witness table fields of an existential value.
+ Result setExistentialHeader(
+ slang::TypeReflection* existentialType,
+ slang::TypeReflection* concreteType,
+ ShaderOffset offset);
+
+public:
SLANG_NO_THROW UInt SLANG_MCALL getEntryPointCount() SLANG_OVERRIDE { return 0; }
SLANG_NO_THROW Result SLANG_MCALL getEntryPoint(UInt index, IShaderObject** outEntryPoint)
@@ -470,8 +495,6 @@ public:
return SLANG_OK;
}
- ShaderObjectLayoutBase* getLayoutBase() { return m_layout; }
-
SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getElementTypeLayout() SLANG_OVERRIDE
{
return m_layout->getElementTypeLayout();
@@ -482,11 +505,12 @@ public:
return m_layout->getContainerType();
}
- /// Sets the RTTI ID and RTTI witness table fields of an existential value.
- Result setExistentialHeader(
- slang::TypeReflection* existentialType,
- slang::TypeReflection* concreteType,
- ShaderOffset offset);
+ virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentVersion(
+ ITransientResourceHeap* transientHeap, IShaderObject** outObject) override
+ {
+ SLANG_UNUSED(outObject);
+ return SLANG_E_NOT_AVAILABLE;
+ }
};
template<typename TShaderObjectImpl, typename TShaderObjectLayoutImpl, typename TShaderObjectData>
@@ -707,12 +731,12 @@ public:
{
// If we are setting into a `StructuredBuffer` field, make sure we create and set
// the StructuredBuffer resource as well.
- setResource(
- offset,
- subObject->m_data.getResourceView(
- getRenderer(),
- subObject->getElementTypeLayout(),
- bindingRange.bindingType));
+ auto resourceView = subObject->m_data.getResourceView(
+ getRenderer(),
+ subObject->getElementTypeLayout(),
+ bindingRange.bindingType);
+ if (resourceView)
+ setResource(offset, resourceView);
}
break;
}
@@ -921,6 +945,24 @@ public:
IFramebufferLayout* getInterface(const Slang::Guid& guid);
};
+class FramebufferBase
+ : public IFramebuffer
+ , public Slang::ComObject
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL
+ IFramebuffer* getInterface(const Slang::Guid& guid);
+};
+
+class QueryPoolBase
+ : public IQueryPool
+ , public Slang::ComObject
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL
+ IQueryPool* getInterface(const Slang::Guid& guid);
+};
+
class PipelineStateBase
: public IPipelineState
, public Slang::ComObject
@@ -1073,6 +1115,30 @@ protected:
Slang::OrderedDictionary<PipelineKey, Slang::RefPtr<PipelineStateBase>> specializedPipelines;
};
+class TransientResourceHeapBase : public ITransientResourceHeap, public Slang::ComObject
+{
+public:
+ uint64_t m_version = 0;
+ uint64_t getVersion() { return m_version; }
+ uint64_t& getVersionCounter()
+ {
+ static uint64_t version = 1;
+ return version;
+ }
+ TransientResourceHeapBase()
+ {
+ m_version = getVersionCounter()++;
+ }
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL
+ ITransientResourceHeap* getInterface(const Slang::Guid& guid)
+ {
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ITransientResourceHeap)
+ return static_cast<ITransientResourceHeap*>(this);
+ return nullptr;
+ }
+};
+
// Renderer implementation shared by all platforms.
// Responsible for shader compilation, specialization and caching.
class RendererBase : public IDevice, public Slang::ComObject
@@ -1093,6 +1159,11 @@ public:
ShaderObjectContainerType containerType,
IShaderObject** outObject) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObject(
+ slang::TypeReflection* type,
+ ShaderObjectContainerType containerType,
+ IShaderObject** outObject) SLANG_OVERRIDE;
+
// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE for platforms
// without ray tracing support.
virtual SLANG_NO_THROW Result SLANG_MCALL getAccelerationStructurePrebuildInfo(
@@ -1134,6 +1205,9 @@ public:
ShaderObjectLayoutBase* layout,
IShaderObject** outObject) = 0;
+ virtual Result createMutableShaderObject(
+ ShaderObjectLayoutBase* layout,
+ IShaderObject** outObject) = 0;
protected:
virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc);
diff --git a/tools/gfx/simple-transient-resource-heap.h b/tools/gfx/simple-transient-resource-heap.h
index 4340d49df..c6980f94c 100644
--- a/tools/gfx/simple-transient-resource-heap.h
+++ b/tools/gfx/simple-transient-resource-heap.h
@@ -9,20 +9,9 @@
namespace gfx
{
template<typename TDevice, typename TCommandBuffer>
-class SimpleTransientResourceHeap
- : public ITransientResourceHeap
- , public Slang::ComObject
+class SimpleTransientResourceHeap : public TransientResourceHeapBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- ITransientResourceHeap* getInterface(const Slang::Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ITransientResourceHeap)
- return static_cast<ITransientResourceHeap*>(this);
- return nullptr;
- }
-
-public:
Slang::RefPtr<TDevice> m_device;
Slang::ComPtr<IBufferResource> m_constantBuffer;
@@ -49,6 +38,10 @@ public:
return SLANG_OK;
}
- virtual SLANG_NO_THROW Result SLANG_MCALL synchronizeAndReset() override { return SLANG_OK; }
+ virtual SLANG_NO_THROW Result SLANG_MCALL synchronizeAndReset() override
+ {
+ ++getVersionCounter();
+ return SLANG_OK;
+ }
};
}
diff --git a/tools/gfx/transient-resource-heap-base.h b/tools/gfx/transient-resource-heap-base.h
index f11a91c14..27f5e1bb9 100644
--- a/tools/gfx/transient-resource-heap-base.h
+++ b/tools/gfx/transient-resource-heap-base.h
@@ -4,18 +4,9 @@
namespace gfx
{
template <typename TDevice, typename TBufferResource>
-class TransientResourceHeapBase
- : public ITransientResourceHeap
- , public Slang::ComObject
+class TransientResourceHeapBaseImpl : public TransientResourceHeapBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- ITransientResourceHeap* getInterface(const Slang::Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ITransientResourceHeap)
- return static_cast<ITransientResourceHeap*>(this);
- return nullptr;
- }
void breakStrongReferenceToDevice() { m_device.breakStrongReference(); }
public:
@@ -24,13 +15,6 @@ public:
Slang::Index m_constantBufferAllocCounter = 0;
size_t m_constantBufferOffsetAllocCounter = 0;
uint32_t m_alignment = 256;
- uint64_t m_version;
- uint64_t getVersion() { return m_version; }
- uint64_t& getVersionCounter()
- {
- static uint64_t version = 1;
- return version;
- }
Result init(const ITransientResourceHeap::Desc& desc, uint32_t alignment, TDevice* device)
{
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 2dd5d4041..e7ebf8040 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -4,6 +4,7 @@
//WORKING:#include "options.h"
#include "../renderer-shared.h"
#include "../transient-resource-heap-base.h"
+#include "../mutable-shader-object.h"
#include "core/slang-basic.h"
#include "core/slang-blob.h"
@@ -95,6 +96,8 @@ public:
ShaderObjectLayoutBase** outLayout) override;
virtual Result createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
override;
+ virtual Result createMutableShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
+ override;
virtual SLANG_NO_THROW Result SLANG_MCALL
createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override;
@@ -140,6 +143,7 @@ public:
~VKDevice();
public:
+ class TransientResourceHeapImpl;
class Buffer
{
@@ -243,17 +247,9 @@ public:
}
};
- class SamplerStateImpl : public ISamplerState, public ComObject
+ class SamplerStateImpl : public SamplerStateBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- ISamplerState* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISamplerState)
- return static_cast<ISamplerState*>(this);
- return nullptr;
- }
- public:
VkSampler m_sampler;
RefPtr<VKDevice> m_device;
SamplerStateImpl(VKDevice* device)
@@ -562,20 +558,9 @@ public:
}
};
- class FramebufferImpl
- : public IFramebuffer
- , public ComObject
+ class FramebufferImpl : public FramebufferBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IFramebuffer* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer)
- return static_cast<IFramebuffer*>(this);
- return nullptr;
- }
-
- public:
VkFramebuffer m_handle;
ShortList<ComPtr<IResourceView>> renderTargetViews;
ComPtr<IResourceView> depthStencilView;
@@ -2322,6 +2307,8 @@ public:
memcpy(dest + offset, data, size);
+ m_isConstantBufferDirty = true;
+
return SLANG_OK;
}
@@ -2388,7 +2375,9 @@ public:
{
m_layout = layout;
- m_upToDateConstantBufferHeapVersion = 0;
+ m_constantBufferTransientHeap = nullptr;
+ m_constantBufferTransientHeapVersion = 0;
+ m_isConstantBufferDirty = true;
// If the layout tells us that there is any uniform data,
// then we will allocate a CPU memory buffer to hold that data
@@ -2812,30 +2801,31 @@ public:
}
}
+ bool shouldAllocateConstantBuffer(TransientResourceHeapImpl* transientHeap)
+ {
+ return m_isConstantBufferDirty || m_constantBufferTransientHeap != transientHeap ||
+ m_constantBufferTransientHeapVersion != transientHeap->getVersion();
+ }
+
/// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed
Result _ensureOrdinaryDataBufferCreatedIfNeeded(
PipelineCommandEncoder* encoder,
ShaderObjectLayoutImpl* specializedLayout)
{
- // If we have already created a buffer to hold ordinary data, then we should
- // simply re-use that buffer rather than re-create it.
- //
- // TODO: Simply re-using the buffer without any kind of validation checks
- // means that we are assuming that users cannot or will not perform any `set`
- // operations on a shader object once an operation has requested this buffer
- // be created. We need to enforce that rule if we want to rely on it.
+ // If data has been changed since last allocation/filling of constant buffer,
+ // we will need to allocate a new one.
//
- if (m_upToDateConstantBufferHeapVersion ==
- encoder->m_commandBuffer->m_transientHeap->getVersion())
+ if (!shouldAllocateConstantBuffer(encoder->m_commandBuffer->m_transientHeap))
{
return SLANG_OK;
}
+ m_isConstantBufferDirty = false;
+ m_constantBufferTransientHeap = encoder->m_commandBuffer->m_transientHeap;
+ m_constantBufferTransientHeapVersion = encoder->m_commandBuffer->m_transientHeap->getVersion();
m_constantBufferSize = specializedLayout->getTotalOrdinaryDataSize();
if (m_constantBufferSize == 0)
{
- m_upToDateConstantBufferHeapVersion =
- encoder->m_commandBuffer->m_transientHeap->getVersion();
return SLANG_OK;
}
@@ -2858,10 +2848,6 @@ public:
m_constantBufferSize,
specializedLayout));
- // Update version tracker so that we don't redundantly alloc and fill in
- // constant buffers for the same transient heap.
- m_upToDateConstantBufferHeapVersion =
- encoder->m_commandBuffer->m_transientHeap->getVersion();
return SLANG_OK;
}
@@ -3213,9 +3199,6 @@ public:
List<CombinedTextureSamplerSlot> m_combinedTextureSamplers;
- // The version number of the transient resource heap that contains up-to-date
- // constant buffer content for this shader object.
- uint64_t m_upToDateConstantBufferHeapVersion;
// The transient constant buffer that holds the GPU copy of the constant data,
// weak referenced.
IBufferResource* m_constantBuffer = nullptr;
@@ -3223,6 +3206,13 @@ public:
size_t m_constantBufferOffset = 0;
size_t m_constantBufferSize = 0;
+ /// Dirty bit tracking whether the constant buffer needs to be updated.
+ bool m_isConstantBufferDirty = true;
+ /// The transient heap from which the constant buffer is allocated.
+ VKDevice::TransientResourceHeapImpl* m_constantBufferTransientHeap;
+ /// The version of the transient heap when the constant buffer is allocated.
+ uint64_t m_constantBufferTransientHeapVersion;
+
/// Get the layout of this shader object with specialization arguments considered
///
/// This operation should only be called after the shader object has been
@@ -3261,6 +3251,9 @@ public:
RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
};
+ class MutableShaderObjectImpl : public MutableShaderObject<MutableShaderObjectImpl, ShaderObjectLayoutImpl>
+ {};
+
class EntryPointShaderObject : public ShaderObjectImpl
{
typedef ShaderObjectImpl Super;
@@ -3541,8 +3534,6 @@ public:
List<RefPtr<EntryPointShaderObject>> m_entryPoints;
};
- class TransientResourceHeapImpl;
-
class CommandBufferImpl
: public ICommandBuffer
, public ComObject
@@ -4141,7 +4132,7 @@ public:
VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false);
auto& vkApi = m_commandBuffer->m_renderer->m_api;
- vkApi.vkCmdPipelineBarrier(m_commandBuffer->m_commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, count, barriers.getBuffer());
+ vkApi.vkCmdPipelineBarrier(m_commandBuffer->m_commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, (uint32_t)count, barriers.getBuffer());
}
virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier(
size_t count,
@@ -4150,7 +4141,7 @@ public:
ResourceState dst)
{
List<VkBufferMemoryBarrier> barriers;
- barriers.setCount(count);
+ barriers.reserve(count);
for (size_t i = 0; i < count; i++)
{
@@ -4171,7 +4162,7 @@ public:
VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false);
auto& vkApi = m_commandBuffer->m_renderer->m_api;
- vkApi.vkCmdPipelineBarrier(m_commandBuffer->m_commandBuffer, srcStage, dstStage, 0, 0, nullptr, count, barriers.getBuffer(), 0, nullptr);
+ vkApi.vkCmdPipelineBarrier(m_commandBuffer->m_commandBuffer, srcStage, dstStage, 0, 0, nullptr, (uint32_t)count, barriers.getBuffer(), 0, nullptr);
}
virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override
{
@@ -4661,10 +4652,10 @@ public:
};
class TransientResourceHeapImpl
- : public TransientResourceHeapBase<VKDevice, BufferResourceImpl>
+ : public TransientResourceHeapBaseImpl<VKDevice, BufferResourceImpl>
{
private:
- typedef TransientResourceHeapBase<VKDevice, BufferResourceImpl> Super;
+ typedef TransientResourceHeapBaseImpl<VKDevice, BufferResourceImpl> Super;
public:
VkCommandPool m_commandPool;
@@ -4708,19 +4699,9 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL synchronizeAndReset() override;
};
- class QueryPoolImpl
- : public IQueryPool
- , public ComObject
+ class QueryPoolImpl : public QueryPoolBase
{
public:
- SLANG_COM_OBJECT_IUNKNOWN_ALL
- IQueryPool* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IQueryPool)
- return static_cast<IQueryPool*>(this);
- return nullptr;
- }
- public:
Result init(const IQueryPool::Desc& desc, VKDevice* device)
{
m_device = device;
@@ -6177,9 +6158,9 @@ static VkBufferUsageFlagBits _calcBufferUsageFlags(ResourceState state)
return VkBufferUsageFlagBits(0);
}
case ResourceState::UnorderedAccess:
- return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+ return (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
case ResourceState::ShaderResource:
- return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ return (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
case ResourceState::CopySource:
return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
case ResourceState::CopyDestination:
@@ -6302,7 +6283,7 @@ void VKDevice::_transitionImageLayout(VkImage image, VkFormat format, const Text
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = desc.numMipLevels;
barrier.subresourceRange.baseArrayLayer = 0;
- barrier.subresourceRange.layerCount = 1;
+ barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
@@ -6425,7 +6406,6 @@ Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, con
// Create the image
{
VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
-
switch (desc.type)
{
case IResource::Type::Texture1D:
@@ -6444,6 +6424,7 @@ Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, con
{
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 };
+ imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
break;
}
case IResource::Type::Texture3D:
@@ -6470,9 +6451,8 @@ Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, con
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.cpuAccessFlags, initData);
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-
+
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- imageInfo.flags = 0; // Optional
SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image));
}
@@ -6661,7 +6641,11 @@ Result VKDevice::createBufferResource(const IBufferResource::Desc& descIn, const
{
usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
}
-
+ if (desc.allowedStates.contains(ResourceState::ShaderResource) &&
+ m_api.m_extendedFeatures.accelerationStructureFeatures.accelerationStructure)
+ {
+ usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
+ }
if (initData)
{
usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
@@ -6861,19 +6845,20 @@ Result VKDevice::createTextureView(ITextureResource* texture, IResourceView::Des
createInfo.format = resourceImpl->m_vkformat;
createInfo.image = resourceImpl->m_image;
createInfo.components = VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,VK_COMPONENT_SWIZZLE_B,VK_COMPONENT_SWIZZLE_A };
+ bool isArray = resourceImpl->getDesc()->arraySize != 0;
switch (resourceImpl->getType())
{
case IResource::Type::Texture1D:
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
+ createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
break;
case IResource::Type::Texture2D:
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
break;
case IResource::Type::Texture3D:
createInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
break;
case IResource::Type::TextureCube:
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
+ createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
break;
default:
SLANG_UNIMPLEMENTED_X("Unknown Texture type.");
@@ -7144,6 +7129,19 @@ Result VKDevice::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObjec
return SLANG_OK;
}
+Result VKDevice::createMutableShaderObject(
+ ShaderObjectLayoutBase* layout,
+ IShaderObject** outObject)
+{
+ auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
+
+ RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
+ SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
+ returnComPtr(outObject, result);
+
+ return SLANG_OK;
+}
+
Result VKDevice::createGraphicsPipelineState(const GraphicsPipelineStateDesc& inDesc, IPipelineState** outState)
{
GraphicsPipelineStateDesc desc = inDesc;
diff --git a/tools/slang-test/options.cpp b/tools/slang-test/options.cpp
index 27b759a0e..fa7f332b0 100644
--- a/tools/slang-test/options.cpp
+++ b/tools/slang-test/options.cpp
@@ -266,6 +266,10 @@ static bool _isSubCommand(const char* arg)
return res;
}
}
+ else if (strcmp(arg, "-skip-api-detection") == 0)
+ {
+ optionsOut->skipApiDetection = true;
+ }
else
{
stdError.print("unknown option '%s'\n", arg);
diff --git a/tools/slang-test/options.h b/tools/slang-test/options.h
index a8c2e3852..eacbc7acb 100644
--- a/tools/slang-test/options.h
+++ b/tools/slang-test/options.h
@@ -61,6 +61,9 @@ struct Options
// force generation of baselines for HLSL tests
bool generateHLSLBaselines = false;
+ // Whether to skip the step of creating test devices to check if an API is actually available.
+ bool skipApiDetection = false;
+
// Dump expected/actual output on failures, for debugging.
// This is especially intended for use in continuous
// integration builds.
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 6fb270c35..8f7c7e35b 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -897,6 +897,11 @@ static RenderApiFlags _getAvailableRenderApiFlags(TestContext* context)
// See if it's possible the api is available
if (RenderApiUtil::calcHasApi(apiType))
{
+ if (context->options.skipApiDetection)
+ {
+ availableRenderApiFlags |= RenderApiFlags(1) << int(apiType);
+ continue;
+ }
// Try starting up the device
CommandLine cmdLine;
cmdLine.setExecutablePath(Path::combine(context->options.binDir, String("render-test") + ProcessUtil::getExecutableSuffix()));
@@ -908,7 +913,6 @@ static RenderApiFlags _getAvailableRenderApiFlags(TestContext* context)
StringBuilder builder;
builder << "-" << RenderApiUtil::getApiName(apiType);
cmdLine.addArg(builder);
-
// Run the render-test tool and see if the device could startup
ExecuteResult exeRes;
if (SLANG_SUCCEEDED(spawnAndWaitSharedLibrary(context, "device-startup", cmdLine, exeRes))
@@ -3337,6 +3341,8 @@ static void _disableCPPBackends(TestContext* context)
for (auto passThru : cppPassThrus)
{
context->availableBackendFlags &= ~(PassThroughFlags(1) << int(passThru));
+ context->availableRenderApiFlags &= ~(RenderApiFlag::CPU);
+ context->options.enabledApis &= ~(RenderApiFlag::CPU);
}
}
diff --git a/tools/slang-test/test-reporter.cpp b/tools/slang-test/test-reporter.cpp
index 84bcaa32c..8000fd2a5 100644
--- a/tools/slang-test/test-reporter.cpp
+++ b/tools/slang-test/test-reporter.cpp
@@ -338,6 +338,7 @@ void TestReporter::_addResult(const TestInfo& info)
_appendTime(info.executionTime, buffer);
}
printf("%s test: '%S' %s\n", resultString, info.name.toWString().begin(), buffer.getBuffer());
+ fflush(stdout);
};
switch (m_outputMode)
@@ -498,7 +499,7 @@ void TestReporter::message(TestMessageType type, const String& message)
{
fputs(message.getBuffer(), stderr);
}
-
+ fflush(stderr);
// Just dump out if can dump out
return;
}
@@ -515,6 +516,7 @@ void TestReporter::message(TestMessageType type, const String& message)
{
fputs(message.getBuffer(), stderr);
}
+ fflush(stderr);
}
if (m_currentMessage.getLength() > 0)