summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/visual-studio/gfx/gfx.vcxproj2
-rw-r--r--build/visual-studio/gfx/gfx.vcxproj.filters6
-rw-r--r--examples/example-base/example-base.cpp51
-rw-r--r--examples/example-base/example-base.h3
-rw-r--r--examples/gpu-printing/gpu-printing.cpp2
-rw-r--r--examples/hello-world/main.cpp1
-rw-r--r--slang-gfx.h48
-rw-r--r--tools/gfx/cpu/render-cpu.cpp12
-rw-r--r--tools/gfx/cuda/render-cuda.cpp5
-rw-r--r--tools/gfx/d3d11/render-d3d11.cpp5
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp7
-rw-r--r--tools/gfx/debug-layer.cpp948
-rw-r--r--tools/gfx/debug-layer.h419
-rw-r--r--tools/gfx/open-gl/render-gl.cpp28
-rw-r--r--tools/gfx/render.cpp44
-rw-r--r--tools/gfx/renderer-shared.cpp27
-rw-r--r--tools/gfx/renderer-shared.h16
-rw-r--r--tools/gfx/vulkan/render-vk.cpp19
-rw-r--r--tools/render-test/render-test-main.cpp4
19 files changed, 1606 insertions, 41 deletions
diff --git a/build/visual-studio/gfx/gfx.vcxproj b/build/visual-studio/gfx/gfx.vcxproj
index 313125919..30e38a878 100644
--- a/build/visual-studio/gfx/gfx.vcxproj
+++ b/build/visual-studio/gfx/gfx.vcxproj
@@ -189,6 +189,7 @@
<ClInclude Include="..\..\..\tools\gfx\d3d12\descriptor-heap-d3d12.h" />
<ClInclude Include="..\..\..\tools\gfx\d3d12\render-d3d12.h" />
<ClInclude Include="..\..\..\tools\gfx\d3d12\resource-d3d12.h" />
+ <ClInclude Include="..\..\..\tools\gfx\debug-layer.h" />
<ClInclude Include="..\..\..\tools\gfx\flag-combiner.h" />
<ClInclude Include="..\..\..\tools\gfx\immediate-renderer-base.h" />
<ClInclude Include="..\..\..\tools\gfx\nvapi\nvapi-include.h" />
@@ -216,6 +217,7 @@
<ClCompile Include="..\..\..\tools\gfx\d3d12\descriptor-heap-d3d12.cpp" />
<ClCompile Include="..\..\..\tools\gfx\d3d12\render-d3d12.cpp" />
<ClCompile Include="..\..\..\tools\gfx\d3d12\resource-d3d12.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx\debug-layer.cpp" />
<ClCompile Include="..\..\..\tools\gfx\flag-combiner.cpp" />
<ClCompile Include="..\..\..\tools\gfx\immediate-renderer-base.cpp" />
<ClCompile Include="..\..\..\tools\gfx\nvapi\nvapi-util.cpp" />
diff --git a/build/visual-studio/gfx/gfx.vcxproj.filters b/build/visual-studio/gfx/gfx.vcxproj.filters
index 9065b785f..8920d30a6 100644
--- a/build/visual-studio/gfx/gfx.vcxproj.filters
+++ b/build/visual-studio/gfx/gfx.vcxproj.filters
@@ -39,6 +39,9 @@
<ClInclude Include="..\..\..\tools\gfx\d3d12\resource-d3d12.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\tools\gfx\debug-layer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\tools\gfx\flag-combiner.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -116,6 +119,9 @@
<ClCompile Include="..\..\..\tools\gfx\d3d12\resource-d3d12.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx\debug-layer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx\flag-combiner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp
index a75ddf247..04f938697 100644
--- a/examples/example-base/example-base.cpp
+++ b/examples/example-base/example-base.cpp
@@ -25,6 +25,10 @@ Slang::Result WindowedAppBase::initializeBase(const char* title, int width, int
gWindow->events.sizeChanged = Slang::Action<>(this, &WindowedAppBase::windowSizeChanged);
// Initialize the rendering layer.
+#ifdef _DEBUG
+ // Enable debug layer in debug config.
+ gfxEnableDebugLayer();
+#endif
IDevice::Desc deviceDesc = {};
// deviceDesc.slang.targetFlags = SLANG_TARGET_FLAG_DUMP_IR;
gfx::Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef());
@@ -170,6 +174,53 @@ int64_t getCurrentTime() { return std::chrono::high_resolution_clock::now().time
int64_t getTimerFrequency() { return std::chrono::high_resolution_clock::period::den; }
+class DebugCallback : public IDebugCallback
+{
+public:
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override
+ {
+ const char* typeStr = "";
+ switch (type)
+ {
+ case DebugMessageType::Info:
+ typeStr = "INFO: ";
+ break;
+ case DebugMessageType::Warning:
+ typeStr = "WARNING: ";
+ break;
+ case DebugMessageType::Error:
+ typeStr = "ERROR: ";
+ break;
+ default:
+ break;
+ }
+ const char* sourceStr = "[GraphicsLayer]: ";
+ switch (source)
+ {
+ case DebugMessageSource::Slang:
+ sourceStr = "[Slang]: ";
+ break;
+ case DebugMessageSource::Driver:
+ sourceStr = "[Driver]: ";
+ break;
+ }
+ printf("%s%s%s\n", sourceStr, typeStr, message);
+#ifdef _WIN32
+ OutputDebugStringA(sourceStr);
+ OutputDebugStringA(typeStr);
+ OutputDebugStringW(String(message).toWString());
+ OutputDebugStringW(L"\n");
+#endif
+ }
+};
+
+void initDebugCallback()
+{
+ static DebugCallback callback = {};
+ gfxSetDebugCallback(&callback);
+}
+
#ifdef _WIN32
void _Win32OutputDebugString(const char* str) { OutputDebugStringW(Slang::String(str).toWString().begin()); }
#endif
diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h
index 67f722c11..a1c46aa53 100644
--- a/examples/example-base/example-base.h
+++ b/examples/example-base/example-base.h
@@ -72,10 +72,13 @@ inline void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
}
}
+void initDebugCallback();
template<typename TApp>
int innerMain()
{
+ initDebugCallback();
+
TApp app;
if (SLANG_FAILED(app.initialize()))
diff --git a/examples/gpu-printing/gpu-printing.cpp b/examples/gpu-printing/gpu-printing.cpp
index f1e842e95..aeca7aa9a 100644
--- a/examples/gpu-printing/gpu-printing.cpp
+++ b/examples/gpu-printing/gpu-printing.cpp
@@ -156,7 +156,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// that the buffer is corrupted or invalid, but we will try to
// soldier on and process further commands.
//
- fprintf(stderr, "error: unexpected GPU printing op %d\n", op);
+ fprintf(stderr, "error: unexpected GPU printing op %d\n", (int)op);
break;
case GPUPrintingOp::Nop:
diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp
index da149a8e0..e635b3a48 100644
--- a/examples/hello-world/main.cpp
+++ b/examples/hello-world/main.cpp
@@ -66,6 +66,7 @@ struct HelloWorldExample
int main()
{
+ initDebugCallback();
HelloWorldExample example;
return example.run();
}
diff --git a/slang-gfx.h b/slang-gfx.h
index a8234f6bb..e6f5048be 100644
--- a/slang-gfx.h
+++ b/slang-gfx.h
@@ -1061,6 +1061,21 @@ struct DeviceInfo
const char* adapterName = nullptr;
};
+enum class DebugMessageType
+{
+ Info, Warning, Error
+};
+enum class DebugMessageSource
+{
+ Layer, Driver, Slang
+};
+class IDebugCallback
+{
+public:
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) = 0;
+};
+
class IDevice: public ISlangUnknown
{
public:
@@ -1084,13 +1099,21 @@ public:
struct Desc
{
- DeviceType deviceType = DeviceType::Default; // The underlying API/Platform of the device.
- const char* adapter = nullptr; // Name to identify the adapter to use
- int requiredFeatureCount = 0; // Number of required features.
- const char** requiredFeatures = nullptr; // Array of required feature names, whose size is `requiredFeatureCount`.
- int nvapiExtnSlot = -1; // The slot (typically UAV) used to identify NVAPI intrinsics. If >=0 NVAPI is required.
- ISlangFileSystem* shaderCacheFileSystem = nullptr; // The file system for loading cached shader kernels.
- SlangDesc slang = {}; // Configurations for Slang.
+ // The underlying API/Platform of the device.
+ DeviceType deviceType = DeviceType::Default;
+ // Name to identify the adapter to use
+ const char* adapter = nullptr;
+ // Number of required features.
+ int requiredFeatureCount = 0;
+ // Array of required feature names, whose size is `requiredFeatureCount`.
+ const char** requiredFeatures = nullptr;
+ // The slot (typically UAV) used to identify NVAPI intrinsics. If >=0 NVAPI is required.
+ int nvapiExtnSlot = -1;
+ // The file system for loading cached shader kernels. The layer does not maintain a strong reference to the object,
+ // instead the user is responsible for holding the object alive during the lifetime of an `IDevice`.
+ ISlangFileSystem* shaderCacheFileSystem = nullptr;
+ // Configurations for Slang compiler.
+ SlangDesc slang = {};
};
virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature(const char* feature) = 0;
@@ -1308,7 +1331,7 @@ public:
virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const = 0;
};
-#define SLANG_UUID_IRenderer \
+#define SLANG_UUID_IDevice \
{ \
0x715bdf26, 0x5135, 0x11eb, { 0xAE, 0x93, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x02 } \
}
@@ -1324,6 +1347,15 @@ extern "C"
SLANG_GFX_API SlangResult SLANG_MCALL
gfxCreateDevice(const IDevice::Desc* desc, IDevice** outDevice);
+ /// Sets a callback for receiving debug messages.
+ /// The layer does not hold a strong reference to the callback object.
+ /// The user is responsible for holding the callback object alive.
+ SLANG_GFX_API SlangResult SLANG_MCALL
+ gfxSetDebugCallback(IDebugCallback* callback);
+
+ /// Enables debug layer. The debug layer will check all `gfx` calls and verify that uses are valid.
+ SLANG_GFX_API void SLANG_MCALL gfxEnableDebugLayer();
+
SLANG_GFX_API const char* SLANG_MCALL gfxGetDeviceTypeName(DeviceType type);
}
diff --git a/tools/gfx/cpu/render-cpu.cpp b/tools/gfx/cpu/render-cpu.cpp
index af1641e60..2d7d858c4 100644
--- a/tools/gfx/cpu/render-cpu.cpp
+++ b/tools/gfx/cpu/render-cpu.cpp
@@ -1136,7 +1136,17 @@ private:
auto entryPointObject = m_currentRootObject->getEntryPoint(entryPointIndex);
ComPtr<ISlangSharedLibrary> sharedLibrary;
- program->slangProgram->getEntryPointHostCallable(entryPointIndex, targetIndex, sharedLibrary.writeRef());
+ ComPtr<ISlangBlob> diagnostics;
+ auto compileResult = program->slangProgram->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);
diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp
index 14699915b..a6400789f 100644
--- a/tools/gfx/cuda/render-cuda.cpp
+++ b/tools/gfx/cuda/render-cuda.cpp
@@ -1883,7 +1883,10 @@ public:
(SlangInt)0, 0, kernelCode.writeRef(), diagnostics.writeRef());
if (diagnostics)
{
- // TODO: report compile error.
+ getDebugCallback()->handleMessage(
+ compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
+ DebugMessageSource::Slang,
+ (char*)diagnostics->getBufferPointer());
}
SLANG_RETURN_ON_FAIL(compileResult);
diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp
index bbc213bb6..5108b4d8b 100644
--- a/tools/gfx/d3d11/render-d3d11.cpp
+++ b/tools/gfx/d3d11/render-d3d11.cpp
@@ -2762,7 +2762,10 @@ Result D3D11Device::createProgram(const IShaderProgram::Desc& desc, IShaderProgr
if (diagnostics)
{
- // TODO: dump compiler output.
+ getDebugCallback()->handleMessage(
+ compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
+ DebugMessageSource::Slang,
+ (char*)diagnostics->getBufferPointer());
}
SLANG_RETURN_ON_FAIL(compileResult);
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index a752222d6..8cb9ce197 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -3849,7 +3849,6 @@ Result D3D12Device::initialize(const Desc& desc)
debug1->SetEnableGPUBasedValidation(true);
}
#endif
-
m_dxDebug->EnableDebugLayer();
}
}
@@ -4824,8 +4823,10 @@ Result D3D12Device::createProgram(const IShaderProgram::Desc& desc, IShaderProgr
(SlangInt)i, 0, kernelCode.writeRef(), diagnostics.writeRef());
if (diagnostics)
{
- printf("%s\n", (char*)diagnostics->getBufferPointer());
- // TODO: report compile error.
+ getDebugCallback()->handleMessage(
+ compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
+ DebugMessageSource::Slang,
+ (char*)diagnostics->getBufferPointer());
}
SLANG_RETURN_ON_FAIL(compileResult);
List<uint8_t>* shaderCodeDestBuffer = nullptr;
diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp
new file mode 100644
index 000000000..aa8989623
--- /dev/null
+++ b/tools/gfx/debug-layer.cpp
@@ -0,0 +1,948 @@
+#include "debug-layer.h"
+#include "renderer-shared.h"
+#include "slang-gfx.h"
+
+using namespace Slang;
+
+namespace gfx
+{
+#ifdef __FUNCSIG__
+# define SLANG_FUNC_SIG __FUNCSIG__
+#elif defined(__PRETTY_FUNCTION__)
+# define SLANG_FUNC_SIG __FUNCSIG__
+#elif defined(__FUNCTION__)
+# define SLANG_FUNC_SIG __FUNCTION__
+#else
+# define SLANG_FUNC_SIG "UnknownFunction"
+#endif
+
+thread_local const char* _currentFunctionName = nullptr;
+struct SetCurrentFuncRAII
+{
+ SetCurrentFuncRAII(const char* funcName) { _currentFunctionName = funcName; }
+ ~SetCurrentFuncRAII() { _currentFunctionName = nullptr; }
+};
+#define SLANG_GFX_API_FUNC SetCurrentFuncRAII setFuncNameRAII(SLANG_FUNC_SIG)
+#define SLANG_GFX_API_FUNC_NAME(x) SetCurrentFuncRAII setFuncNameRAII(x)
+
+/// Returns the public API function name from a `SLANG_FUNC_SIG` string.
+String _gfxGetFuncName(const char* input)
+{
+ UnownedStringSlice str(input);
+ auto prefixIndex = str.indexOf(UnownedStringSlice("Debug"));
+ if (prefixIndex == -1)
+ return input;
+ auto endIndex = str.lastIndexOf('(');
+ if (endIndex == -1)
+ endIndex = str.getLength();
+ auto startIndex = prefixIndex + 5;
+ StringBuilder sb;
+ sb.appendChar('I');
+ sb.append(str.subString(startIndex, endIndex - startIndex));
+ return sb.ProduceString();
+}
+
+template <typename... TArgs>
+static char* _gfxDiagnoseFormat(
+ char* buffer, // Initial buffer to output formatted string.
+ size_t shortBufferSize, // Size of the initial buffer.
+ List<char>& bufferArray, // A list for allocating a large buffer if needed.
+ const char* format, // The format string.
+ TArgs... args)
+{
+ int length = sprintf_s(buffer, shortBufferSize, format, args...);
+ if (length < 0)
+ return buffer;
+ if (length > 255)
+ {
+ bufferArray.setCount(length + 1);
+ buffer = bufferArray.getBuffer();
+ sprintf_s(buffer, bufferArray.getCount(), format, args...);
+ }
+ return buffer;
+}
+
+template <typename... TArgs>
+static void _gfxDiagnoseImpl(DebugMessageType type, const char* format, TArgs... args)
+{
+ char shortBuffer[256];
+ List<char> bufferArray;
+ auto buffer =
+ _gfxDiagnoseFormat(shortBuffer, sizeof(shortBuffer), bufferArray, format, args...);
+ getDebugCallback()->handleMessage(type, DebugMessageSource::Layer, buffer);
+}
+
+#define GFX_DIAGNOSE_ERROR(message) \
+ _gfxDiagnoseImpl( \
+ DebugMessageType::Error, \
+ "%s: %s", \
+ _gfxGetFuncName(_currentFunctionName ? _currentFunctionName : SLANG_FUNC_SIG).getBuffer(), \
+ message)
+#define GFX_DIAGNOSE_WARNING(message) \
+ _gfxDiagnoseImpl( \
+ DebugMessageType::Warning, \
+ "%s: %s", \
+ _gfxGetFuncName(_currentFunctionName ? _currentFunctionName : SLANG_FUNC_SIG).getBuffer(), \
+ message)
+#define GFX_DIAGNOSE_INFO(message) \
+ _gfxDiagnoseImpl( \
+ DebugMessageType::Info, \
+ "%s: %s", \
+ _gfxGetFuncName(_currentFunctionName ? _currentFunctionName : SLANG_FUNC_SIG).getBuffer(), \
+ message)
+#define GFX_DIAGNOSE_FORMAT(type, format, ...) \
+ { \
+ char shortBuffer[256]; \
+ List<char> bufferArray; \
+ auto message = _gfxDiagnoseFormat( \
+ shortBuffer, sizeof(shortBuffer), bufferArray, format, __VA_ARGS__); \
+ _gfxDiagnoseImpl( \
+ type, \
+ "%s: %s", \
+ _gfxGetFuncName(_currentFunctionName ? _currentFunctionName : SLANG_FUNC_SIG) \
+ .getBuffer(), \
+ message); \
+ }
+#define GFX_DIAGNOSE_ERROR_FORMAT(...) GFX_DIAGNOSE_FORMAT(DebugMessageType::Error, __VA_ARGS__)
+
+#define SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(typeName) \
+ I##typeName* Debug##typeName::getInterface(const Slang::Guid& guid) \
+ { \
+ return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_I##typeName) \
+ ? static_cast<I##typeName*>(this) \
+ : nullptr; \
+ }
+#define SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(typeName, parentType) \
+ I##typeName* Debug##typeName::getInterface(const Slang::Guid& guid) \
+ { \
+ return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_I##typeName || \
+ guid == GfxGUID::IID_I##parentType) \
+ ? static_cast<I##typeName*>(this) \
+ : nullptr; \
+ }
+
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(Device)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(BufferResource, Resource)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(TextureResource, Resource)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(CommandBuffer)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(CommandQueue)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(ComputeCommandEncoder, CommandEncoder)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(RenderCommandEncoder, CommandEncoder)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT(ResourceCommandEncoder, CommandEncoder)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(Framebuffer)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(FramebufferLayout)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(InputLayout)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(RenderPassLayout)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(PipelineState)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(ResourceView)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(SamplerState)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(ShaderObject)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(ShaderProgram)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(Swapchain)
+SLANG_GFX_DEBUG_GET_INTERFACE_IMPL(TransientResourceHeap)
+
+#undef SLANG_GFX_DEBUG_GET_INTERFACE_IMPL
+#undef SLANG_GFX_DEBUG_GET_INTERFACE_IMPL_PARENT
+
+Result DebugDevice::getFeatures(const char** outFeatures, UInt bufferSize, UInt* outFeatureCount)
+{
+ SLANG_GFX_API_FUNC;
+
+ return baseObject->getFeatures(outFeatures, bufferSize, outFeatureCount);
+}
+
+DebugDevice::DebugDevice()
+{
+ SLANG_GFX_API_FUNC_NAME("CreateDevice");
+ GFX_DIAGNOSE_INFO("Debug layer is enabled.");
+}
+
+SLANG_NO_THROW bool SLANG_MCALL DebugDevice::hasFeature(const char* feature)
+{
+ SLANG_GFX_API_FUNC;
+
+ return baseObject->hasFeature(feature);
+}
+
+Result DebugDevice::getSlangSession(slang::ISession** outSlangSession)
+{
+ SLANG_GFX_API_FUNC;
+
+ return baseObject->getSlangSession(outSlangSession);
+}
+
+Result DebugDevice::createTransientResourceHeap(
+ const ITransientResourceHeap::Desc& desc,
+ ITransientResourceHeap** outHeap)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugTransientResourceHeap> outObject = new DebugTransientResourceHeap();
+ auto result = baseObject->createTransientResourceHeap(desc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outHeap, outObject);
+ return result;
+}
+
+Result DebugDevice::createTextureResource(
+ const ITextureResource::Desc& desc,
+ const ITextureResource::SubresourceData* initData,
+ ITextureResource** outResource)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugTextureResource> outObject = new DebugTextureResource();
+ auto result =
+ baseObject->createTextureResource(desc, initData, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outResource, outObject);
+ return result;
+}
+
+Result DebugDevice::createBufferResource(
+ const IBufferResource::Desc& desc,
+ const void* initData,
+ IBufferResource** outResource)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugBufferResource> outObject = new DebugBufferResource();
+ auto result =
+ baseObject->createBufferResource(desc, initData, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outResource, outObject);
+ return result;
+}
+
+Result DebugDevice::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugSamplerState> outObject = new DebugSamplerState();
+ auto result = baseObject->createSamplerState(desc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outSampler, outObject);
+ return result;
+}
+
+Result DebugDevice::createTextureView(
+ ITextureResource* texture,
+ IResourceView::Desc const& desc,
+ IResourceView** outView)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugResourceView> outObject = new DebugResourceView();
+ auto result = baseObject->createTextureView(
+ static_cast<DebugTextureResource*>(texture)->baseObject,
+ desc,
+ outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outView, outObject);
+ return result;
+}
+
+Result DebugDevice::createBufferView(
+ IBufferResource* buffer,
+ IResourceView::Desc const& desc,
+ IResourceView** outView)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugResourceView> outObject = new DebugResourceView();
+ auto result = baseObject->createBufferView(
+ static_cast<DebugBufferResource*>(buffer)->baseObject,
+ desc,
+ outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outView, outObject);
+ return result;
+}
+
+Result DebugDevice::createFramebufferLayout(
+ IFramebufferLayout::Desc const& desc,
+ IFramebufferLayout** outFrameBuffer)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugFramebufferLayout> outObject = new DebugFramebufferLayout();
+ auto result = baseObject->createFramebufferLayout(desc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outFrameBuffer, outObject);
+ return result;
+}
+
+Result DebugDevice::createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer)
+{
+ SLANG_GFX_API_FUNC;
+
+ auto innerDesc = desc;
+ innerDesc.layout =
+ desc.layout ? static_cast<DebugFramebufferLayout*>(desc.layout)->baseObject.get() : nullptr;
+ innerDesc.depthStencilView =
+ desc.depthStencilView
+ ? static_cast<DebugResourceView*>(desc.depthStencilView)->baseObject.get()
+ : nullptr;
+ List<IResourceView*> innerRenderTargets;
+ for (uint32_t i = 0; i < desc.renderTargetCount; i++)
+ {
+ auto innerRenderTarget =
+ desc.renderTargetViews[i]
+ ? static_cast<DebugResourceView*>(desc.renderTargetViews[i])->baseObject.get()
+ : nullptr;
+ innerRenderTargets.add(innerRenderTarget);
+ }
+ innerDesc.renderTargetViews = innerRenderTargets.getBuffer();
+
+ RefPtr<DebugFramebuffer> outObject = new DebugFramebuffer();
+ auto result = baseObject->createFramebuffer(innerDesc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outFrameBuffer, outObject);
+ return result;
+}
+
+Result DebugDevice::createRenderPassLayout(
+ const IRenderPassLayout::Desc& desc,
+ IRenderPassLayout** outRenderPassLayout)
+{
+ SLANG_GFX_API_FUNC;
+
+ auto innerDesc = desc;
+ innerDesc.framebufferLayout =
+ desc.framebufferLayout? static_cast<DebugFramebufferLayout*>(desc.framebufferLayout)->baseObject.get()
+ : nullptr;
+ RefPtr<DebugRenderPassLayout> outObject = new DebugRenderPassLayout();
+ auto result = baseObject->createRenderPassLayout(innerDesc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outRenderPassLayout, outObject);
+ return result;
+}
+
+Result DebugDevice::createSwapchain(
+ ISwapchain::Desc const& desc,
+ WindowHandle window,
+ ISwapchain** outSwapchain)
+{
+ SLANG_GFX_API_FUNC;
+
+ auto innerDesc = desc;
+ innerDesc.queue = static_cast<DebugCommandQueue*>(desc.queue)->baseObject.get();
+ RefPtr<DebugSwapchain> outObject = new DebugSwapchain();
+ outObject->queue = static_cast<DebugCommandQueue*>(desc.queue);
+ auto result = baseObject->createSwapchain(innerDesc, window, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outSwapchain, outObject);
+ return Result();
+}
+
+Result DebugDevice::createInputLayout(
+ const InputElementDesc* inputElements,
+ UInt inputElementCount,
+ IInputLayout** outLayout)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugInputLayout> outObject = new DebugInputLayout();
+ auto result = baseObject->createInputLayout(
+ inputElements, inputElementCount, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outLayout, outObject);
+ return result;
+}
+
+Result DebugDevice::createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugCommandQueue> outObject = new DebugCommandQueue();
+ auto result = baseObject->createCommandQueue(desc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outQueue, outObject);
+ return result;
+}
+
+Result DebugDevice::createShaderObject(slang::TypeReflection* type, IShaderObject** outShaderObject)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugShaderObject> outObject = new DebugShaderObject();
+ auto result = baseObject->createShaderObject(type, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outShaderObject, outObject);
+ return result;
+}
+
+Result DebugDevice::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
+{
+ SLANG_GFX_API_FUNC;
+
+ RefPtr<DebugShaderProgram> outObject = new DebugShaderProgram();
+ auto result = baseObject->createProgram(desc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outProgram, outObject);
+ return result;
+}
+
+Result DebugDevice::createGraphicsPipelineState(
+ const GraphicsPipelineStateDesc& desc,
+ IPipelineState** outState)
+{
+ SLANG_GFX_API_FUNC;
+
+ GraphicsPipelineStateDesc innerDesc = desc;
+ innerDesc.program =
+ desc.program ? static_cast<DebugShaderProgram*>(desc.program)->baseObject : nullptr;
+ innerDesc.inputLayout =
+ desc.inputLayout ? static_cast<DebugInputLayout*>(desc.inputLayout)->baseObject : nullptr;
+ innerDesc.framebufferLayout =
+ desc.framebufferLayout
+ ? static_cast<DebugFramebufferLayout*>(desc.framebufferLayout)->baseObject
+ : nullptr;
+ RefPtr<DebugPipelineState> outObject = new DebugPipelineState();
+ auto result =
+ baseObject->createGraphicsPipelineState(innerDesc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outState, outObject);
+ return result;
+}
+
+Result DebugDevice::createComputePipelineState(
+ const ComputePipelineStateDesc& desc,
+ IPipelineState** outState)
+{
+ SLANG_GFX_API_FUNC;
+
+ ComputePipelineStateDesc innerDesc = desc;
+ innerDesc.program = static_cast<DebugShaderProgram*>(desc.program)->baseObject;
+
+ RefPtr<DebugPipelineState> outObject = new DebugPipelineState();
+ auto result =
+ baseObject->createComputePipelineState(innerDesc, outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outState, outObject);
+ return result;
+}
+
+SlangResult DebugDevice::readTextureResource(
+ ITextureResource* resource,
+ ResourceState state,
+ ISlangBlob** outBlob,
+ size_t* outRowPitch,
+ size_t* outPixelSize)
+{
+ SLANG_GFX_API_FUNC;
+ auto resourceImpl = static_cast<DebugTextureResource*>(resource);
+ return baseObject->readTextureResource(
+ resourceImpl->baseObject, state, outBlob, outRowPitch, outPixelSize);
+}
+
+SlangResult DebugDevice::readBufferResource(
+ IBufferResource* buffer,
+ size_t offset,
+ size_t size,
+ ISlangBlob** outBlob)
+{
+ SLANG_GFX_API_FUNC;
+ auto bufferImpl = static_cast<DebugBufferResource*>(buffer);
+ return baseObject->readBufferResource(bufferImpl->baseObject, offset, size, outBlob);
+}
+
+const DeviceInfo& DebugDevice::getDeviceInfo() const
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getDeviceInfo();
+}
+
+IResource::Type DebugBufferResource::getType()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getType();
+}
+
+IBufferResource::Desc* DebugBufferResource::getDesc()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getDesc();
+}
+
+IResource::Type DebugTextureResource::getType()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getType();
+}
+
+ITextureResource::Desc* DebugTextureResource::getDesc()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getDesc();
+}
+
+DebugCommandBuffer::DebugCommandBuffer()
+{
+ SLANG_GFX_API_FUNC;
+ m_renderCommandEncoder.commandBuffer = this;
+ m_computeCommandEncoder.commandBuffer = this;
+ m_resourceCommandEncoder.commandBuffer = this;
+}
+
+void DebugCommandBuffer::encodeRenderCommands(
+ IRenderPassLayout* renderPass,
+ IFramebuffer* framebuffer,
+ IRenderCommandEncoder** outEncoder)
+{
+ SLANG_GFX_API_FUNC;
+ checkCommandBufferOpenWhenCreatingEncoder();
+ checkEncodersClosedBeforeNewEncoder();
+ auto innerRenderPass =
+ renderPass ? static_cast<DebugRenderPassLayout*>(renderPass)->baseObject : nullptr;
+ auto innerFramebuffer =
+ framebuffer ? static_cast<DebugFramebuffer*>(framebuffer)->baseObject : nullptr;
+ m_renderCommandEncoder.isOpen = true;
+ baseObject->encodeRenderCommands(
+ innerRenderPass, innerFramebuffer, m_renderCommandEncoder.baseObject.writeRef());
+ if (m_renderCommandEncoder.baseObject)
+ *outEncoder = &m_renderCommandEncoder;
+ else
+ *outEncoder = nullptr;
+}
+
+void DebugCommandBuffer::encodeComputeCommands(IComputeCommandEncoder** outEncoder)
+{
+ SLANG_GFX_API_FUNC;
+ checkCommandBufferOpenWhenCreatingEncoder();
+ checkEncodersClosedBeforeNewEncoder();
+ m_computeCommandEncoder.isOpen = true;
+ baseObject->encodeComputeCommands(m_computeCommandEncoder.baseObject.writeRef());
+ *outEncoder = &m_computeCommandEncoder;
+}
+
+void DebugCommandBuffer::encodeResourceCommands(IResourceCommandEncoder** outEncoder)
+{
+ SLANG_GFX_API_FUNC;
+ checkCommandBufferOpenWhenCreatingEncoder();
+ checkEncodersClosedBeforeNewEncoder();
+ m_resourceCommandEncoder.isOpen = true;
+ baseObject->encodeResourceCommands(m_resourceCommandEncoder.baseObject.writeRef());
+ *outEncoder = &m_resourceCommandEncoder;
+}
+
+void DebugCommandBuffer::close()
+{
+ SLANG_GFX_API_FUNC;
+ if (!isOpen)
+ {
+ GFX_DIAGNOSE_ERROR("command buffer is already closed.");
+ }
+ if (m_renderCommandEncoder.isOpen)
+ {
+ GFX_DIAGNOSE_ERROR(
+ "A render command encoder on this command buffer is still open. "
+ "IRenderCommandEncoder::endEncoding() must be called before closing a command buffer.");
+ }
+ if (m_computeCommandEncoder.isOpen)
+ {
+ GFX_DIAGNOSE_ERROR(
+ "A compute command encoder on this command buffer is still open. "
+ "IComputeCommandEncoder::endEncoding() must be called before closing a command buffer.");
+ }
+ if (m_resourceCommandEncoder.isOpen)
+ {
+ GFX_DIAGNOSE_ERROR(
+ "A resource command encoder on this command buffer is still open. "
+ "IResourceCommandEncoder::endEncoding() must be called before closing a command buffer.");
+ }
+ isOpen = false;
+ baseObject->close();
+}
+
+void DebugCommandBuffer::checkEncodersClosedBeforeNewEncoder()
+{
+ if (m_renderCommandEncoder.isOpen || m_resourceCommandEncoder.isOpen ||
+ m_computeCommandEncoder.isOpen)
+ {
+ GFX_DIAGNOSE_ERROR(
+ "A previouse command encoder created on this command buffer is still open. "
+ "endEncoding() must be called on the encoder before creating an encoder.");
+ }
+}
+
+void DebugCommandBuffer::checkCommandBufferOpenWhenCreatingEncoder()
+{
+ if (!isOpen)
+ {
+ GFX_DIAGNOSE_ERROR("The command buffer is already closed. Encoders can only be retrieved "
+ "while the command buffer is open.");
+ }
+}
+
+void DebugComputeCommandEncoder::endEncoding()
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->endEncoding();
+}
+
+Result DebugComputeCommandEncoder::bindPipeline(
+ IPipelineState* state,
+ IShaderObject** outRootShaderObject)
+{
+ SLANG_GFX_API_FUNC;
+
+ auto innerState = static_cast<DebugPipelineState*>(state)->baseObject;
+ auto result =
+ baseObject->bindPipeline(innerState, commandBuffer->rootObject.baseObject.writeRef());
+ *outRootShaderObject = &commandBuffer->rootObject;
+ return result;
+}
+
+void DebugComputeCommandEncoder::dispatchCompute(int x, int y, int z)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->dispatchCompute(x, y, z);
+}
+
+void DebugRenderCommandEncoder::endEncoding()
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->endEncoding();
+}
+
+Result DebugRenderCommandEncoder::bindPipeline(
+ IPipelineState* state,
+ IShaderObject** outRootShaderObject)
+{
+ SLANG_GFX_API_FUNC;
+
+ auto innerState = static_cast<DebugPipelineState*>(state)->baseObject;
+ auto result =
+ baseObject->bindPipeline(innerState, commandBuffer->rootObject.baseObject.writeRef());
+ *outRootShaderObject = &commandBuffer->rootObject;
+ return result;
+}
+
+void DebugRenderCommandEncoder::setViewports(uint32_t count, const Viewport* viewports)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->setViewports(count, viewports);
+}
+
+void DebugRenderCommandEncoder::setScissorRects(uint32_t count, const ScissorRect* scissors)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->setScissorRects(count, scissors);
+}
+
+void DebugRenderCommandEncoder::setPrimitiveTopology(PrimitiveTopology topology)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->setPrimitiveTopology(topology);
+}
+
+void DebugRenderCommandEncoder::setVertexBuffers(
+ UInt startSlot,
+ UInt slotCount,
+ IBufferResource* const* buffers,
+ const UInt* strides,
+ const UInt* offsets)
+{
+ SLANG_GFX_API_FUNC;
+
+ List<IBufferResource*> innerBuffers;
+ for (UInt i = 0; i < slotCount; i++)
+ {
+ innerBuffers.add(static_cast<DebugBufferResource*>(buffers[i])->baseObject.get());
+ }
+ baseObject->setVertexBuffers(startSlot, slotCount, innerBuffers.getBuffer(), strides, offsets);
+}
+
+void DebugRenderCommandEncoder::setIndexBuffer(
+ IBufferResource* buffer,
+ Format indexFormat,
+ UInt offset)
+{
+ SLANG_GFX_API_FUNC;
+ auto innerBuffer = static_cast<DebugBufferResource*>(buffer)->baseObject.get();
+ baseObject->setIndexBuffer(innerBuffer, indexFormat, offset);
+}
+
+void DebugRenderCommandEncoder::draw(UInt vertexCount, UInt startVertex)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->draw(vertexCount, startVertex);
+}
+
+void DebugRenderCommandEncoder::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->drawIndexed(indexCount, startIndex, baseVertex);
+}
+
+void DebugRenderCommandEncoder::setStencilReference(uint32_t referenceValue)
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->setStencilReference(referenceValue);
+}
+
+void DebugResourceCommandEncoder::endEncoding()
+{
+ SLANG_GFX_API_FUNC;
+ baseObject->endEncoding();
+}
+
+void DebugResourceCommandEncoder::copyBuffer(
+ IBufferResource* dst,
+ size_t dstOffset,
+ IBufferResource* src,
+ size_t srcOffset,
+ size_t size)
+{
+ SLANG_GFX_API_FUNC;
+ auto dstImpl = static_cast<DebugBufferResource*>(dst);
+ auto srcImpl = static_cast<DebugBufferResource*>(src);
+ baseObject->copyBuffer(dstImpl->baseObject, dstOffset, srcImpl->baseObject, srcOffset, size);
+}
+
+void DebugResourceCommandEncoder::uploadBufferData(
+ IBufferResource* dst,
+ size_t offset,
+ size_t size,
+ void* data)
+{
+ SLANG_GFX_API_FUNC;
+ auto dstImpl = static_cast<DebugBufferResource*>(dst);
+ baseObject->uploadBufferData(dstImpl->baseObject, offset, size, data);
+}
+
+const ICommandQueue::Desc& DebugCommandQueue::getDesc()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getDesc();
+}
+
+void DebugCommandQueue::executeCommandBuffers(uint32_t count, ICommandBuffer* const* commandBuffers)
+{
+ SLANG_GFX_API_FUNC;
+ List<ICommandBuffer*> innerCommandBuffers;
+ for (uint32_t i = 0; i < count; i++)
+ {
+ auto cmdBufferIn = commandBuffers[i];
+ auto cmdBufferImpl = static_cast<DebugCommandBuffer*>(cmdBufferIn);
+ auto innerCmdBuffer = cmdBufferImpl->baseObject.get();
+ innerCommandBuffers.add(innerCmdBuffer);
+ if (cmdBufferImpl->isOpen)
+ {
+ GFX_DIAGNOSE_ERROR_FORMAT(
+ "Command buffer %lld is still open. A command buffer must be closed "
+ "before submitting to a command queue.",
+ cmdBufferImpl->uid);
+ }
+ }
+ baseObject->executeCommandBuffers(count, innerCommandBuffers.getBuffer());
+}
+
+void DebugCommandQueue::wait() { baseObject->wait(); }
+
+Result DebugTransientResourceHeap::synchronizeAndReset()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->synchronizeAndReset();
+}
+
+Result DebugTransientResourceHeap::createCommandBuffer(ICommandBuffer** outCommandBuffer)
+{
+ SLANG_GFX_API_FUNC;
+ RefPtr<DebugCommandBuffer> outObject = new DebugCommandBuffer();
+ auto result = baseObject->createCommandBuffer(outObject->baseObject.writeRef());
+ if (SLANG_FAILED(result))
+ return result;
+ returnComPtr(outCommandBuffer, outObject);
+ return result;
+}
+
+const ISwapchain::Desc& DebugSwapchain::getDesc()
+{
+ SLANG_GFX_API_FUNC;
+ desc = baseObject->getDesc();
+ desc.queue = queue.Ptr();
+ return desc;
+}
+
+Result DebugSwapchain::getImage(uint32_t index, ITextureResource** outResource)
+{
+ SLANG_GFX_API_FUNC;
+ maybeRebuildImageList();
+ if (index > (uint32_t)m_images.getCount())
+ {
+ GFX_DIAGNOSE_ERROR_FORMAT(
+ "`index`(%d) must not exceed total number of images (%d) in the swapchain.",
+ index,
+ (uint32_t)m_images.getCount());
+ }
+ returnComPtr(outResource, m_images[index]);
+ return SLANG_OK;
+}
+
+Result DebugSwapchain::present()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->present();
+}
+
+int DebugSwapchain::acquireNextImage()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->acquireNextImage();
+}
+
+Result DebugSwapchain::resize(uint32_t width, uint32_t height)
+{
+ SLANG_GFX_API_FUNC;
+ for (auto& image : m_images)
+ {
+ if (image->debugGetReferenceCount() != 1)
+ {
+ GFX_DIAGNOSE_ERROR("all swapchain images must be released before calling resize().");
+ return SLANG_FAIL;
+ }
+ }
+ m_images.clearAndDeallocate();
+ return baseObject->resize(width, height);
+}
+
+void DebugSwapchain::maybeRebuildImageList()
+{
+ SLANG_GFX_API_FUNC;
+ if (m_images.getCount() != 0)
+ return;
+ m_images.clearAndDeallocate();
+ for (uint32_t i = 0; i < baseObject->getDesc().imageCount; i++)
+ {
+ RefPtr<DebugTextureResource> image = new DebugTextureResource();
+ baseObject->getImage(i, image->baseObject.writeRef());
+ m_images.add(image);
+ }
+}
+
+slang::TypeLayoutReflection* DebugShaderObject::getElementTypeLayout()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getElementTypeLayout();
+}
+
+UInt DebugShaderObject::getEntryPointCount()
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getEntryPointCount();
+}
+
+Result DebugShaderObject::getEntryPoint(UInt index, IShaderObject** entryPoint)
+{
+ SLANG_GFX_API_FUNC;
+ if (m_entryPoints.getCount() == 0)
+ {
+ for (UInt i = 0; i < getEntryPointCount(); i++)
+ {
+ RefPtr<DebugShaderObject> entryPointObj = new DebugShaderObject();
+ SLANG_RETURN_ON_FAIL(
+ baseObject->getEntryPoint(i, entryPointObj->baseObject.writeRef()));
+ m_entryPoints.add(entryPointObj);
+ }
+ }
+ if (index > (UInt)m_entryPoints.getCount())
+ {
+ GFX_DIAGNOSE_ERROR("`index` must not exceed `entryPointCount`.");
+ return SLANG_FAIL;
+ }
+ returnComPtr(entryPoint, m_entryPoints[index]);
+ return SLANG_OK;
+}
+
+Result DebugShaderObject::setData(ShaderOffset const& offset, void const* data, size_t size)
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->setData(offset, data, size);
+}
+
+Result DebugShaderObject::getObject(ShaderOffset const& offset, IShaderObject** object)
+{
+ SLANG_GFX_API_FUNC;
+
+ ComPtr<IShaderObject> innerObject;
+ auto resultCode = baseObject->getObject(offset, innerObject.writeRef());
+ SLANG_RETURN_ON_FAIL(resultCode);
+ RefPtr<DebugShaderObject> debugShaderObject;
+ if (m_objects.TryGetValue(ShaderOffsetKey{offset}, debugShaderObject))
+ {
+ if (debugShaderObject->baseObject == innerObject)
+ {
+ returnComPtr(object, debugShaderObject);
+ return resultCode;
+ }
+ }
+ debugShaderObject = new DebugShaderObject();
+ debugShaderObject->baseObject = innerObject;
+ m_objects[ShaderOffsetKey{offset}] = debugShaderObject;
+ returnComPtr(object, debugShaderObject);
+ return resultCode;
+}
+
+Result DebugShaderObject::setObject(ShaderOffset const& offset, IShaderObject* object)
+{
+ SLANG_GFX_API_FUNC;
+ auto objectImpl = static_cast<DebugShaderObject*>(object);
+ m_objects[ShaderOffsetKey{offset}] = objectImpl;
+ return baseObject->setObject(offset, objectImpl->baseObject.get());
+}
+
+Result DebugShaderObject::setResource(ShaderOffset const& offset, IResourceView* resourceView)
+{
+ SLANG_GFX_API_FUNC;
+ auto viewImpl = static_cast<DebugResourceView*>(resourceView);
+ m_resources[ShaderOffsetKey{offset}] = viewImpl;
+ return baseObject->setResource(offset, viewImpl->baseObject.get());
+}
+
+Result DebugShaderObject::setSampler(ShaderOffset const& offset, ISamplerState* sampler)
+{
+ SLANG_GFX_API_FUNC;
+ auto samplerImpl = static_cast<DebugSamplerState*>(sampler);
+ m_samplers[ShaderOffsetKey{offset}] = samplerImpl;
+ return baseObject->setSampler(offset, samplerImpl->baseObject.get());
+}
+
+Result DebugShaderObject::setCombinedTextureSampler(
+ ShaderOffset const& offset,
+ IResourceView* textureView,
+ ISamplerState* sampler)
+{
+ SLANG_GFX_API_FUNC;
+ auto samplerImpl = static_cast<DebugSamplerState*>(sampler);
+ m_samplers[ShaderOffsetKey{offset}] = samplerImpl;
+ auto viewImpl = static_cast<DebugResourceView*>(textureView);
+ m_resources[ShaderOffsetKey{offset}] = viewImpl;
+ return baseObject->setCombinedTextureSampler(
+ offset, viewImpl->baseObject.get(), samplerImpl->baseObject.get());
+}
+
+DebugObjectBase::DebugObjectBase()
+{
+ static uint64_t uidCounter = 0;
+ uid = ++uidCounter;
+}
+
+} // namespace gfx
diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h
new file mode 100644
index 000000000..12540c31a
--- /dev/null
+++ b/tools/gfx/debug-layer.h
@@ -0,0 +1,419 @@
+#pragma once
+
+#include "slang-gfx.h"
+#include "slang-com-ptr.h"
+#include "core/slang-com-object.h"
+
+namespace gfx
+{
+
+class DebugObjectBase : public Slang::ComObject
+{
+public:
+ uint64_t uid;
+ DebugObjectBase();
+};
+
+template<typename TInterface>
+class DebugObject
+ : public TInterface
+ , public DebugObjectBase
+{
+public:
+ Slang::ComPtr<TInterface> baseObject;
+};
+
+class DebugDevice : public DebugObject<IDevice>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ DebugDevice();
+ IDevice* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature(const char* feature) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ getFeatures(const char** outFeatures, UInt bufferSize, UInt* outFeatureCount) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ getSlangSession(slang::ISession** outSlangSession) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createTransientResourceHeap(
+ const ITransientResourceHeap::Desc& desc,
+ ITransientResourceHeap** outHeap) 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& desc,
+ const void* initData,
+ IBufferResource** outResource) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView(
+ ITextureResource* texture,
+ IResourceView::Desc const& desc,
+ IResourceView** outView) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView(
+ IBufferResource* buffer,
+ IResourceView::Desc const& desc,
+ IResourceView** outView) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout(
+ IFramebufferLayout::Desc const& desc,
+ IFramebufferLayout** outFrameBuffer) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createRenderPassLayout(
+ const IRenderPassLayout::Desc& desc,
+ IRenderPassLayout** outRenderPassLayout) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain(
+ ISwapchain::Desc const& desc,
+ WindowHandle window,
+ ISwapchain** outSwapchain) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout(
+ const InputElementDesc* inputElements,
+ UInt inputElementCount,
+ IInputLayout** outLayout) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createShaderObject(slang::TypeReflection* type, 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(
+ const GraphicsPipelineStateDesc& desc,
+ IPipelineState** outState) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState(
+ const ComputePipelineStateDesc& desc,
+ IPipelineState** outState) override;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource(
+ ITextureResource* resource,
+ ResourceState state,
+ ISlangBlob** outBlob,
+ size_t* outRowPitch,
+ size_t* outPixelSize) override;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL readBufferResource(
+ IBufferResource* buffer,
+ size_t offset,
+ size_t size,
+ ISlangBlob** outBlob) override;
+ virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const override;
+};
+
+class DebugBufferResource : public DebugObject<IBufferResource>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IBufferResource* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW Type SLANG_MCALL getType() override;
+ virtual SLANG_NO_THROW Desc* SLANG_MCALL getDesc() override;
+};
+
+class DebugTextureResource : public DebugObject<ITextureResource>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ ITextureResource* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW Type SLANG_MCALL getType() override;
+ virtual SLANG_NO_THROW Desc* SLANG_MCALL getDesc() override;
+};
+
+class DebugResourceView : public DebugObject<IResourceView>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IResourceView* getInterface(const Slang::Guid& guid);
+};
+
+class DebugSamplerState : public DebugObject<ISamplerState>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ ISamplerState* getInterface(const Slang::Guid& guid);
+};
+
+class DebugShaderObject : public DebugObject<IShaderObject>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IShaderObject* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getElementTypeLayout() override;
+ virtual SLANG_NO_THROW UInt SLANG_MCALL getEntryPointCount() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ getEntryPoint(UInt index, IShaderObject** entryPoint) 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
+ getObject(ShaderOffset const& offset, IShaderObject** object) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ setObject(ShaderOffset const& offset, IShaderObject* object) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ setResource(ShaderOffset const& offset, IResourceView* resourceView) 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;
+
+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::List<Slang::RefPtr<DebugShaderObject>> m_entryPoints;
+ Slang::Dictionary<ShaderOffsetKey, Slang::RefPtr<DebugShaderObject>> m_objects;
+ Slang::Dictionary<ShaderOffsetKey, Slang::RefPtr<DebugResourceView>> m_resources;
+ Slang::Dictionary<ShaderOffsetKey, Slang::RefPtr<DebugSamplerState>> m_samplers;
+};
+
+class DebugRootShaderObject : public DebugShaderObject
+{
+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; }
+};
+
+class DebugCommandBuffer;
+
+class DebugComputeCommandEncoder : public DebugObject<IComputeCommandEncoder>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_QUERY_INTERFACE;
+
+public:
+ IComputeCommandEncoder* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL dispatchCompute(int x, int y, int z) override;
+
+public:
+ DebugCommandBuffer* commandBuffer;
+ bool isOpen = false;
+};
+
+class DebugRenderCommandEncoder : public DebugObject<IRenderCommandEncoder>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_QUERY_INTERFACE;
+
+public:
+ IRenderCommandEncoder* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setViewports(uint32_t count, const Viewport* viewports) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setScissorRects(uint32_t count, const ScissorRect* scissors) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setPrimitiveTopology(PrimitiveTopology topology) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL setVertexBuffers(
+ UInt startSlot,
+ UInt slotCount,
+ IBufferResource* const* buffers,
+ const UInt* strides,
+ const UInt* offsets) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset = 0) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex = 0) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL setStencilReference(uint32_t referenceValue) override;
+
+public:
+ DebugCommandBuffer* commandBuffer;
+ bool isOpen = false;
+};
+
+class DebugResourceCommandEncoder : public DebugObject<IResourceCommandEncoder>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_QUERY_INTERFACE;
+
+public:
+ IResourceCommandEncoder* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
+
+ virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() override;
+ virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer(
+ IBufferResource* dst,
+ size_t dstOffset,
+ IBufferResource* src,
+ size_t srcOffset,
+ size_t size) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ uploadBufferData(IBufferResource* dst, size_t offset, size_t size, void* data) override;
+
+public:
+ DebugCommandBuffer* commandBuffer;
+ bool isOpen = false;
+};
+
+class DebugCommandBuffer : public DebugObject<ICommandBuffer>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+private:
+ DebugRenderCommandEncoder m_renderCommandEncoder;
+ DebugComputeCommandEncoder m_computeCommandEncoder;
+ DebugResourceCommandEncoder m_resourceCommandEncoder;
+
+public:
+ DebugCommandBuffer();
+ ICommandBuffer* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW void SLANG_MCALL encodeRenderCommands(
+ IRenderPassLayout* renderPass,
+ IFramebuffer* framebuffer,
+ IRenderCommandEncoder** outEncoder) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ encodeComputeCommands(IComputeCommandEncoder** outEncoder) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ encodeResourceCommands(IResourceCommandEncoder** outEncoder) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL close() override;
+
+private:
+ void checkEncodersClosedBeforeNewEncoder();
+ void checkCommandBufferOpenWhenCreatingEncoder();
+public:
+ DebugRootShaderObject rootObject;
+ bool isOpen = true;
+};
+
+class DebugCommandQueue : public DebugObject<ICommandQueue>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ ICommandQueue* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override;
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ executeCommandBuffers(uint32_t count, ICommandBuffer* const* commandBuffers) override;
+ virtual SLANG_NO_THROW void SLANG_MCALL wait() override;
+};
+
+class DebugFramebuffer
+ : public DebugObject<IFramebuffer>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IFramebuffer* getInterface(const Slang::Guid& guid);
+};
+
+class DebugFramebufferLayout : public DebugObject<IFramebufferLayout>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IFramebufferLayout* getInterface(const Slang::Guid& guid);
+};
+
+class DebugInputLayout : public DebugObject<IInputLayout>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IInputLayout* getInterface(const Slang::Guid& guid);
+};
+
+class DebugPipelineState : public DebugObject<IPipelineState>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IPipelineState* getInterface(const Slang::Guid& guid);
+};
+
+class DebugRenderPassLayout : public DebugObject<IRenderPassLayout>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IRenderPassLayout* getInterface(const Slang::Guid& guid);
+};
+
+class DebugShaderProgram : public DebugObject<IShaderProgram>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ IShaderProgram* getInterface(const Slang::Guid& guid);
+
+};
+
+class DebugTransientResourceHeap : public DebugObject<ITransientResourceHeap>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ ITransientResourceHeap* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW Result SLANG_MCALL synchronizeAndReset() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ createCommandBuffer(ICommandBuffer** outCommandBuffer) override;
+};
+
+class DebugSwapchain : public DebugObject<ISwapchain>
+{
+public:
+ SLANG_COM_OBJECT_IUNKNOWN_ALL;
+
+public:
+ ISwapchain* getInterface(const Slang::Guid& guid);
+ virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL
+ getImage(uint32_t index, ITextureResource** outResource) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL present() override;
+ virtual SLANG_NO_THROW int SLANG_MCALL acquireNextImage() override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL resize(uint32_t width, uint32_t height) override;
+
+public:
+ Slang::RefPtr<DebugCommandQueue> queue;
+ Desc desc;
+
+private:
+ Slang::List<Slang::RefPtr<DebugTextureResource>> m_images;
+ void maybeRebuildImageList();
+};
+
+}
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp
index d5735add5..3ef3c1aa1 100644
--- a/tools/gfx/open-gl/render-gl.cpp
+++ b/tools/gfx/open-gl/render-gl.cpp
@@ -1789,17 +1789,16 @@ SlangResult SLANG_MCALL createGLDevice(const IDevice::Desc* desc, IDevice** outR
void GLDevice::debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message)
{
- ::OutputDebugStringA("GL: ");
- ::OutputDebugStringA(message);
- ::OutputDebugStringA("\n");
-
- switch (type)
+ DebugMessageType msgType = DebugMessageType::Info;
+ switch(type)
{
- case GL_DEBUG_TYPE_ERROR:
- break;
- default:
- break;
+ case GL_DEBUG_TYPE_ERROR:
+ msgType = DebugMessageType::Error;
+ break;
+ default:
+ break;
}
+ getDebugCallback()->handleMessage(msgType, DebugMessageSource::Driver, message);
}
/* static */void APIENTRY GLDevice::staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
@@ -2862,7 +2861,16 @@ Result GLDevice::createProgram(const IShaderProgram::Desc& desc, IShaderProgram*
{
ComPtr<ISlangBlob> kernelCode;
ComPtr<ISlangBlob> diagnostics;
- SLANG_RETURN_ON_FAIL(desc.slangProgram->getEntryPointCode(i, 0, kernelCode.writeRef(), diagnostics.writeRef()));
+ auto compileResult = desc.slangProgram->getEntryPointCode(
+ i, 0, kernelCode.writeRef(), diagnostics.writeRef());
+ if (diagnostics)
+ {
+ getDebugCallback()->handleMessage(
+ compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
+ DebugMessageSource::Slang,
+ (char*)diagnostics->getBufferPointer());
+ }
+ SLANG_RETURN_ON_FAIL(compileResult);
GLenum glShaderType = 0;
auto stage = programLayout->getEntryPointByIndex(i)->getStage();
switch (stage)
diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp
index 81fa73f22..d14ce904a 100644
--- a/tools/gfx/render.cpp
+++ b/tools/gfx/render.cpp
@@ -8,12 +8,14 @@
#include "vulkan/render-vk.h"
#include "cuda/render-cuda.h"
#include "cpu/render-cpu.h"
+#include "debug-layer.h"
+
#include <cstring>
namespace gfx {
using namespace Slang;
-static const IResource::DescBase s_emptyDescBase = {};
+static bool debugLayerEnabled = false;
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Global Renderer Functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
@@ -47,8 +49,7 @@ extern "C"
return s_formatSize[int(format)];
}
- SLANG_GFX_API SlangResult SLANG_MCALL
- gfxCreateDevice(const IDevice::Desc* desc, IDevice** outDevice)
+ SlangResult _createDevice(const IDevice::Desc* desc, IDevice** outDevice)
{
switch (desc->deviceType)
{
@@ -77,16 +78,16 @@ extern "C"
{
IDevice::Desc newDesc = *desc;
newDesc.deviceType = DeviceType::DirectX12;
- if (gfxCreateDevice(&newDesc, outDevice) == SLANG_OK)
+ if (_createDevice(&newDesc, outDevice) == SLANG_OK)
return SLANG_OK;
newDesc.deviceType = DeviceType::Vulkan;
- if (gfxCreateDevice(&newDesc, outDevice) == SLANG_OK)
+ if (_createDevice(&newDesc, outDevice) == SLANG_OK)
return SLANG_OK;
newDesc.deviceType = DeviceType::DirectX11;
- if (gfxCreateDevice(&newDesc, outDevice) == SLANG_OK)
+ if (_createDevice(&newDesc, outDevice) == SLANG_OK)
return SLANG_OK;
newDesc.deviceType = DeviceType::OpenGl;
- if (gfxCreateDevice(&newDesc, outDevice) == SLANG_OK)
+ if (_createDevice(&newDesc, outDevice) == SLANG_OK)
return SLANG_OK;
return SLANG_FAIL;
}
@@ -113,6 +114,35 @@ extern "C"
}
}
+ SLANG_GFX_API SlangResult SLANG_MCALL
+ gfxCreateDevice(const IDevice::Desc* desc, IDevice** outDevice)
+ {
+ ComPtr<IDevice> innerDevice;
+ auto resultCode = _createDevice(desc, innerDevice.writeRef());
+ if (SLANG_FAILED(resultCode))
+ return resultCode;
+ if (!debugLayerEnabled)
+ {
+ returnComPtr(outDevice, innerDevice);
+ return resultCode;
+ }
+ RefPtr<DebugDevice> debugDevice = new DebugDevice();
+ debugDevice->baseObject = innerDevice;
+ returnComPtr(outDevice, debugDevice);
+ return resultCode;
+ }
+
+ SLANG_GFX_API SlangResult SLANG_MCALL gfxSetDebugCallback(IDebugCallback* callback)
+ {
+ _getDebugCallback() = callback;
+ return SLANG_OK;
+ }
+
+ SLANG_GFX_API void SLANG_MCALL gfxEnableDebugLayer()
+ {
+ debugLayerEnabled = true;
+ }
+
const char* SLANG_MCALL gfxGetDeviceTypeName(DeviceType type)
{
switch (type)
diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp
index 2a12b777c..99af6e4ff 100644
--- a/tools/gfx/renderer-shared.cpp
+++ b/tools/gfx/renderer-shared.cpp
@@ -21,7 +21,7 @@ const Slang::Guid GfxGUID::IID_ISamplerState = SLANG_UUID_ISamplerState;
const Slang::Guid GfxGUID::IID_IResource = SLANG_UUID_IResource;
const Slang::Guid GfxGUID::IID_IBufferResource = SLANG_UUID_IBufferResource;
const Slang::Guid GfxGUID::IID_ITextureResource = SLANG_UUID_ITextureResource;
-const Slang::Guid GfxGUID::IID_IRenderer = SLANG_UUID_IRenderer;
+const Slang::Guid GfxGUID::IID_IDevice = SLANG_UUID_IDevice;
const Slang::Guid GfxGUID::IID_IShaderObject = SLANG_UUID_IShaderObject;
const Slang::Guid GfxGUID::IID_IRenderPassLayout = SLANG_UUID_IRenderPassLayout;
@@ -223,7 +223,7 @@ void PipelineStateBase::initializeBase(const PipelineStateDesc& inDesc)
IDevice* gfx::RendererBase::getInterface(const Guid& guid)
{
- return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IRenderer)
+ return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IDevice)
? static_cast<IDevice*>(this)
: nullptr;
}
@@ -447,5 +447,28 @@ Result RendererBase::maybeSpecializePipeline(
return SLANG_OK;
}
+IDebugCallback*& _getDebugCallback()
+{
+ static IDebugCallback* callback = nullptr;
+ return callback;
+}
+
+class NullDebugCallback : public IDebugCallback
+{
+public:
+ virtual SLANG_NO_THROW void SLANG_MCALL
+ handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override
+ {
+ SLANG_UNUSED(type);
+ SLANG_UNUSED(source);
+ SLANG_UNUSED(message);
+ }
+};
+IDebugCallback* _getNullDebugCallback()
+{
+ static NullDebugCallback result = {};
+ return &result;
+}
} // namespace gfx
+
diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h
index ed045c617..9aedc8c74 100644
--- a/tools/gfx/renderer-shared.h
+++ b/tools/gfx/renderer-shared.h
@@ -25,7 +25,7 @@ struct GfxGUID
static const Slang::Guid IID_IBufferResource;
static const Slang::Guid IID_ITextureResource;
static const Slang::Guid IID_IInputLayout;
- static const Slang::Guid IID_IRenderer;
+ static const Slang::Guid IID_IDevice;
static const Slang::Guid IID_IShaderObjectLayout;
static const Slang::Guid IID_IShaderObject;
static const Slang::Guid IID_IRenderPassLayout;
@@ -606,4 +606,18 @@ public:
Slang::Dictionary<slang::TypeReflection*, Slang::RefPtr<ShaderObjectLayoutBase>> m_shaderObjectLayoutCache;
};
+IDebugCallback*& _getDebugCallback();
+IDebugCallback* _getNullDebugCallback();
+inline IDebugCallback* getDebugCallback()
+{
+ auto rs = _getDebugCallback();
+ if (rs)
+ {
+ return rs;
+ }
+ else
+ {
+ return _getNullDebugCallback();
+ }
+}
}
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 55d0f2ee6..b3f99ff59 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -3983,11 +3983,19 @@ VKDevice::~VKDevice()
VkBool32 VKDevice::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg)
{
+ DebugMessageType msgType = DebugMessageType::Info;
+
char const* severity = "message";
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
+ {
severity = "warning";
+ msgType = DebugMessageType::Warning;
+ }
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
+ {
severity = "error";
+ msgType = DebugMessageType::Error;
+ }
// pMsg can be really big (it can be assembler dump for example)
// Use a dynamic buffer to store
@@ -4004,11 +4012,7 @@ VkBool32 VKDevice::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReport
msgCode,
pMsg);
- fprintf(stderr, "%s", buffer);
- fflush(stderr);
-#ifdef _WIN32
- OutputDebugStringA(buffer);
-#endif
+ getDebugCallback()->handleMessage(msgType, DebugMessageSource::Driver, buffer);
return VK_FALSE;
}
@@ -5512,7 +5516,10 @@ Result VKDevice::createProgram(const IShaderProgram::Desc& desc, IShaderProgram*
(SlangInt)i, 0, kernelCode.writeRef(), diagnostics.writeRef());
if (diagnostics)
{
- // TODO: report compile error.
+ getDebugCallback()->handleMessage(
+ compileResult == SLANG_OK ? DebugMessageType::Warning : DebugMessageType::Error,
+ DebugMessageSource::Slang,
+ (char*)diagnostics->getBufferPointer());
}
SLANG_RETURN_ON_FAIL(compileResult);
shaderProgram->m_codeBlobs.add(kernelCode);
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index d3c0ef1a9..c6f775312 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -1008,6 +1008,10 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
}
}
+#ifdef _DEBUG
+ gfxEnableDebugLayer();
+#endif
+
// Use the profile name set on options if set
input.profile = options.profileName ? options.profileName : input.profile;