diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gfx/cpu/render-cpu.cpp | 12 | ||||
| -rw-r--r-- | tools/gfx/cuda/render-cuda.cpp | 5 | ||||
| -rw-r--r-- | tools/gfx/d3d11/render-d3d11.cpp | 5 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 7 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.cpp | 948 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.h | 419 | ||||
| -rw-r--r-- | tools/gfx/open-gl/render-gl.cpp | 28 | ||||
| -rw-r--r-- | tools/gfx/render.cpp | 44 | ||||
| -rw-r--r-- | tools/gfx/renderer-shared.cpp | 27 | ||||
| -rw-r--r-- | tools/gfx/renderer-shared.h | 16 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 19 | ||||
| -rw-r--r-- | tools/render-test/render-test-main.cpp | 4 |
12 files changed, 1502 insertions, 32 deletions
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; |
