summaryrefslogtreecommitdiffstats
path: root/tools/gfx/debug-layer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gfx/debug-layer.cpp')
-rw-r--r--tools/gfx/debug-layer.cpp948
1 files changed, 948 insertions, 0 deletions
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