diff options
| author | Gangzheng Tong <tonggangzheng@gmail.com> | 2025-07-08 23:44:56 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-09 06:44:56 +0000 |
| commit | 43d0c2100ef1a5df4b54525e50eb29fe7c39ec16 (patch) | |
| tree | 25ec4fb9c726115f90bdaa9878f2f4ca372ad0a6 /examples | |
| parent | 00746bf09047cdf01c19dac513a532bcf3ed3ea3 (diff) | |
Convert gfx unit tests and examples to use slang-rhi (#7577)
* Port first gfx unit test to slang-rhi
* port triangle example to use slang-rhi
* port platform-test to slang-rhi
* Update platform-test to throttle mouse move events
* port gpu-printing example to use slang-rhi
* port model-viewer example to use slang-rhi
* port ray-tracing example to use slang-rhi
* port ray-tracing pipeline example to use slang-rhi
* port reflection parameter blocks example to use slang-rhi
* port shader-object example to use slang-rhi
* port shader-toy example to use slang-rhi
* Port most of tests to slang-rhi
* port link-time-constant-array-size to use slang-rhi
* Fix tests and find matching tests in slang-rhi
* port autodiff-texture
* remove gfx target; port nv-aftermath-example
* update include path for shader-cursor.h
* Disabled 2 more ported tests
* fix build error
* remove gfx test
* put slang-rhi (static-lib) before slang (shared)
* format code (#7621)
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
* add debug callback
* format code (#7649)
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
* Address review comments; revert back to use SLANG_CHECK_MSG
---------
Co-authored-by: slangbot <ellieh+slangbot@nvidia.com>
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | examples/autodiff-texture/main.cpp | 662 | ||||
| -rw-r--r-- | examples/example-base/example-base.cpp | 255 | ||||
| -rw-r--r-- | examples/example-base/example-base.h | 36 | ||||
| -rw-r--r-- | examples/gpu-printing/main.cpp | 84 | ||||
| -rw-r--r-- | examples/hello-world/main.cpp | 1 | ||||
| -rw-r--r-- | examples/model-viewer/main.cpp | 117 | ||||
| -rw-r--r-- | examples/nv-aftermath-example/main.cpp | 248 | ||||
| -rw-r--r-- | examples/platform-test/main.cpp | 115 | ||||
| -rw-r--r-- | examples/ray-tracing-pipeline/main.cpp | 425 | ||||
| -rw-r--r-- | examples/ray-tracing/main.cpp | 421 | ||||
| -rw-r--r-- | examples/reflection-parameter-blocks/main.cpp | 44 | ||||
| -rw-r--r-- | examples/shader-object/main.cpp | 123 | ||||
| -rw-r--r-- | examples/shader-toy/main.cpp | 106 | ||||
| -rw-r--r-- | examples/triangle/main.cpp | 104 |
15 files changed, 1270 insertions, 1477 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 87b0b39f8..e67e56ea5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -55,12 +55,12 @@ function(example dir) LINK_WITH_PRIVATE core example-base + slang-rhi slang - gfx - gfx-util platform $<$<BOOL:${SLANG_ENABLE_CUDA}>:CUDA::cuda_driver> ${main_wrapper_libraries} + INCLUDE_DIRECTORIES_PUBLIC ${slang_SOURCE_DIR} EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EXAMPLE_NAME=${dir} $<$<BOOL:${SLANG_ENABLE_XLIB}>:SLANG_ENABLE_XLIB> @@ -81,8 +81,8 @@ if(SLANG_ENABLE_EXAMPLES) STATIC LINK_WITH_PRIVATE core + slang-rhi slang - gfx platform stb $<$<BOOL:${SLANG_ENABLE_CUDA}>:CUDA::cuda_driver> diff --git a/examples/autodiff-texture/main.cpp b/examples/autodiff-texture/main.cpp index d99f9f341..951d7f0ad 100644 --- a/examples/autodiff-texture/main.cpp +++ b/examples/autodiff-texture/main.cpp @@ -1,13 +1,13 @@ #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/vector-math.h" #include "platform/window.h" #include "slang-com-ptr.h" -#include "slang-gfx.h" +#include "slang-rhi.h" +#include "slang-rhi/shader-cursor.h" #include "slang.h" -using namespace gfx; +using namespace rhi; using namespace Slang; static const ExampleResources resourceBase("autodiff-texture"); @@ -24,6 +24,8 @@ static const Vertex kVertexData[kVertexCount] = { {{1, 0, 0}}, {{1, 1, 0}}, }; +float clearValue[] = {0.0f, 0.0f, 0.0f, 0.0f}; + struct AutoDiffTexture : public WindowedAppBase { @@ -40,11 +42,11 @@ struct AutoDiffTexture : public WindowedAppBase } } - gfx::Result loadRenderProgram( - gfx::IDevice* device, + Result loadRenderProgram( + IDevice* device, const char* fileName, const char* fragmentShader, - gfx::IShaderProgram** outProgram) + IShaderProgram** outProgram) { ComPtr<slang::ISession> slangSession; slangSession = device->getSlangSession(); @@ -87,17 +89,14 @@ struct AutoDiffTexture : public WindowedAppBase printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); } - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(device->createShaderProgram(programDesc, outProgram)); return SLANG_OK; } - gfx::Result loadComputeProgram( - gfx::IDevice* device, - const char* fileName, - gfx::IShaderProgram** outProgram) + Result loadComputeProgram(IDevice* device, const char* fileName, IShaderProgram** outProgram) { ComPtr<slang::ISession> slangSession; slangSession = device->getSlangSession(); @@ -131,161 +130,131 @@ struct AutoDiffTexture : public WindowedAppBase printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); } - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(device->createShaderProgram(programDesc, outProgram)); return SLANG_OK; } - ComPtr<gfx::IPipelineState> gRefPipelineState; - ComPtr<gfx::IPipelineState> gIterPipelineState; - ComPtr<gfx::IPipelineState> gReconstructPipelineState; - ComPtr<gfx::IPipelineState> gConvertPipelineState; - ComPtr<gfx::IPipelineState> gBuildMipPipelineState; - ComPtr<gfx::IPipelineState> gLearnMipPipelineState; - ComPtr<gfx::IPipelineState> gDrawQuadPipelineState; + ComPtr<IRenderPipeline> gRefPipeline; + ComPtr<IRenderPipeline> gIterPipeline; + ComPtr<IComputePipeline> gReconstructPipeline; + ComPtr<IComputePipeline> gConvertPipeline; + ComPtr<IComputePipeline> gBuildMipPipeline; + ComPtr<IComputePipeline> gLearnMipPipeline; + ComPtr<IRenderPipeline> gDrawQuadPipeline; - ComPtr<gfx::ITextureResource> gLearningTexture; - ComPtr<gfx::IResourceView> gLearningTextureSRV; - List<ComPtr<gfx::IResourceView>> gLearningTextureUAVs; + ComPtr<ITexture> gLearningTexture; + ComPtr<ITextureView> gLearningTextureSRV; + List<ComPtr<ITextureView>> gLearningTextureUAVs; - ComPtr<gfx::ITextureResource> gDiffTexture; - ComPtr<gfx::IResourceView> gDiffTextureSRV; - List<ComPtr<gfx::IResourceView>> gDiffTextureUAVs; + ComPtr<ITexture> gDiffTexture; + ComPtr<ITextureView> gDiffTextureSRV; + List<ComPtr<ITextureView>> gDiffTextureUAVs; - ComPtr<gfx::IBufferResource> gVertexBuffer; - ComPtr<gfx::IResourceView> gTexView; - ComPtr<gfx::ISamplerState> gSampler; - ComPtr<gfx::IFramebuffer> gRefFrameBuffer; - ComPtr<gfx::IFramebuffer> gIterFrameBuffer; + ComPtr<IBuffer> gVertexBuffer; + ComPtr<ITextureView> gTexView; + ComPtr<ISampler> gSampler; - ComPtr<gfx::ITextureResource> gDepthTexture; - ComPtr<gfx::IResourceView> gDepthTextureView; + ComPtr<ITexture> gDepthTexture; + ComPtr<ITextureView> gDepthTextureView; - ComPtr<gfx::IResourceView> gIterImageDSV; + ComPtr<ITexture> gIterImage; + ComPtr<ITextureView> gIterImageSRV; - ComPtr<gfx::ITextureResource> gIterImage; - ComPtr<gfx::IResourceView> gIterImageSRV; - ComPtr<gfx::IResourceView> gIterImageRTV; + ComPtr<ITexture> gRefImage; + ComPtr<ITextureView> gRefImageSRV; - ComPtr<gfx::ITextureResource> gRefImage; - ComPtr<gfx::IResourceView> gRefImageSRV; - ComPtr<gfx::IResourceView> gRefImageRTV; + ComPtr<IBuffer> gAccumulateBuffer; + ComPtr<ITextureView> gAccumulateBufferView; + + ComPtr<IBuffer> gReconstructBuffer; + ComPtr<ITextureView> gReconstructBufferView; - ComPtr<gfx::IBufferResource> gAccumulateBuffer; - ComPtr<gfx::IBufferResource> gReconstructBuffer; - ComPtr<gfx::IResourceView> gAccumulateBufferView; - ComPtr<gfx::IResourceView> gReconstructBufferView; - ClearValue kClearValue; bool resetLearntTexture = false; - ComPtr<gfx::ITextureResource> createRenderTargetTexture( - gfx::Format format, - int w, - int h, - int levels) + ComPtr<ITexture> createRenderTargetTexture(Format format, int w, int h, int levels) { - gfx::ITextureResource::Desc textureDesc = {}; - textureDesc.allowedStates.add(ResourceState::ShaderResource); - textureDesc.allowedStates.add(ResourceState::UnorderedAccess); - textureDesc.allowedStates.add(ResourceState::RenderTarget); - textureDesc.defaultState = ResourceState::RenderTarget; + TextureDesc textureDesc = {}; textureDesc.format = format; - textureDesc.numMipLevels = levels; - textureDesc.type = gfx::IResource::Type::Texture2D; textureDesc.size.width = w; textureDesc.size.height = h; textureDesc.size.depth = 1; - textureDesc.optimalClearValue = &kClearValue; - return gDevice->createTextureResource(textureDesc, nullptr); + textureDesc.mipCount = levels; + textureDesc.usage = TextureUsage::ShaderResource | TextureUsage::UnorderedAccess | + TextureUsage::RenderTarget; + textureDesc.defaultState = ResourceState::RenderTarget; + return gDevice->createTexture(textureDesc); } - ComPtr<gfx::ITextureResource> createDepthTexture() + ComPtr<ITexture> createDepthTexture() { - gfx::ITextureResource::Desc textureDesc = {}; - textureDesc.allowedStates.add(ResourceState::DepthWrite); - textureDesc.defaultState = ResourceState::DepthWrite; - textureDesc.format = gfx::Format::D32_FLOAT; - textureDesc.numMipLevels = 1; - textureDesc.type = gfx::IResource::Type::Texture2D; + TextureDesc textureDesc = {}; + textureDesc.format = Format::D32Float; textureDesc.size.width = windowWidth; textureDesc.size.height = windowHeight; textureDesc.size.depth = 1; - ClearValue clearValue = {}; - textureDesc.optimalClearValue = &clearValue; - return gDevice->createTextureResource(textureDesc, nullptr); - } - ComPtr<gfx::IFramebuffer> createRenderTargetFramebuffer(IResourceView* tex) - { - IFramebuffer::Desc desc = {}; - desc.layout = gFramebufferLayout.get(); - desc.renderTargetCount = 1; - desc.renderTargetViews = &tex; - desc.depthStencilView = gDepthTextureView; - return gDevice->createFramebuffer(desc); + textureDesc.mipCount = 1; + textureDesc.usage = TextureUsage::DepthStencil; + textureDesc.defaultState = ResourceState::DepthWrite; + return gDevice->createTexture(textureDesc); } - ComPtr<gfx::IResourceView> createRTV(ITextureResource* tex, Format f) + ComPtr<ITextureView> createRTV(ITexture* tex, Format f) { - IResourceView::Desc rtvDesc = {}; - rtvDesc.type = IResourceView::Type::RenderTarget; - rtvDesc.subresourceRange.mipLevelCount = 1; + TextureViewDesc rtvDesc = {}; rtvDesc.format = f; - rtvDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + rtvDesc.subresourceRange.mipCount = 1; return gDevice->createTextureView(tex, rtvDesc); } - ComPtr<gfx::IResourceView> createDSV(ITextureResource* tex) + ComPtr<ITextureView> createDSV(ITexture* tex) { - IResourceView::Desc dsvDesc = {}; - dsvDesc.type = IResourceView::Type::DepthStencil; - dsvDesc.subresourceRange.mipLevelCount = 1; - dsvDesc.format = Format::D32_FLOAT; - dsvDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + TextureViewDesc dsvDesc = {}; + dsvDesc.format = Format::D32Float; + dsvDesc.subresourceRange.mipCount = 1; return gDevice->createTextureView(tex, dsvDesc); } - ComPtr<gfx::IResourceView> createSRV(ITextureResource* tex) + ComPtr<ITextureView> createSRV(ITexture* tex) { - IResourceView::Desc rtvDesc = {}; - rtvDesc.type = IResourceView::Type::ShaderResource; - return gDevice->createTextureView(tex, rtvDesc); + TextureViewDesc srvDesc = {}; + return gDevice->createTextureView(tex, srvDesc); } - ComPtr<gfx::IPipelineState> createRenderPipelineState( - IInputLayout* inputLayout, - IShaderProgram* program) + ComPtr<IRenderPipeline> createRenderPipeline(IInputLayout* inputLayout, IShaderProgram* program) { - GraphicsPipelineStateDesc desc; + ColorTargetDesc colorTarget; + colorTarget.format = Format::RGBA8Unorm; + RenderPipelineDesc desc; desc.inputLayout = inputLayout; desc.program = program; - desc.rasterizer.cullMode = gfx::CullMode::None; - desc.framebufferLayout = gFramebufferLayout; - auto pipelineState = gDevice->createGraphicsPipelineState(desc); - return pipelineState; + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = true; + desc.depthStencil.depthWriteEnable = true; + desc.depthStencil.format = Format::D32Float; + desc.rasterizer.cullMode = CullMode::None; + desc.primitiveTopology = PrimitiveTopology::TriangleStrip; + return gDevice->createRenderPipeline(desc); } - ComPtr<gfx::IPipelineState> createComputePipelineState(IShaderProgram* program) + ComPtr<IComputePipeline> createComputePipeline(IShaderProgram* program) { - ComputePipelineStateDesc desc = {}; + ComputePipelineDesc desc = {}; desc.program = program; - auto pipelineState = gDevice->createComputePipelineState(desc); - return pipelineState; - } - ComPtr<gfx::IResourceView> createUAV(IBufferResource* buffer) - { - IResourceView::Desc desc = {}; - desc.type = IResourceView::Type::UnorderedAccess; - return gDevice->createBufferView(buffer, nullptr, desc); + return gDevice->createComputePipeline(desc); } - ComPtr<gfx::IResourceView> createUAV(ITextureResource* texture, int level) + ComPtr<ITextureView> createUAV(ITexture* texture, int level) { - IResourceView::Desc desc = {}; - desc.type = IResourceView::Type::UnorderedAccess; - desc.subresourceRange.layerCount = 1; - desc.subresourceRange.mipLevel = level; - desc.subresourceRange.baseArrayLayer = 0; + TextureViewDesc desc = {}; + SubresourceRange textureViewRange = {}; + textureViewRange.mipCount = 1; + textureViewRange.mip = level; // Fixed: should be level, not 0 + textureViewRange.layerCount = 1; // Fixed: should be 1, not level + textureViewRange.layer = 0; + desc.subresourceRange = textureViewRange; return gDevice->createTextureView(texture, desc); } Slang::Result initialize() { - SLANG_RETURN_ON_FAIL(initializeBase("autodiff-texture", 1024, 768)); + SLANG_RETURN_ON_FAIL(initializeBase("autodiff-texture", 1024, 768, DeviceType::Default)); srand(20421); if (!isTestMode()) @@ -297,11 +266,6 @@ struct AutoDiffTexture : public WindowedAppBase }; } - kClearValue.color.floatValues[0] = 0.3f; - kClearValue.color.floatValues[1] = 0.5f; - kClearValue.color.floatValues[2] = 0.7f; - kClearValue.color.floatValues[3] = 1.0f; - platform::Rect clientRect{}; if (isTestMode()) { @@ -317,16 +281,16 @@ struct AutoDiffTexture : public WindowedAppBase windowHeight = clientRect.height; InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)}}; + {"POSITION", 0, Format::RGB32Float, offsetof(Vertex, position)}}; auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 1); if (!inputLayout) return SLANG_FAIL; - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + BufferDesc vertexBufferDesc; + vertexBufferDesc.size = kVertexCount * sizeof(Vertex); + vertexBufferDesc.elementSize = sizeof(Vertex); + vertexBufferDesc.usage = BufferUsage::VertexBuffer; + gVertexBuffer = gDevice->createBuffer(vertexBufferDesc, &kVertexData[0]); if (!gVertexBuffer) return SLANG_FAIL; @@ -337,7 +301,7 @@ struct AutoDiffTexture : public WindowedAppBase "train.slang", "fragmentMain", shaderProgram.writeRef())); - gRefPipelineState = createRenderPipelineState(inputLayout, shaderProgram); + gRefPipeline = createRenderPipeline(inputLayout, shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; @@ -346,7 +310,7 @@ struct AutoDiffTexture : public WindowedAppBase "train.slang", "diffFragmentMain", shaderProgram.writeRef())); - gIterPipelineState = createRenderPipelineState(inputLayout, shaderProgram); + gIterPipeline = createRenderPipeline(inputLayout, shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; @@ -355,126 +319,92 @@ struct AutoDiffTexture : public WindowedAppBase "draw-quad.slang", "fragmentMain", shaderProgram.writeRef())); - gDrawQuadPipelineState = createRenderPipelineState(inputLayout, shaderProgram); + gDrawQuadPipeline = createRenderPipeline(inputLayout, shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL( loadComputeProgram(gDevice, "reconstruct.slang", shaderProgram.writeRef())); - gReconstructPipelineState = createComputePipelineState(shaderProgram); + gReconstructPipeline = createComputePipeline(shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL( loadComputeProgram(gDevice, "convert.slang", shaderProgram.writeRef())); - gConvertPipelineState = createComputePipelineState(shaderProgram); + gConvertPipeline = createComputePipeline(shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL( loadComputeProgram(gDevice, "buildmip.slang", shaderProgram.writeRef())); - gBuildMipPipelineState = createComputePipelineState(shaderProgram); + gBuildMipPipeline = createComputePipeline(shaderProgram); } { ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL( loadComputeProgram(gDevice, "learnmip.slang", shaderProgram.writeRef())); - gLearnMipPipelineState = createComputePipelineState(shaderProgram); + gLearnMipPipeline = createComputePipeline(shaderProgram); } + // Load texture from file - this would need to be adapted to use slang-rhi texture loading Slang::String imagePath = resourceBase.resolveResource("checkerboard.jpg"); gTexView = createTextureFromFile(imagePath.getBuffer(), textureWidth, textureHeight); + textureWidth = 512; // Placeholder values + textureHeight = 512; initMipOffsets(textureWidth, textureHeight); - gfx::IBufferResource::Desc bufferDesc = {}; - bufferDesc.allowedStates.add(ResourceState::ShaderResource); - bufferDesc.allowedStates.add(ResourceState::UnorderedAccess); - bufferDesc.allowedStates.add(ResourceState::General); - bufferDesc.sizeInBytes = mipMapOffset.getLast() * sizeof(uint32_t); - bufferDesc.type = IResource::Type::Buffer; - gAccumulateBuffer = gDevice->createBufferResource(bufferDesc); - gReconstructBuffer = gDevice->createBufferResource(bufferDesc); + BufferDesc bufferDesc = {}; + bufferDesc.size = mipMapOffset.getLast() * sizeof(uint32_t); + bufferDesc.usage = BufferUsage::ShaderResource | BufferUsage::UnorderedAccess; - gAccumulateBufferView = createUAV(gAccumulateBuffer); - gReconstructBufferView = createUAV(gReconstructBuffer); + gAccumulateBuffer = gDevice->createBuffer(bufferDesc); + if (!gAccumulateBuffer) + { + printf("ERROR: Failed to create accumulate buffer!\n"); + return SLANG_FAIL; + } + + gReconstructBuffer = gDevice->createBuffer(bufferDesc); + if (!gReconstructBuffer) + { + printf("ERROR: Failed to create reconstruct buffer!\n"); + return SLANG_FAIL; + } int mipCount = 1 + Math::Log2Ceil(Math::Max(textureWidth, textureHeight)); - gLearningTexture = createRenderTargetTexture( - Format::R32G32B32A32_FLOAT, - textureWidth, - textureHeight, - mipCount); + SubresourceData initialData = {}; + initialData.data = gLearningTexture = + createRenderTargetTexture(Format::RGBA32Float, textureWidth, textureHeight, mipCount); gLearningTextureSRV = createSRV(gLearningTexture); for (int i = 0; i < mipCount; i++) gLearningTextureUAVs.add(createUAV(gLearningTexture, i)); - gDiffTexture = createRenderTargetTexture( - Format::R32G32B32A32_FLOAT, - textureWidth, - textureHeight, - mipCount); + gDiffTexture = + createRenderTargetTexture(Format::RGBA32Float, textureWidth, textureHeight, mipCount); gDiffTextureSRV = createSRV(gDiffTexture); for (int i = 0; i < mipCount; i++) gDiffTextureUAVs.add(createUAV(gDiffTexture, i)); - gfx::ISamplerState::Desc samplerDesc = {}; - // samplerDesc.maxLOD = 0.0f; - gSampler = gDevice->createSamplerState(samplerDesc); + SamplerDesc samplerDesc = {}; + gSampler = gDevice->createSampler(samplerDesc); gDepthTexture = createDepthTexture(); gDepthTextureView = createDSV(gDepthTexture); - gRefImage = createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1); - gRefImageRTV = createRTV(gRefImage, Format::R8G8B8A8_UNORM); + gRefImage = createRenderTargetTexture(Format::RGBA8Unorm, windowWidth, windowHeight, 1); gRefImageSRV = createSRV(gRefImage); - gIterImage = - createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1); - gIterImageRTV = createRTV(gIterImage, Format::R8G8B8A8_UNORM); + gIterImage = createRenderTargetTexture(Format::RGBA8Unorm, windowWidth, windowHeight, 1); gIterImageSRV = createSRV(gIterImage); - gRefFrameBuffer = createRenderTargetFramebuffer(gRefImageRTV); - gIterFrameBuffer = createRenderTargetFramebuffer(gIterImageRTV); - + // Initialize textures { - ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeResourceCommands(); - encoder->textureBarrier( - gLearningTexture, - ResourceState::RenderTarget, - ResourceState::UnorderedAccess); - encoder->textureBarrier( - gDiffTexture, - ResourceState::RenderTarget, - ResourceState::UnorderedAccess); - encoder->textureBarrier( - gRefImage, - ResourceState::RenderTarget, - ResourceState::ShaderResource); - encoder->textureBarrier( - gIterImage, - ResourceState::RenderTarget, - ResourceState::ShaderResource); - for (int i = 0; i < gLearningTextureUAVs.getCount(); i++) - { - ClearValue clearValue = {}; - encoder->clearResourceView( - gLearningTextureUAVs[i], - &clearValue, - ClearResourceViewFlags::None); - encoder->clearResourceView( - gDiffTextureUAVs[i], - &clearValue, - ClearResourceViewFlags::None); - } - encoder->textureBarrier( - gLearningTexture, - ResourceState::UnorderedAccess, - ResourceState::ShaderResource); - - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + auto commandEncoder = gQueue->createCommandEncoder(); + // Clear learning and diff textures + commandEncoder->clearTextureFloat(gLearningTexture, kEntireTexture, clearValue); + commandEncoder->clearTextureFloat(gDiffTexture, kEntireTexture, clearValue); + + gQueue->submit(commandEncoder->finish()); } return SLANG_OK; @@ -518,160 +448,122 @@ struct AutoDiffTexture : public WindowedAppBase } template<typename SetupPipelineFunc> - void renderImage( - int transientHeapIndex, - IFramebuffer* fb, - const SetupPipelineFunc& setupPipeline) + void renderImage(ITexture* renderTarget, const SetupPipelineFunc& setupPipeline) { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[transientHeapIndex]->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, fb); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> renderTargetView = createRTV(renderTarget, Format::RGBA8Unorm); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = renderTargetView; + colorAttachment.loadOp = LoadOp::Clear; + colorAttachment.clearValue[0] = 0.3f; + colorAttachment.clearValue[1] = 0.5f; + colorAttachment.clearValue[2] = 0.7f; + colorAttachment.clearValue[3] = 1.0f; + + RenderPassDepthStencilAttachment depthAttachment = {}; + depthAttachment.view = gDepthTextureView; + depthAttachment.depthLoadOp = LoadOp::Clear; + depthAttachment.depthClearValue = 1.0f; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; + renderPass.depthStencilAttachment = &depthAttachment; + + auto renderEncoder = commandEncoder->beginRenderPass(renderPass); + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + renderState.vertexBuffers[0] = gVertexBuffer; + renderState.vertexBufferCount = 1; setupPipeline(renderEncoder); - renderEncoder->setVertexBuffer(0, gVertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleStrip); - renderEncoder->draw(4); - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + renderEncoder->setRenderState(renderState); + + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 4; + renderEncoder->draw(drawArgs); + renderEncoder->end(); + gQueue->submit(commandEncoder->finish()); } - void renderReferenceImage(int transientHeapIndex, glm::mat4x4 transformMatrix) + void renderReferenceImage(glm::mat4x4 transformMatrix) { - { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[transientHeapIndex]->createCommandBuffer(); - auto encoder = commandBuffer->encodeResourceCommands(); - encoder->textureBarrier( - gRefImage, - ResourceState::ShaderResource, - ResourceState::RenderTarget); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - } - renderImage( - transientHeapIndex, - gRefFrameBuffer, - [&](IRenderCommandEncoder* encoder) + gRefImage, + [&](IRenderPassEncoder* encoder) { - auto rootObject = encoder->bindPipeline(gRefPipelineState); + auto rootObject = + encoder->bindPipeline(static_cast<IRenderPipeline*>(gRefPipeline.get())); ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["modelViewProjection"].setData( &transformMatrix, sizeof(float) * 16); - rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gTexView); - rootCursor["Uniforms"]["sampler"].setSampler(gSampler); + rootCursor["Uniforms"]["bwdTexture"]["texture"].setBinding(gTexView); + rootCursor["Uniforms"]["sampler"].setBinding(gSampler); rootCursor["Uniforms"]["mipOffset"].setData( mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); - rootCursor["Uniforms"]["texRef"].setResource(gTexView); - rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource( - gAccumulateBufferView); + rootCursor["Uniforms"]["texRef"].setBinding(gTexView); + rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setBinding( + gAccumulateBuffer); }); } - virtual void renderFrame(int frameBufferIndex) override + virtual void renderFrame(ITexture* texture) override { static uint32_t frameCount = 0; frameCount++; auto transformMatrix = getTransformMatrix(); - renderReferenceImage(frameBufferIndex, transformMatrix); + renderReferenceImage(transformMatrix); - // Barriers. + // Clear buffers { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto resEncoder = commandBuffer->encodeResourceCommands(); - ClearValue clearValue = {}; - resEncoder->bufferBarrier( - gAccumulateBuffer, - ResourceState::Undefined, - ResourceState::UnorderedAccess); - resEncoder->bufferBarrier( - gReconstructBuffer, - ResourceState::Undefined, - ResourceState::UnorderedAccess); - resEncoder->textureBarrier( - gRefImage, - ResourceState::Present, - ResourceState::ShaderResource); - resEncoder->textureBarrier( - gIterImage, - ResourceState::ShaderResource, - ResourceState::RenderTarget); - resEncoder->clearResourceView( - gAccumulateBufferView, - &clearValue, - ClearResourceViewFlags::None); - resEncoder->clearResourceView( - gReconstructBufferView, - &clearValue, - ClearResourceViewFlags::None); + auto commandEncoder = gQueue->createCommandEncoder(); + commandEncoder->clearBuffer(gAccumulateBuffer, 0, gAccumulateBuffer->getDesc().size); + commandEncoder->clearBuffer(gReconstructBuffer, 0, gReconstructBuffer->getDesc().size); + if (resetLearntTexture) { - resEncoder->textureBarrier( - gLearningTexture, - ResourceState::ShaderResource, - ResourceState::UnorderedAccess); - for (Index i = 0; i < gLearningTextureUAVs.getCount(); i++) - resEncoder->clearResourceView( - gLearningTextureUAVs[i], - &clearValue, - ClearResourceViewFlags::None); - resEncoder->textureBarrier( - gLearningTexture, - ResourceState::UnorderedAccess, - ResourceState::ShaderResource); + commandEncoder->clearTextureFloat(gLearningTexture, kEntireTexture, clearValue); resetLearntTexture = false; } - resEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + gQueue->submit(commandEncoder->finish()); } // Render image using backward propagate shader to obtain texture-space gradients. renderImage( - frameBufferIndex, - gIterFrameBuffer, - [&](IRenderCommandEncoder* encoder) + gIterImage, + [&](IRenderPassEncoder* encoder) { - auto rootObject = encoder->bindPipeline(gIterPipelineState); + auto rootObject = encoder->bindPipeline(gIterPipeline.get()); ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["modelViewProjection"].setData( &transformMatrix, sizeof(float) * 16); - rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gLearningTextureSRV); - rootCursor["Uniforms"]["sampler"].setSampler(gSampler); + rootCursor["Uniforms"]["bwdTexture"]["texture"].setBinding(gLearningTextureSRV); + rootCursor["Uniforms"]["sampler"].setBinding(gSampler); rootCursor["Uniforms"]["mipOffset"].setData( mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); - rootCursor["Uniforms"]["texRef"].setResource(gRefImageSRV); - rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource( - gAccumulateBufferView); + rootCursor["Uniforms"]["texRef"].setBinding(gRefImageSRV); + rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setBinding( + gAccumulateBuffer); rootCursor["Uniforms"]["bwdTexture"]["minLOD"].setData(5.0); }); // Propagete gradients through mip map layers from top (lowest res) to bottom (highest res). { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - encoder->textureBarrier( - gLearningTexture, - ResourceState::ShaderResource, - ResourceState::UnorderedAccess); - auto rootObject = encoder->bindPipeline(gReconstructPipelineState); + auto commandEncoder = gQueue->createCommandEncoder(); + auto encoder = commandEncoder->beginComputePass(); + auto rootObject = encoder->bindPipeline(gReconstructPipeline.get()); for (int i = (int)mipMapOffset.getCount() - 2; i >= 0; i--) { ShaderCursor rootCursor(rootObject); @@ -682,90 +574,91 @@ struct AutoDiffTexture : public WindowedAppBase rootCursor["Uniforms"]["layerCount"].setData(mipMapOffset.getCount() - 1); rootCursor["Uniforms"]["width"].setData(textureWidth); rootCursor["Uniforms"]["height"].setData(textureHeight); - rootCursor["Uniforms"]["accumulateBuffer"].setResource(gAccumulateBufferView); - rootCursor["Uniforms"]["dstBuffer"].setResource(gReconstructBufferView); + rootCursor["Uniforms"]["accumulateBuffer"].setBinding(gAccumulateBuffer); + rootCursor["Uniforms"]["dstBuffer"].setBinding(gReconstructBuffer); + encoder->dispatchCompute( ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); - encoder->bufferBarrier( - gReconstructBuffer, - ResourceState::UnorderedAccess, - ResourceState::UnorderedAccess); + } + encoder->end(); + gQueue->submit(commandEncoder->finish()); + + commandEncoder = gQueue->createCommandEncoder(); + // Convert bottom layer mip from buffer to texture + { + auto encoder = commandEncoder->beginComputePass(); + auto rootObject = encoder->bindPipeline(gConvertPipeline.get()); + ShaderCursor rootCursor(rootObject); + rootCursor["Uniforms"]["mipOffset"].setData( + mipMapOffset.getBuffer(), + sizeof(uint32_t) * mipMapOffset.getCount()); + rootCursor["Uniforms"]["dstLayer"].setData(0); + rootCursor["Uniforms"]["width"].setData(textureWidth); + rootCursor["Uniforms"]["height"].setData(textureHeight); + rootCursor["Uniforms"]["srcBuffer"].setBinding(gReconstructBuffer); + rootCursor["Uniforms"]["dstTexture"].setBinding(gDiffTextureUAVs[0]); + encoder->dispatchCompute((textureWidth + 15) / 16, (textureHeight + 15) / 16, 1); + encoder->end(); } - // Convert bottom layer mip from buffer to texture. - rootObject = encoder->bindPipeline(gConvertPipelineState); - ShaderCursor rootCursor(rootObject); - rootCursor["Uniforms"]["mipOffset"].setData( - mipMapOffset.getBuffer(), - sizeof(uint32_t) * mipMapOffset.getCount()); - rootCursor["Uniforms"]["dstLayer"].setData(0); - rootCursor["Uniforms"]["width"].setData(textureWidth); - rootCursor["Uniforms"]["height"].setData(textureHeight); - rootCursor["Uniforms"]["srcBuffer"].setResource(gReconstructBufferView); - rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[0]); - encoder->dispatchCompute((textureWidth + 15) / 16, (textureHeight + 15) / 16, 1); - encoder->textureBarrier( - gDiffTexture, - ResourceState::UnorderedAccess, - ResourceState::UnorderedAccess); - - // Build higher level mip map layers. - rootObject = encoder->bindPipeline(gBuildMipPipelineState); + // Build higher level mip map layers + encoder = commandEncoder->beginComputePass(); + rootObject = encoder->bindPipeline(gBuildMipPipeline.get()); for (int i = 1; i < (int)mipMapOffset.getCount() - 1; i++) { + ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["dstWidth"].setData(textureWidth >> i); rootCursor["Uniforms"]["dstHeight"].setData(textureHeight >> i); - rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i - 1]); - rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[i]); + rootCursor["Uniforms"]["srcTexture"].setBinding(gDiffTextureUAVs[i - 1]); + rootCursor["Uniforms"]["dstTexture"].setBinding(gDiffTextureUAVs[i]); encoder->dispatchCompute( ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); - encoder->textureBarrier( - gDiffTexture, - ResourceState::UnorderedAccess, - ResourceState::UnorderedAccess); } + encoder->end(); - // Accumulate gradients to learnt texture. - rootObject = encoder->bindPipeline(gLearnMipPipelineState); + // Accumulate gradients to learnt texture + encoder = commandEncoder->beginComputePass(); + rootObject = encoder->bindPipeline(gLearnMipPipeline.get()); for (int i = 0; i < (int)mipMapOffset.getCount() - 1; i++) { ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["dstWidth"].setData(textureWidth >> i); rootCursor["Uniforms"]["dstHeight"].setData(textureHeight >> i); rootCursor["Uniforms"]["learningRate"].setData(0.1f); - rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i]); - rootCursor["Uniforms"]["dstTexture"].setResource(gLearningTextureUAVs[i]); + rootCursor["Uniforms"]["srcTexture"].setBinding(gDiffTextureUAVs[i]); + rootCursor["Uniforms"]["dstTexture"].setBinding(gLearningTextureUAVs[i]); encoder->dispatchCompute( ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); } - encoder->textureBarrier( - gLearningTexture, - ResourceState::UnorderedAccess, - ResourceState::ShaderResource); - encoder->textureBarrier( - gIterImage, - ResourceState::Present, - ResourceState::ShaderResource); - - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + encoder->end(); + + gQueue->submit(commandEncoder->finish()); } - // Draw currently learnt texture. + // Draw currently learnt texture { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = - commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; + + auto renderEncoder = commandEncoder->beginRenderPass(renderPass); + drawTexturedQuad(renderEncoder, 0, 0, textureWidth, textureHeight, gLearningTextureSRV); + int refImageWidth = windowWidth - textureWidth - 10; int refImageHeight = refImageWidth * windowHeight / windowWidth; drawTexturedQuad( @@ -775,6 +668,7 @@ struct AutoDiffTexture : public WindowedAppBase refImageWidth, refImageHeight, gRefImageSRV); + drawTexturedQuad( renderEncoder, textureWidth + 10, @@ -782,32 +676,35 @@ struct AutoDiffTexture : public WindowedAppBase refImageWidth, refImageHeight, gIterImageSRV); - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + renderEncoder->end(); + gQueue->submit(commandEncoder->finish()); } if (!isTestMode()) { - gSwapchain->present(); + gSurface->present(); } } void drawTexturedQuad( - IRenderCommandEncoder* renderEncoder, + IRenderPassEncoder* renderEncoder, int x, int y, int w, int h, - IResourceView* srv) + ITextureView* srv) { - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); - - auto root = renderEncoder->bindPipeline(gDrawQuadPipelineState); + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + renderState.vertexBuffers[0] = gVertexBuffer; + renderState.vertexBufferCount = 1; + renderEncoder->setRenderState(renderState); + + auto root = + renderEncoder->bindPipeline(static_cast<IRenderPipeline*>(gDrawQuadPipeline.get())); ShaderCursor rootCursor(root); rootCursor["Uniforms"]["x"].setData(x); rootCursor["Uniforms"]["y"].setData(y); @@ -815,11 +712,12 @@ struct AutoDiffTexture : public WindowedAppBase rootCursor["Uniforms"]["height"].setData(h); rootCursor["Uniforms"]["viewWidth"].setData(windowWidth); rootCursor["Uniforms"]["viewHeight"].setData(windowHeight); - rootCursor["Uniforms"]["texture"].setResource(srv); - rootCursor["Uniforms"]["sampler"].setSampler(gSampler); - renderEncoder->setVertexBuffer(0, gVertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleStrip); - renderEncoder->draw(4); + rootCursor["Uniforms"]["texture"].setBinding(srv); + rootCursor["Uniforms"]["sampler"].setBinding(gSampler); + + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 4; + renderEncoder->draw(drawArgs); } }; diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp index 9de47b77b..2c7dd277c 100644 --- a/examples/example-base/example-base.cpp +++ b/examples/example-base/example-base.cpp @@ -10,7 +10,7 @@ #include "stb_image.h" using namespace Slang; -using namespace gfx; +using namespace rhi; Slang::Result WindowedAppBase::initializeBase( const char* title, @@ -18,33 +18,21 @@ Slang::Result WindowedAppBase::initializeBase( int height, DeviceType deviceType) { - // Initialize the rendering layer. + DeviceDesc deviceDesc = {}; + deviceDesc.deviceType = deviceType; #ifdef _DEBUG - // Enable debug layer in debug config. - gfxEnableDebugLayer(true); + deviceDesc.enableValidation = true; #endif - IDevice::Desc deviceDesc = {}; - deviceDesc.deviceType = deviceType; - gfx::Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); - if (SLANG_FAILED(res)) - return res; - - ICommandQueue::Desc queueDesc = {}; - queueDesc.type = ICommandQueue::QueueType::Graphics; - gQueue = gDevice->createCommandQueue(queueDesc); + gDevice = getRHI()->createDevice(deviceDesc); + if (!gDevice) + { + return SLANG_FAIL; + } + gQueue = gDevice->getQueue(QueueType::Graphics); windowWidth = width; windowHeight = height; - IFramebufferLayout::TargetLayout renderTargetLayout = {gfx::Format::R8G8B8A8_UNORM, 1}; - IFramebufferLayout::TargetLayout depthLayout = {gfx::Format::D32_FLOAT, 1}; - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &renderTargetLayout; - framebufferLayoutDesc.depthStencil = &depthLayout; - SLANG_RETURN_ON_FAIL( - gDevice->createFramebufferLayout(framebufferLayoutDesc, gFramebufferLayout.writeRef())); - // Do not create swapchain and windows in test mode, because there won't be any display. if (!isTestMode()) { @@ -59,155 +47,39 @@ Slang::Result WindowedAppBase::initializeBase( gWindow->events.mainLoop = [this]() { mainLoop(); }; gWindow->events.sizeChanged = Slang::Action<>(this, &WindowedAppBase::windowSizeChanged); - auto deviceInfo = gDevice->getDeviceInfo(); + + WindowHandle windowHandle = gWindow->getNativeHandle().convert<WindowHandle>(); + gSurface = gDevice->createSurface(windowHandle); + + auto deviceInfo = gDevice->getInfo(); Slang::StringBuilder titleSb; titleSb << title << " (" << deviceInfo.apiName << ": " << deviceInfo.adapterName << ")"; gWindow->setText(titleSb.getBuffer()); - // Create swapchain and framebuffers. - gfx::ISwapchain::Desc swapchainDesc = {}; - swapchainDesc.format = gfx::Format::R8G8B8A8_UNORM; - swapchainDesc.width = width; - swapchainDesc.height = height; - swapchainDesc.imageCount = kSwapchainImageCount; - swapchainDesc.queue = gQueue; - gfx::WindowHandle windowHandle = gWindow->getNativeHandle().convert<gfx::WindowHandle>(); - gSwapchain = gDevice->createSwapchain(swapchainDesc, windowHandle); - createSwapchainFramebuffers(); + rhi::SurfaceConfig surfaceConfig = {}; + + surfaceConfig.format = Format::RGBA8Unorm; + surfaceConfig.width = width; + surfaceConfig.height = height; + surfaceConfig.desiredImageCount = kSwapchainImageCount; + gSurface->configure(surfaceConfig); } else { - createOfflineFramebuffers(); + createOfflineTextures(); } - for (uint32_t i = 0; i < kSwapchainImageCount; i++) - { - gfx::ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096 * 1024; - auto transientHeap = gDevice->createTransientResourceHeap(transientHeapDesc); - gTransientHeaps.add(transientHeap); - } - - gfx::IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = gFramebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - IRenderPassLayout::TargetAccessDesc depthStencilAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = ResourceState::Undefined; - renderTargetAccess.finalState = ResourceState::Present; - depthStencilAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - depthStencilAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - depthStencilAccess.initialState = ResourceState::DepthWrite; - depthStencilAccess.finalState = ResourceState::DepthWrite; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - renderPassDesc.depthStencilAccess = &depthStencilAccess; - gRenderPass = gDevice->createRenderPassLayout(renderPassDesc); - return SLANG_OK; } void WindowedAppBase::mainLoop() { - int frameBufferIndex = gSwapchain->acquireNextImage(); - - gTransientHeaps[frameBufferIndex]->synchronizeAndReset(); - renderFrame(frameBufferIndex); - gTransientHeaps[frameBufferIndex]->finish(); -} - -void WindowedAppBase::offlineRender() -{ - gTransientHeaps[0]->synchronizeAndReset(); - renderFrame(0); - gTransientHeaps[0]->finish(); -} - -void WindowedAppBase::createFramebuffers( - uint32_t width, - uint32_t height, - gfx::Format colorFormat, - uint32_t frameBufferCount) -{ - for (uint32_t i = 0; i < frameBufferCount; i++) - { - gfx::ITextureResource::Desc depthBufferDesc; - depthBufferDesc.type = IResource::Type::Texture2D; - depthBufferDesc.size.width = width; - depthBufferDesc.size.height = height; - depthBufferDesc.size.depth = 1; - depthBufferDesc.format = gfx::Format::D32_FLOAT; - depthBufferDesc.defaultState = ResourceState::DepthWrite; - depthBufferDesc.allowedStates = ResourceStateSet(ResourceState::DepthWrite); - ClearValue depthClearValue = {}; - depthBufferDesc.optimalClearValue = &depthClearValue; - ComPtr<gfx::ITextureResource> depthBufferResource = - gDevice->createTextureResource(depthBufferDesc, nullptr); - - ComPtr<gfx::ITextureResource> colorBuffer; - if (isTestMode()) - { - gfx::ITextureResource::Desc colorBufferDesc; - colorBufferDesc.type = IResource::Type::Texture2D; - colorBufferDesc.size.width = width; - colorBufferDesc.size.height = height; - colorBufferDesc.size.depth = 1; - colorBufferDesc.format = colorFormat; - colorBufferDesc.defaultState = ResourceState::RenderTarget; - colorBufferDesc.allowedStates = - ResourceStateSet(ResourceState::RenderTarget, ResourceState::CopyDestination); - colorBuffer = gDevice->createTextureResource(colorBufferDesc, nullptr); - } - else - { - gSwapchain->getImage(i, colorBuffer.writeRef()); - } - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = colorFormat; - colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; - ComPtr<gfx::IResourceView> rtv = - gDevice->createTextureView(colorBuffer.get(), colorBufferViewDesc); - - gfx::IResourceView::Desc depthBufferViewDesc; - memset(&depthBufferViewDesc, 0, sizeof(depthBufferViewDesc)); - depthBufferViewDesc.format = gfx::Format::D32_FLOAT; - depthBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - depthBufferViewDesc.type = gfx::IResourceView::Type::DepthStencil; - ComPtr<gfx::IResourceView> dsv = - gDevice->createTextureView(depthBufferResource.get(), depthBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = dsv.get(); - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = gFramebufferLayout; - ComPtr<gfx::IFramebuffer> frameBuffer = gDevice->createFramebuffer(framebufferDesc); - - gFramebuffers.add(frameBuffer); - } -} - -void WindowedAppBase::createOfflineFramebuffers() -{ - gFramebuffers.clear(); - createFramebuffers(windowWidth, windowHeight, gfx::Format::R8G8B8A8_UNORM, 1); + auto texture = gSurface->acquireNextImage(); + renderFrame(texture); } -void WindowedAppBase::createSwapchainFramebuffers() -{ - gFramebuffers.clear(); - createFramebuffers( - gSwapchain->getDesc().width, - gSwapchain->getDesc().height, - gSwapchain->getDesc().format, - kSwapchainImageCount); -} -ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile( +ComPtr<ITextureView> WindowedAppBase::createTextureFromFile( String fileName, int& textureWidth, int& textureHeight) @@ -215,24 +87,24 @@ ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile( int channelsInFile = 0; auto textureContent = stbi_load(fileName.getBuffer(), &textureWidth, &textureHeight, &channelsInFile, 4); - gfx::ITextureResource::Desc textureDesc = {}; - textureDesc.allowedStates.add(ResourceState::ShaderResource); - textureDesc.format = gfx::Format::R8G8B8A8_UNORM; - textureDesc.numMipLevels = Math::Log2Ceil(Math::Min(textureWidth, textureHeight)) + 1; - textureDesc.type = gfx::IResource::Type::Texture2D; + TextureDesc textureDesc = {}; + textureDesc.type = TextureType::Texture2D; + textureDesc.usage = TextureUsage::ShaderResource; + textureDesc.format = Format::RGBA8Unorm; + textureDesc.mipCount = Math::Log2Ceil(Math::Min(textureWidth, textureHeight)) + 1; textureDesc.size.width = textureWidth; textureDesc.size.height = textureHeight; textureDesc.size.depth = 1; - List<gfx::ITextureResource::SubresourceData> subresData; + List<SubresourceData> subresData; List<List<uint32_t>> mipMapData; - mipMapData.setCount(textureDesc.numMipLevels); - subresData.setCount(textureDesc.numMipLevels); + mipMapData.setCount(textureDesc.mipCount); + subresData.setCount(textureDesc.mipCount); mipMapData[0].setCount(textureWidth * textureHeight); memcpy(mipMapData[0].getBuffer(), textureContent, textureWidth * textureHeight * 4); stbi_image_free(textureContent); subresData[0].data = mipMapData[0].getBuffer(); - subresData[0].strideY = textureWidth * 4; - subresData[0].strideZ = textureWidth * textureHeight * 4; + subresData[0].rowPitch = textureWidth * 4; + subresData[0].slicePitch = textureWidth * textureHeight * 4; // Build mipmaps. struct RGBA @@ -254,15 +126,15 @@ ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile( int lastMipWidth = textureWidth; int lastMipHeight = textureHeight; - for (int m = 1; m < textureDesc.numMipLevels; m++) + for (uint32_t m = 1; m < textureDesc.mipCount; m++) { auto lastMipmapData = mipMapData[m - 1].getBuffer(); int w = lastMipWidth / 2; int h = lastMipHeight / 2; mipMapData[m].setCount(w * h); subresData[m].data = mipMapData[m].getBuffer(); - subresData[m].strideY = w * 4; - subresData[m].strideZ = h * w * 4; + subresData[m].rowPitch = w * 4; + subresData[m].slicePitch = h * w * 4; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) @@ -284,13 +156,33 @@ ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile( lastMipHeight = h; } - auto texture = gDevice->createTextureResource(textureDesc, subresData.getBuffer()); + auto texture = gDevice->createTexture(textureDesc, subresData.getBuffer()); - gfx::IResourceView::Desc viewDesc = {}; - viewDesc.type = gfx::IResourceView::Type::ShaderResource; + TextureViewDesc viewDesc = {}; return gDevice->createTextureView(texture.get(), viewDesc); } +void WindowedAppBase::createOfflineTextures() +{ + for (uint32_t i = 0; i < kSwapchainImageCount; i++) + { + TextureDesc textureDesc = {}; + textureDesc.size.width = this->windowWidth; + textureDesc.size.height = this->windowHeight; + textureDesc.format = Format::RGBA8Unorm; + textureDesc.mipCount = 1; + textureDesc.usage = TextureUsage::UnorderedAccess | TextureUsage::CopySource; + auto texture = gDevice->createTexture(textureDesc); + gOfflineTextures.add(texture); + } +} + +void WindowedAppBase::offlineRender() +{ + SLANG_ASSERT(gOfflineTextures.getCount() > 0); + renderFrame(gOfflineTextures[0]); +} + void WindowedAppBase::windowSizeChanged() { // Wait for the GPU to finish. @@ -299,17 +191,12 @@ void WindowedAppBase::windowSizeChanged() auto clientRect = gWindow->getClientRect(); if (clientRect.width > 0 && clientRect.height > 0) { - // Free all framebuffers before resizing swapchain. - gFramebuffers = decltype(gFramebuffers)(); - - // Resize swapchain. - if (gSwapchain->resize(clientRect.width, clientRect.height) == SLANG_OK) - { - // Recreate framebuffers for each swapchain back buffer image. - createSwapchainFramebuffers(); - windowWidth = clientRect.width; - windowHeight = clientRect.height; - } + SurfaceConfig config = {}; + config.format = gSurface->getInfo().preferredFormat; + config.width = clientRect.width; + config.height = clientRect.height; + config.vsync = false; + gSurface->configure(config); } } @@ -364,12 +251,6 @@ public: } }; -void initDebugCallback() -{ - static DebugCallback callback = {}; - gfxSetDebugCallback(&callback); -} - #ifdef _WIN32 void _Win32OutputDebugString(const char* str) { diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h index 9aabac8d4..06970aaba 100644 --- a/examples/example-base/example-base.h +++ b/examples/example-base/example-base.h @@ -3,7 +3,7 @@ #include "core/slang-basic.h" #include "core/slang-io.h" #include "platform/window.h" -#include "slang-gfx.h" +#include "slang-rhi.h" #include "test-base.h" #ifdef _WIN32 @@ -23,6 +23,8 @@ void _Win32OutputDebugString(const char* str); #define EXAMPLE_MAIN(innerMain) PLATFORM_UI_MAIN(innerMain) #endif // _WIN32 +static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + struct WindowedAppBase : public TestBase { protected: @@ -32,39 +34,31 @@ protected: uint32_t windowWidth; uint32_t windowHeight; - Slang::ComPtr<gfx::IDevice> gDevice; + Slang::ComPtr<rhi::IDevice> gDevice; + Slang::ComPtr<rhi::ICommandQueue> gQueue; + Slang::ComPtr<rhi::ISurface> gSurface; - Slang::ComPtr<gfx::ISwapchain> gSwapchain; - Slang::ComPtr<gfx::IFramebufferLayout> gFramebufferLayout; - Slang::List<Slang::ComPtr<gfx::IFramebuffer>> gFramebuffers; - Slang::List<Slang::ComPtr<gfx::ITransientResourceHeap>> gTransientHeaps; - Slang::ComPtr<gfx::IRenderPassLayout> gRenderPass; - Slang::ComPtr<gfx::ICommandQueue> gQueue; + Slang::List<Slang::ComPtr<rhi::ITexture>> gOfflineTextures; Slang::Result initializeBase( const char* title, int width, int height, - gfx::DeviceType deviceType = gfx::DeviceType::Default); - - void createFramebuffers( - uint32_t width, - uint32_t height, - gfx::Format colorFormat, - uint32_t frameBufferCount); - void createSwapchainFramebuffers(); - void createOfflineFramebuffers(); + rhi::DeviceType deviceType = rhi::DeviceType::Default); void mainLoop(); - Slang::ComPtr<gfx::IResourceView> createTextureFromFile( + Slang::ComPtr<rhi::ITextureView> createTextureFromFile( Slang::String fileName, int& textureWidth, int& textureHeight); + + void createOfflineTextures(); + virtual void windowSizeChanged(); protected: - virtual void renderFrame(int framebufferIndex) = 0; + virtual void renderFrame(rhi::ITexture* texture) = 0; public: platform::Window* getWindow() { return gWindow.Ptr(); } @@ -136,13 +130,9 @@ inline void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) } } -void initDebugCallback(); - template<typename TApp> int innerMain(int argc, char** argv) { - initDebugCallback(); - TApp app; app.parseOption(argc, argv); diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp index 27a77a82b..ccf7838a6 100644 --- a/examples/gpu-printing/main.cpp +++ b/examples/gpu-printing/main.cpp @@ -7,16 +7,17 @@ using Slang::ComPtr; #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "gpu-printing.h" #include "platform/window.h" -#include "slang-gfx.h" +#include "slang-rhi.h" -using namespace gfx; +#include <slang-rhi/shader-cursor.h> + +using namespace rhi; static const ExampleResources resourceBase("gpu-printing"); -ComPtr<slang::ISession> createSlangSession(gfx::IDevice* device) +ComPtr<slang::ISession> createSlangSession(IDevice* device) { ComPtr<slang::ISession> slangSession = device->getSlangSession(); return slangSession; @@ -40,19 +41,19 @@ struct ExampleProgram : public TestBase int gWindowWidth = 640; int gWindowHeight = 480; - ComPtr<gfx::IDevice> gDevice; + ComPtr<IDevice> gDevice; ComPtr<slang::ISession> gSlangSession; ComPtr<slang::IModule> gSlangModule; - ComPtr<gfx::IShaderProgram> gProgram; + ComPtr<IShaderProgram> gProgram; - ComPtr<gfx::IPipelineState> gPipelineState; + ComPtr<IComputePipeline> gPipelineState; Slang::Dictionary<int, std::string> gHashedStrings; GPUPrinting gGPUPrinting; - ComPtr<gfx::IShaderProgram> loadComputeProgram( + ComPtr<IShaderProgram> loadComputeProgram( slang::IModule* slangModule, char const* entryPointName) { @@ -69,10 +70,10 @@ struct ExampleProgram : public TestBase gGPUPrinting.loadStrings(linkedProgram->getLayout()); - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - auto shaderProgram = gDevice->createProgram(programDesc); + auto shaderProgram = gDevice->createShaderProgram(programDesc); return shaderProgram; } @@ -80,10 +81,10 @@ struct ExampleProgram : public TestBase Result execute(int argc, char* argv[]) { parseOption(argc, argv); - IDevice::Desc deviceDesc; - Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); - if (SLANG_FAILED(res)) - return res; + DeviceDesc deviceDesc; + gDevice = getRHI()->createDevice(deviceDesc); + if (!gDevice) + return SLANG_FAIL; Slang::String path = resourceBase.resolveResource("kernels.slang"); @@ -96,9 +97,9 @@ struct ExampleProgram : public TestBase if (!gProgram) return SLANG_FAIL; - ComputePipelineStateDesc desc; + ComputePipelineDesc desc; desc.program = gProgram; - auto pipelineState = gDevice->createComputePipelineState(desc); + auto pipelineState = gDevice->createComputePipeline(desc); if (!pipelineState) return SLANG_FAIL; @@ -106,45 +107,28 @@ struct ExampleProgram : public TestBase size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output - IBufferResource::Desc printBufferDesc = {}; - printBufferDesc.type = IResource::Type::Buffer; - printBufferDesc.sizeInBytes = printBufferSize; + BufferDesc printBufferDesc = {}; + printBufferDesc.size = printBufferSize; printBufferDesc.elementSize = sizeof(uint32_t); - printBufferDesc.defaultState = ResourceState::UnorderedAccess; - printBufferDesc.allowedStates = ResourceStateSet( - ResourceState::CopySource, - ResourceState::CopyDestination, - ResourceState::UnorderedAccess); + printBufferDesc.usage = + BufferUsage::UnorderedAccess | BufferUsage::CopySource | BufferUsage::CopyDestination; printBufferDesc.memoryType = MemoryType::DeviceLocal; - auto printBuffer = gDevice->createBufferResource(printBufferDesc); - - IResourceView::Desc printBufferViewDesc = {}; - printBufferViewDesc.type = IResourceView::Type::UnorderedAccess; - printBufferViewDesc.format = Format::Unknown; - auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc); - - ITransientResourceHeap::Desc transientResourceHeapDesc = {}; - transientResourceHeapDesc.constantBufferSize = 256; - auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc); - - ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; - auto queue = gDevice->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - auto rootShaderObject = encoder->bindPipeline(gPipelineState); + auto printBuffer = gDevice->createBuffer(printBufferDesc); + + auto queue = gDevice->getQueue(QueueType::Graphics); + auto commandEncoder = queue->createCommandEncoder(); + auto computeEncoder = commandEncoder->beginComputePass(); + auto rootShaderObject = computeEncoder->bindPipeline(gPipelineState); auto cursor = ShaderCursor(rootShaderObject); - cursor["gPrintBuffer"].setResource(printBufferView); - encoder->dispatchCompute(1, 1, 1); - encoder->bufferBarrier( - printBuffer, - ResourceState::UnorderedAccess, - ResourceState::CopySource); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); + cursor["gPrintBuffer"].setBinding(printBuffer); + + computeEncoder->dispatchCompute(1, 1, 1); + + computeEncoder->end(); + queue->submit(commandEncoder->finish()); ComPtr<ISlangBlob> blob; - gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef()); + gDevice->readBuffer(printBuffer, 0, printBufferSize, blob.writeRef()); gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize); diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp index e71a02115..ece390543 100644 --- a/examples/hello-world/main.cpp +++ b/examples/hello-world/main.cpp @@ -69,7 +69,6 @@ struct HelloWorldExample : public TestBase int exampleMain(int argc, char** argv) { - initDebugCallback(); HelloWorldExample example; example.parseOption(argc, argv); return example.run(); diff --git a/examples/model-viewer/main.cpp b/examples/model-viewer/main.cpp index 8bbc8ec88..9c1c763f2 100644 --- a/examples/model-viewer/main.cpp +++ b/examples/model-viewer/main.cpp @@ -25,17 +25,17 @@ // and parameter binding. // #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/gui.h" #include "platform/model.h" #include "platform/vector-math.h" #include "platform/window.h" -#include "slang-gfx.h" +#include "slang-rhi.h" #include <map> +#include <slang-rhi/shader-cursor.h> #include <sstream> -using namespace gfx; +using namespace rhi; using Slang::RefObject; using Slang::RefPtr; @@ -121,12 +121,12 @@ struct RendererContext // At this point, `composedProgram` represents the shader program // we want to run, and the compute shader there have been checked. - // We can create a `gfx::IShaderProgram` object from `composedProgram` + // We can create a `IShaderProgram` object from `composedProgram` // so it may be used by the graphics layer. - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = composedProgram.get(); - shaderProgram = device->createProgram(programDesc); + shaderProgram = device->createShaderProgram(programDesc); // Get other shader types that we will use for creating shader objects. perViewShaderType = slangReflection->findTypeByName("PerView"); @@ -175,7 +175,7 @@ struct SimpleMaterial : Material auto program = context->slangReflection; auto shaderType = program->findTypeByName("SimpleMaterial"); shaderObject = context->device->createShaderObject(shaderType); - gfx::ShaderCursor cursor(shaderObject); + ShaderCursor cursor(shaderObject); cursor["diffuseColor"].setData(&diffuseColor, sizeof(diffuseColor)); cursor["specularColor"].setData(&specularColor, sizeof(specularColor)); cursor["specularity"].setData(&specularity, sizeof(specularity)); @@ -201,8 +201,8 @@ struct Model : RefObject { typedef platform::ModelLoader::Vertex Vertex; - ComPtr<IBufferResource> vertexBuffer; - ComPtr<IBufferResource> indexBuffer; + ComPtr<IBuffer> vertexBuffer; + ComPtr<IBuffer> indexBuffer; PrimitiveTopology primitiveTopology; int vertexCount; int indexCount; @@ -383,16 +383,19 @@ struct LightEnvLayout : public RefObject // struct LightArrayLayout : RefObject { - Int maximumCount = 0; + SlangInt maximumCount = 0; std::string typeName; }; std::vector<LightArrayLayout> lightArrayLayouts; - std::map<slang::TypeReflection*, Int> mapLightTypeToArrayIndex; + std::map<slang::TypeReflection*, SlangInt> mapLightTypeToArrayIndex; slang::TypeReflection* shaderType = nullptr; - void addLightType(RendererContext* context, slang::TypeReflection* lightType, Int maximumCount) + void addLightType( + RendererContext* context, + slang::TypeReflection* lightType, + SlangInt maximumCount) { - Int arrayIndex = (Int)lightArrayLayouts.size(); + SlangInt arrayIndex = (SlangInt)lightArrayLayouts.size(); LightArrayLayout layout; layout.maximumCount = maximumCount; @@ -419,12 +422,12 @@ struct LightEnvLayout : public RefObject } template<typename T> - void addLightType(RendererContext* context, Int maximumCount) + void addLightType(RendererContext* context, SlangInt maximumCount) { addLightType(context, getShaderType<T>(context), maximumCount); } - Int getArrayIndexForType(slang::TypeReflection* lightType) + SlangInt getArrayIndexForType(slang::TypeReflection* lightType) { auto iter = mapLightTypeToArrayIndex.find(lightType); if (iter != mapLightTypeToArrayIndex.end()) @@ -647,7 +650,7 @@ struct ModelViewer : WindowedAppBase RefPtr<LightEnv> lightEnv; // The pipeline state object we will use to draw models. - ComPtr<IPipelineState> gPipelineState; + ComPtr<IPipeline> gPipelineState; // During startup the application will load one or more models and // add them to the `gModels` list. @@ -762,23 +765,27 @@ struct ModelViewer : WindowedAppBase InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, position)}, - {"NORMAL", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, normal)}, - {"UV", 0, Format::R32G32_FLOAT, offsetof(Model::Vertex, uv)}, + {"POSITION", 0, Format::RGB32Float, offsetof(Model::Vertex, position)}, + {"NORMAL", 0, Format::RGB32Float, offsetof(Model::Vertex, normal)}, + {"UV", 0, Format::RG32Float, offsetof(Model::Vertex, uv)}, }; auto inputLayout = gDevice->createInputLayout(sizeof(Model::Vertex), &inputElements[0], 3); if (!inputLayout) return SLANG_FAIL; // Create the pipeline state object for drawing models. - GraphicsPipelineStateDesc pipelineStateDesc = {}; + RenderPipelineDesc pipelineStateDesc = {}; pipelineStateDesc.program = context.shaderProgram; - pipelineStateDesc.framebufferLayout = gFramebufferLayout; pipelineStateDesc.inputLayout = inputLayout; - pipelineStateDesc.primitiveType = PrimitiveType::Triangle; + pipelineStateDesc.primitiveTopology = PrimitiveTopology::TriangleList; pipelineStateDesc.depthStencil.depthFunc = ComparisonFunc::LessEqual; pipelineStateDesc.depthStencil.depthTestEnable = true; - gPipelineState = gDevice->createGraphicsPipelineState(pipelineStateDesc); + // Set up color target + ColorTargetDesc colorTarget = {}; + colorTarget.format = Format::RGBA8Unorm; + pipelineStateDesc.targetCount = 1; + pipelineStateDesc.targets = &colorTarget; + gPipelineState = gDevice->createRenderPipeline(pipelineStateDesc); // We will create a lighting environment layout that can hold a few point // and directional lights, and then initialize a lighting environment @@ -813,7 +820,7 @@ struct ModelViewer : WindowedAppBase // logic to see how the application will drive the `RenderContext` // type to perform both shader parameter binding and code specialization. // - void renderFrame(int frameIndex) override + void renderFrame(ITexture* texture) override { // In order to see that things are rendering properly we need some // kind of animation, so we will compute a crude delta-time value here. @@ -871,22 +878,35 @@ struct ModelViewer : WindowedAppBase view = glm::translate(view, -cameraPosition); glm::mat4x4 viewProjection = projection * view; - auto deviceInfo = gDevice->getDeviceInfo(); + auto deviceInfo = gDevice->getInfo(); + // Use identity matrix for correction + static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; glm::mat4x4 correctionMatrix; - memcpy(&correctionMatrix, deviceInfo.identityProjectionMatrix, sizeof(float) * 16); + memcpy(&correctionMatrix, kIdentity, sizeof(float) * 16); viewProjection = correctionMatrix * viewProjection; // glm uses column-major layout, we need to translate it to row-major. viewProjection = glm::transpose(viewProjection); - auto drawCommandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); - auto drawCommandEncoder = - drawCommandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)clientRect.width; - viewport.extentY = (float)clientRect.height; - drawCommandEncoder->setViewportAndScissor(viewport); - drawCommandEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + auto drawCommandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; + + auto renderEncoder = drawCommandEncoder->beginRenderPass(renderPass); + + RenderState renderState = {}; + renderState.viewports[0] = + Viewport::fromSize((float)clientRect.width, (float)clientRect.height); + renderState.viewportCount = 1; + renderState.scissorRects[0] = + ScissorRect::fromSize((float)clientRect.width, (float)clientRect.height); + renderState.scissorRectCount = 1; // We are only rendering one view, so we can fill in a per-view // shader object once and use it across all draw calls. @@ -903,8 +923,10 @@ struct ModelViewer : WindowedAppBase // for (auto& model : gModels) { - drawCommandEncoder->setVertexBuffer(0, model->vertexBuffer); - drawCommandEncoder->setIndexBuffer(model->indexBuffer, Format::R32_UINT); + renderState.vertexBuffers[0] = model->vertexBuffer; + renderState.vertexBufferCount = 1; + renderState.indexBuffer = model->indexBuffer; + renderState.indexFormat = IndexFormat::Uint32; // For each model we provide a parameter // block that holds the per-model transformation // parameters, corresponding to the `PerModel` type @@ -932,7 +954,12 @@ struct ModelViewer : WindowedAppBase for (auto& mesh : model->meshes) { // Set the pipeline and binding state for drawing each mesh. - auto rootObject = drawCommandEncoder->bindPipeline(gPipelineState); + auto rootObject = renderEncoder->bindPipeline( + static_cast<IRenderPipeline*>(gPipelineState.get())); + + // Apply render state + renderEncoder->setRenderState(renderState); + ShaderCursor rootCursor(rootObject); rootCursor["gViewParams"].setObject(viewShaderObject); rootCursor["gModelParams"].setObject(modelShaderObject); @@ -953,16 +980,20 @@ struct ModelViewer : WindowedAppBase // All the shader parameters and pipeline states have been set up, // we can now issue a draw call for the mesh. - drawCommandEncoder->drawIndexed(mesh->indexCount, mesh->firstIndex); + DrawArguments drawArgs = {}; + // `drawArgs.vertexCount` is actually `indexCount` for the `DrawIndexed` Graphics + // API + drawArgs.vertexCount = mesh->indexCount; + drawArgs.startIndexLocation = mesh->firstIndex; + renderEncoder->drawIndexed(drawArgs); } } - drawCommandEncoder->endEncoding(); - drawCommandBuffer->close(); - gQueue->executeCommandBuffer(drawCommandBuffer); + renderEncoder->end(); + gQueue->submit(drawCommandEncoder->finish()); if (!isTestMode()) { - gSwapchain->present(); + gSurface->present(); } } }; diff --git a/examples/nv-aftermath-example/main.cpp b/examples/nv-aftermath-example/main.cpp index ed6db43a2..bd17ab096 100644 --- a/examples/nv-aftermath-example/main.cpp +++ b/examples/nv-aftermath-example/main.cpp @@ -5,13 +5,14 @@ #include "GFSDK_Aftermath_GpuCrashDump.h" #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/window.h" #include "slang-com-ptr.h" -#include "slang-gfx.h" #include "slang.h" -using namespace gfx; +#include <slang-rhi.h> +#include <slang-rhi/shader-cursor.h> + +using namespace rhi; using namespace Slang; static const ExampleResources resourceBase("nv-aftermath-example"); @@ -46,11 +47,9 @@ struct AftermathCrashExample : public WindowedAppBase { void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); - gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram); - - Slang::Result initialize(); + Result loadShaderProgram(IDevice* device, IShaderProgram** outProgram); - virtual void renderFrame(int frameBufferIndex) override; + virtual void renderFrame(ITexture* texture) override; void onAftermathCrash(const void* data, const uint32_t dataSizeInBytes); @@ -60,23 +59,85 @@ struct AftermathCrashExample : public WindowedAppBase void onAftermathMarker(const void* pMarker, void** resolvedMarkerData, uint32_t* markerSize); - // Create accessors so we don't have to use g prefixed variables. - gfx::IDevice* getDevice() { return gDevice; } - gfx::ICommandQueue* getQueue() { return gQueue; } - gfx::IFramebufferLayout* getFrameBufferLayout() { return gFramebufferLayout; } - gfx::ISwapchain* getSwapChain() { return gSwapchain; } - gfx::IRenderPassLayout* getRenderPassLayout() { return gRenderPass; } - Slang::List<Slang::ComPtr<gfx::IFramebuffer>>& getFrameBuffers() { return gFramebuffers; } - Slang::List<Slang::ComPtr<gfx::ITransientResourceHeap>>& getTransientHeaps() - { - return gTransientHeaps; - } - - ComPtr<gfx::IPipelineState> m_pipelineState; - ComPtr<gfx::IBufferResource> m_vertexBuffer; + ComPtr<IRenderPipeline> m_renderPipeline; + ComPtr<IBuffer> m_vertexBuffer; /// A counter such that we can make aftermath dump file names unique std::atomic<int> m_uniqueId = 0; + + Slang::Result initialize() + { + // Defer shader debug information callbacks until an actual GPU crash dump + // is generated. Increases memory footprint. + const uint32_t aftermathFeatureFlags = + GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks; + + // As per docs must be called before any device is created + GFSDK_Aftermath_EnableGpuCrashDumps( + GFSDK_Aftermath_Version_API, + GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX | + GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, + aftermathFeatureFlags, + _crashCallback, + _debugInfoCallback, + _crashDescriptionCallback, + _markerCallback, + this); + + SLANG_RETURN_ON_FAIL(initializeBase("autodiff-texture", 1024, 768, DeviceType::Default)); + + + // We will create objects needed to configure the "input assembler" + // (IA) stage of the pipeline. + // + // First, we create an input layout: + // + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::RGB32Float, offsetof(Vertex, position)}, + {"COLOR", 0, Format::RGB32Float, offsetof(Vertex, color)}, + }; + auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2); + if (!inputLayout) + return SLANG_FAIL; + + // Next we allocate a vertex buffer for our pre-initialized + // vertex data. + // + BufferDesc vertexBufferDesc; + vertexBufferDesc.size = kVertexCount * sizeof(Vertex); + vertexBufferDesc.usage = BufferUsage::VertexBuffer; + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + m_vertexBuffer = gDevice->createBuffer(vertexBufferDesc, &kVertexData[0]); + if (!m_vertexBuffer) + return SLANG_FAIL; + + // Now we will use our `loadShaderProgram` function to load + // the code from `shaders.slang` into the graphics API. + // + ComPtr<IShaderProgram> shaderProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(device, shaderProgram.writeRef())); + + // Following the D3D12/Vulkan style of API, we need a pipeline state object + // (PSO) to encapsulate the configuration of the overall graphics pipeline. + // + ColorTargetDesc colorTarget; + colorTarget.format = Format::RGBA8Unorm; + RenderPipelineDesc desc; + desc.inputLayout = inputLayout; + desc.program = shaderProgram; + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = false; + desc.depthStencil.depthWriteEnable = false; + desc.primitiveTopology = PrimitiveTopology::TriangleList; + auto pipelineState = gDevice->createRenderPipeline(desc); + if (!pipelineState) + return SLANG_FAIL; + + m_renderPipeline = pipelineState; + + return SLANG_OK; + } }; void AftermathCrashExample::diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) @@ -264,12 +325,10 @@ static SlangResult _addCompileProducts( return SLANG_OK; } -gfx::Result AftermathCrashExample::loadShaderProgram( - gfx::IDevice* device, - gfx::IShaderProgram** outProgram) +Result AftermathCrashExample::loadShaderProgram(IDevice* device, IShaderProgram** outProgram) { ComPtr<slang::ISession> slangSession; - slangSession = device->getSlangSession(); + slangSession = gDevice->getSlangSession(); // This is a little bit of a work around. // @@ -423,9 +482,9 @@ gfx::Result AftermathCrashExample::loadShaderProgram( // to extract compiled kernel code and load it into the API-specific // program representation. // - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(gDevice->createShaderProgram(programDesc, outProgram)); return SLANG_OK; } @@ -465,129 +524,60 @@ static void GFSDK_AFTERMATH_CALL _markerCallback( markerSize); } -Slang::Result AftermathCrashExample::initialize() +void AftermathCrashExample::renderFrame(ITexture* texture) { - // Defer shader debug information callbacks until an actual GPU crash dump - // is generated. Increases memory footprint. - const uint32_t aftermathFeatureFlags = - GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks; - - // As per docs must be called before any device is created - GFSDK_Aftermath_EnableGpuCrashDumps( - GFSDK_Aftermath_Version_API, - GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX | - GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, - aftermathFeatureFlags, - _crashCallback, - _debugInfoCallback, - _crashDescriptionCallback, - _markerCallback, - this); - - // Set to a specific render API as needed. Valid values are... - // - // * gfx::DeviceType::Default - // * gfx::DeviceType::Vulkan - // * gfx::DeviceType::DirectX12 - // * gfx::DeviceType::DirectX11 + auto commandEncoder = gQueue->createCommandEncoder(); - const gfx::DeviceType deviceType = gfx::DeviceType::Default; + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; - initializeBase("aftermath-crash-example", 1024, 768, deviceType); + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; - auto device = getDevice(); + auto renderEncoder = commandEncoder->beginRenderPass(renderPass); - // We will create objects needed to configur the "input assembler" - // (IA) stage of the D3D pipeline. - // - // First, we create an input layout: - // - InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)}, - {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)}, - }; - auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2); - if (!inputLayout) - return SLANG_FAIL; - - // Next we allocate a vertex buffer for our pre-initialized - // vertex data. - // - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - m_vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - if (!m_vertexBuffer) - return SLANG_FAIL; - - // Now we will use our `loadShaderProgram` function to load - // the code from `shaders.slang` into the graphics API. - // - ComPtr<IShaderProgram> shaderProgram; - SLANG_RETURN_ON_FAIL(loadShaderProgram(device, shaderProgram.writeRef())); - - // Following the D3D12/Vulkan style of API, we need a pipeline state object - // (PSO) to encapsulate the configuration of the overall graphics pipeline. - // - GraphicsPipelineStateDesc desc; - desc.inputLayout = inputLayout; - desc.program = shaderProgram; - desc.framebufferLayout = getFrameBufferLayout(); - auto pipelineState = device->createGraphicsPipelineState(desc); - if (!pipelineState) - return SLANG_FAIL; - - m_pipelineState = pipelineState; - - return SLANG_OK; -} - -void AftermathCrashExample::renderFrame(int frameBufferIndex) -{ - ComPtr<ICommandBuffer> commandBuffer = - getTransientHeaps()[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = - commandBuffer->encodeRenderCommands(gRenderPass, getFrameBuffers()[frameBufferIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); - - auto rootObject = renderEncoder->bindPipeline(m_pipelineState); - - auto deviceInfo = getDevice()->getDeviceInfo(); + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + auto rootObject = renderEncoder->bindPipeline(m_renderPipeline); ShaderCursor rootCursor(rootObject); - rootCursor["Uniforms"]["modelViewProjection"].setData( - deviceInfo.identityProjectionMatrix, - sizeof(float) * 16); + rootCursor["Uniforms"]["modelViewProjection"].setData(kIdentity, sizeof(float) * 16); // We are going to extra efforts to create a shader that we know will time // out because we *want* a GPU "crash", such we can capture via nsight aftermath. - // The failCount is just a number that is large enought to make things take too long. + // The failCount is just a number that is large enough to make things take too long. int32_t failCount = 0x3fffffff; rootCursor["Uniforms"]["failCount"].setData(&failCount, sizeof(failCount)); // We also need to set up a few pieces of fixed-function pipeline // state that are not bound by the pipeline state above. // - renderEncoder->setVertexBuffer(0, m_vertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + renderState.vertexBuffers[0] = m_vertexBuffer; + renderState.vertexBufferCount = 1; + renderEncoder->setRenderState(renderState); // Finally, we are ready to issue a draw call for a single triangle. // - renderEncoder->draw(3); - renderEncoder->endEncoding(); - commandBuffer->close(); - getQueue()->executeCommandBuffer(commandBuffer); + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 3; + renderEncoder->draw(drawArgs); - // With that, we are done drawing for one frame, and ready for the next. - // - getSwapChain()->present(); + renderEncoder->end(); + gQueue->submit(commandEncoder->finish()); + + if (!isTestMode()) + { + // With that, we are done drawing for one frame, and ready for the next. + // + gSurface()->present(); + } // If the id changes means we have a capture and so can quit. // On D3D11, the first present *doesn't* appear to crash. diff --git a/examples/platform-test/main.cpp b/examples/platform-test/main.cpp index 865e4eab7..7949d90c1 100644 --- a/examples/platform-test/main.cpp +++ b/examples/platform-test/main.cpp @@ -1,62 +1,91 @@ +#include "core/slang-basic.h" #include "examples/example-base/example-base.h" #include "platform/window.h" +#include "slang-com-ptr.h" +#include "slang-rhi.h" #include "slang.h" -using namespace gfx; +#include <cstdio> + +using namespace rhi; using namespace Slang; struct PlatformTest : public WindowedAppBase { - void onSizeChanged() { printf("onSizeChanged\n"); } + void onSizeChanged() + { + printf("onSizeChanged\n"); + fflush(stdout); + } - void onFocus() { printf("onFocus\n"); } + void onFocus() + { + printf("onFocus\n"); + fflush(stdout); + } - void onLostFocus() { printf("onLostFocus\n"); } + void onLostFocus() + { + printf("onLostFocus\n"); + fflush(stdout); + } void onKeyDown(platform::KeyEventArgs args) { printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); + fflush(stdout); } void onKeyUp(platform::KeyEventArgs args) { - printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); + printf("onKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); + fflush(stdout); } void onKeyPress(platform::KeyEventArgs args) { printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar); + fflush(stdout); } void onMouseMove(platform::MouseEventArgs args) { - printf( - "onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n", - args.x, - args.y, - args.delta, - args.buttons); + // Throttle mouse move events using a simple counter + static int mouseMoveCounter = 0; + mouseMoveCounter++; + if (mouseMoveCounter % 50 == 0) // Only print every 50th mouse move event + { + printf( + "onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x)\n", + args.x, + args.y, + args.delta, + args.buttons); + fflush(stdout); + } } void onMouseDown(platform::MouseEventArgs args) { printf( - "onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + "onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x)\n", args.x, args.y, args.delta, args.buttons); + fflush(stdout); } void onMouseUp(platform::MouseEventArgs args) { printf( - "onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + "onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x)\n", args.x, args.y, args.delta, args.buttons); + fflush(stdout); } void onMouseWheel(platform::MouseEventArgs args) @@ -67,6 +96,7 @@ struct PlatformTest : public WindowedAppBase args.y, args.delta, args.buttons); + fflush(stdout); } Slang::Result initialize() @@ -77,6 +107,9 @@ struct PlatformTest : public WindowedAppBase SLANG_ASSERT(isTestMode() || gWindow); if (gWindow) { + printf("Setting up event handlers...\n"); + fflush(stdout); + gWindow->events.sizeChanged = [this]() { onSizeChanged(); }; gWindow->events.focus = [this]() { onFocus(); }; gWindow->events.lostFocus = [this]() { onLostFocus(); }; @@ -90,33 +123,47 @@ struct PlatformTest : public WindowedAppBase gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); }; + printf("Event handlers set up successfully.\n"); + } + else + { + printf("No window available for event setup.\n"); + fflush(stdout); } return SLANG_OK; } - virtual void renderFrame(int frameBufferIndex) override + virtual void renderFrame(ITexture* texture) override { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - - auto renderEncoder = - commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); - - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - - // We may not have a swapchain if we're running in test mode - SLANG_ASSERT(isTestMode() || gSwapchain); - if (gSwapchain) - gSwapchain->present(); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; + + auto renderEncoder = commandEncoder->beginRenderPass(renderPass); + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + + renderEncoder->setRenderState(renderState); + + renderEncoder->end(); + gQueue->submit(commandEncoder->finish()); + + if (!isTestMode()) + { + gSurface->present(); + } } }; diff --git a/examples/ray-tracing-pipeline/main.cpp b/examples/ray-tracing-pipeline/main.cpp index a3d468db1..19b74011a 100644 --- a/examples/ray-tracing-pipeline/main.cpp +++ b/examples/ray-tracing-pipeline/main.cpp @@ -1,18 +1,19 @@ // main.cpp // This file implements an example of hardware ray-tracing using -// Slang shaders and the `gfx` graphics API. +// Slang shaders and the `slang-rhi` graphics API. #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/vector-math.h" #include "platform/window.h" #include "slang-com-ptr.h" -#include "slang-gfx.h" +#include "slang-rhi.h" +#include "slang-rhi/acceleration-structure-utils.h" +#include "slang-rhi/shader-cursor.h" #include "slang.h" -using namespace gfx; +using namespace rhi; using namespace Slang; static const ExampleResources resourceBase("ray-tracing-pipeline"); @@ -148,10 +149,10 @@ struct RayTracing : public WindowedAppBase } // Load and compile shader code from souce. - gfx::Result loadShaderProgram( - gfx::IDevice* device, + Result loadShaderProgram( + IDevice* device, bool isRayTracingPipeline, - gfx::IShaderProgram** outProgram) + IShaderProgram** outProgram) { ComPtr<slang::ISession> slangSession; slangSession = device->getSlangSession(); @@ -205,29 +206,25 @@ struct RayTracing : public WindowedAppBase printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); } - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(device->createShaderProgram(programDesc, outProgram)); return SLANG_OK; } - ComPtr<gfx::IPipelineState> gPresentPipelineState; - ComPtr<gfx::IPipelineState> gRenderPipelineState; - ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer; - ComPtr<gfx::IBufferResource> gVertexBuffer; - ComPtr<gfx::IBufferResource> gIndexBuffer; - ComPtr<gfx::IBufferResource> gPrimitiveBuffer; - ComPtr<gfx::IBufferResource> gTransformBuffer; - ComPtr<gfx::IResourceView> gPrimitiveBufferSRV; - ComPtr<gfx::IBufferResource> gInstanceBuffer; - ComPtr<gfx::IBufferResource> gBLASBuffer; - ComPtr<gfx::IAccelerationStructure> gBLAS; - ComPtr<gfx::IBufferResource> gTLASBuffer; - ComPtr<gfx::IAccelerationStructure> gTLAS; - ComPtr<gfx::ITextureResource> gResultTexture; - ComPtr<gfx::IResourceView> gResultTextureUAV; - ComPtr<gfx::IShaderTable> gShaderTable; + ComPtr<IRenderPipeline> gPresentPipeline; + ComPtr<IRayTracingPipeline> gRenderPipeline; + ComPtr<IBuffer> gFullScreenVertexBuffer; + ComPtr<IBuffer> gVertexBuffer; + ComPtr<IBuffer> gIndexBuffer; + ComPtr<IBuffer> gPrimitiveBuffer; + ComPtr<IBuffer> gTransformBuffer; + ComPtr<IBuffer> gInstanceBuffer; + ComPtr<IAccelerationStructure> gBLAS; + ComPtr<IAccelerationStructure> gTLAS; + ComPtr<ITexture> gResultTexture; + ComPtr<IShaderTable> gShaderTable; uint64_t lastTime = 0; @@ -310,233 +307,199 @@ struct RayTracing : public WindowedAppBase gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; } - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::ShaderResource; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + BufferDesc vertexBufferDesc; + vertexBufferDesc.size = kVertexCount * sizeof(Vertex); + vertexBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + vertexBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; + gVertexBuffer = gDevice->createBuffer(vertexBufferDesc, &kVertexData[0]); if (!gVertexBuffer) return SLANG_FAIL; - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); - indexBufferDesc.defaultState = ResourceState::ShaderResource; - gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); + BufferDesc indexBufferDesc; + indexBufferDesc.size = kIndexCount * sizeof(int32_t); + indexBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + indexBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; + gIndexBuffer = gDevice->createBuffer(indexBufferDesc, &kIndexData[0]); if (!gIndexBuffer) return SLANG_FAIL; - IBufferResource::Desc primitiveBufferDesc; - primitiveBufferDesc.type = IResource::Type::Buffer; - primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); + BufferDesc primitiveBufferDesc; + primitiveBufferDesc.size = kPrimitiveCount * sizeof(Primitive); primitiveBufferDesc.elementSize = sizeof(Primitive); + primitiveBufferDesc.usage = BufferUsage::ShaderResource; primitiveBufferDesc.defaultState = ResourceState::ShaderResource; - gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); + gPrimitiveBuffer = gDevice->createBuffer(primitiveBufferDesc, &kPrimitiveData[0]); if (!gPrimitiveBuffer) return SLANG_FAIL; - IResourceView::Desc primitiveSRVDesc = {}; - primitiveSRVDesc.format = Format::Unknown; - primitiveSRVDesc.type = IResourceView::Type::ShaderResource; - gPrimitiveBufferSRV = - gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); - - IBufferResource::Desc transformBufferDesc; - transformBufferDesc.type = IResource::Type::Buffer; - transformBufferDesc.sizeInBytes = sizeof(float) * 12; - transformBufferDesc.defaultState = ResourceState::ShaderResource; + BufferDesc transformBufferDesc; + transformBufferDesc.size = sizeof(float) * 12; + transformBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + transformBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; float transformData[12] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); + gTransformBuffer = gDevice->createBuffer(transformBufferDesc, &transformData); if (!gTransformBuffer) return SLANG_FAIL; // Build bottom level acceleration structure. { - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; - accelerationStructureBuildInputs.flags = - IAccelerationStructure::BuildFlags::AllowCompaction; - IAccelerationStructure::GeometryDesc geomDesc; - geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; - geomDesc.type = IAccelerationStructure::GeometryType::Triangles; - geomDesc.content.triangles.indexCount = kIndexCount; - geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); - geomDesc.content.triangles.indexFormat = Format::R32_UINT; - geomDesc.content.triangles.vertexCount = kVertexCount; - geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); - geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; - geomDesc.content.triangles.vertexStride = sizeof(Vertex); - geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); - accelerationStructureBuildInputs.geometryDescs = &geomDesc; + AccelerationStructureBuildInput buildInput = {}; + buildInput.type = AccelerationStructureBuildInputType::Triangles; + buildInput.triangles.vertexBuffers[0] = gVertexBuffer; + buildInput.triangles.vertexBufferCount = 1; + buildInput.triangles.vertexFormat = Format::RGB32Float; + buildInput.triangles.vertexCount = kVertexCount; + buildInput.triangles.vertexStride = sizeof(Vertex); + buildInput.triangles.indexBuffer = gIndexBuffer; + buildInput.triangles.indexFormat = IndexFormat::Uint32; + buildInput.triangles.indexCount = kIndexCount; + buildInput.triangles.preTransformBuffer = gTransformBuffer; + buildInput.triangles.flags = AccelerationStructureGeometryFlags::Opaque; + + AccelerationStructureBuildDesc buildDesc = {}; + buildDesc.inputs = &buildInput; + buildDesc.inputCount = 1; + buildDesc.flags = AccelerationStructureBuildFlags::AllowCompaction; // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, - &accelerationStructurePrebuildInfo)); + AccelerationStructureSizes sizes; + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructureSizes(buildDesc, &sizes)); + // Allocate buffers for acceleration structure. - IBufferResource::Desc asDraftBufferDesc; - asDraftBufferDesc.type = IResource::Type::Buffer; - asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; - asDraftBufferDesc.sizeInBytes = - (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); - if (!draftBuffer) - return SLANG_FAIL; - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; + BufferDesc scratchBufferDesc; + scratchBufferDesc.usage = BufferUsage::UnorderedAccess; scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = - (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = - gDevice->createBufferResource(scratchBufferDesc); + scratchBufferDesc.size = sizes.scratchSize; + ComPtr<IBuffer> scratchBuffer = gDevice->createBuffer(scratchBufferDesc); if (!scratchBuffer) return SLANG_FAIL; // Build acceleration structure. ComPtr<IQueryPool> compactedSizeQuery; - IQueryPool::Desc queryPoolDesc; + QueryPoolDesc queryPoolDesc; queryPoolDesc.count = 1; queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; SLANG_RETURN_ON_FAIL( gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); ComPtr<IAccelerationStructure> draftAS; - IAccelerationStructure::CreateDesc draftCreateDesc; - draftCreateDesc.buffer = draftBuffer; - draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; - draftCreateDesc.offset = 0; - draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + AccelerationStructureDesc draftCreateDesc; + draftCreateDesc.size = sizes.accelerationStructureSize; SLANG_RETURN_ON_FAIL( gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); compactedSizeQuery->reset(); - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = draftAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + auto commandEncoder = gQueue->createCommandEncoder(); AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; compactedSizeQueryDesc.queryPool = compactedSizeQuery; compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; - encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + commandEncoder->buildAccelerationStructure( + buildDesc, + draftAS, + nullptr, + scratchBuffer, + 1, + &compactedSizeQueryDesc); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); uint64_t compactedSize = 0; compactedSizeQuery->getResult(0, 1, &compactedSize); - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)compactedSize; - gBLASBuffer = gDevice->createBufferResource(asBufferDesc); - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gBLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::BottomLevel; - createDesc.offset = 0; - createDesc.size = (size_t)compactedSize; + AccelerationStructureDesc createDesc; + createDesc.size = compactedSize; gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); - commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - encoder = commandBuffer->encodeRayTracingCommands(); - encoder->copyAccelerationStructure( + commandEncoder = gQueue->createCommandEncoder(); + commandEncoder->copyAccelerationStructure( gBLAS, draftAS, AccelerationStructureCopyMode::Compact); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); } // Build top level acceleration structure. { - List<IAccelerationStructure::InstanceDesc> instanceDescs; - instanceDescs.setCount(1); - instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); - instanceDescs[0].flags = - IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; - instanceDescs[0].instanceContributionToHitGroupIndex = 0; - instanceDescs[0].instanceID = 0; - instanceDescs[0].instanceMask = 0xFF; + AccelerationStructureInstanceDescType nativeInstanceDescType = + getAccelerationStructureInstanceDescType(gDevice); + Size nativeInstanceDescSize = + getAccelerationStructureInstanceDescSize(nativeInstanceDescType); + + std::vector<AccelerationStructureInstanceDescGeneric> instanceDescs; + instanceDescs.resize(1); float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = - instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); + instanceDescs[0].instanceID = 0; + instanceDescs[0].instanceMask = 0xFF; + instanceDescs[0].instanceContributionToHitGroupIndex = 0; + instanceDescs[0].flags = AccelerationStructureInstanceFlags::TriangleFacingCullDisable; + instanceDescs[0].accelerationStructure = gBLAS->getHandle(); + + std::vector<uint8_t> nativeInstanceDescs(instanceDescs.size() * nativeInstanceDescSize); + convertAccelerationStructureInstanceDescs( + instanceDescs.size(), + nativeInstanceDescType, + nativeInstanceDescs.data(), + nativeInstanceDescSize, + instanceDescs.data(), + sizeof(AccelerationStructureInstanceDescGeneric)); + + BufferDesc instanceBufferDesc; + instanceBufferDesc.size = + instanceDescs.size() * sizeof(AccelerationStructureInstanceDescGeneric); + instanceBufferDesc.usage = BufferUsage::ShaderResource; instanceBufferDesc.defaultState = ResourceState::ShaderResource; - gInstanceBuffer = - gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); + gInstanceBuffer = gDevice->createBuffer(instanceBufferDesc, nativeInstanceDescs.data()); if (!gInstanceBuffer) return SLANG_FAIL; - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; - accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); + AccelerationStructureBuildInput buildInput = {}; + buildInput.type = AccelerationStructureBuildInputType::Instances; + buildInput.instances.instanceBuffer = gInstanceBuffer; + buildInput.instances.instanceCount = 1; + buildInput.instances.instanceStride = nativeInstanceDescSize; + + AccelerationStructureBuildDesc buildDesc = {}; + buildDesc.inputs = &buildInput; + buildDesc.inputCount = 1; // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, - &accelerationStructurePrebuildInfo)); - - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - gTLASBuffer = gDevice->createBufferResource(asBufferDesc); - - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; + AccelerationStructureSizes sizes; + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructureSizes(buildDesc, &sizes)); + + BufferDesc scratchBufferDesc; + scratchBufferDesc.usage = BufferUsage::UnorderedAccess; scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = - (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = - gDevice->createBufferResource(scratchBufferDesc); - - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gTLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::TopLevel; - createDesc.offset = 0; - createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + scratchBufferDesc.size = sizes.scratchSize; + ComPtr<IBuffer> scratchBuffer = gDevice->createBuffer(scratchBufferDesc); + + AccelerationStructureDesc createDesc; + createDesc.size = sizes.accelerationStructureSize; SLANG_RETURN_ON_FAIL( gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = gTLAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - encoder->buildAccelerationStructure(buildDesc, 0, nullptr); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + auto commandEncoder = gQueue->createCommandEncoder(); + commandEncoder + ->buildAccelerationStructure(buildDesc, gTLAS, nullptr, scratchBuffer, 0, nullptr); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); } - IBufferResource::Desc fullScreenVertexBufferDesc; - fullScreenVertexBufferDesc.type = IResource::Type::Buffer; - fullScreenVertexBufferDesc.sizeInBytes = + BufferDesc fullScreenVertexBufferDesc; + fullScreenVertexBufferDesc.size = FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); + fullScreenVertexBufferDesc.usage = BufferUsage::VertexBuffer; fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gFullScreenVertexBuffer = gDevice->createBufferResource( - fullScreenVertexBufferDesc, - &FullScreenTriangle::kVertices[0]); + gFullScreenVertexBuffer = + gDevice->createBuffer(fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]); if (!gFullScreenVertexBuffer) return SLANG_FAIL; InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + {"POSITION", 0, Format::RG32Float, offsetof(FullScreenTriangle::Vertex, position)}, }; auto inputLayout = gDevice->createInputLayout( sizeof(FullScreenTriangle::Vertex), @@ -547,19 +510,25 @@ struct RayTracing : public WindowedAppBase ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); - GraphicsPipelineStateDesc desc; + ColorTargetDesc colorTarget; + colorTarget.format = Format::RGBA16Float; + RenderPipelineDesc desc; desc.inputLayout = inputLayout; desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); - if (!gPresentPipelineState) + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = false; + desc.depthStencil.depthWriteEnable = false; + desc.primitiveTopology = PrimitiveTopology::TriangleList; + gPresentPipeline = gDevice->createRenderPipeline(desc); + if (!gPresentPipeline) return SLANG_FAIL; const char* hitgroupNames[] = {"hitgroup0", "hitgroup1"}; ComPtr<IShaderProgram> rayTracingProgram; SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, rayTracingProgram.writeRef())); - RayTracingPipelineStateDesc rtpDesc = {}; + RayTracingPipelineDesc rtpDesc = {}; rtpDesc.program = rayTracingProgram; rtpDesc.hitGroupCount = 2; HitGroupDesc hitGroups[2]; @@ -571,11 +540,11 @@ struct RayTracing : public WindowedAppBase rtpDesc.maxRayPayloadSize = 64; rtpDesc.maxRecursion = 2; SLANG_RETURN_ON_FAIL( - gDevice->createRayTracingPipelineState(rtpDesc, gRenderPipelineState.writeRef())); - if (!gRenderPipelineState) + gDevice->createRayTracingPipeline(rtpDesc, gRenderPipeline.writeRef())); + if (!gRenderPipeline) return SLANG_FAIL; - IShaderTable::Desc shaderTableDesc = {}; + ShaderTableDesc shaderTableDesc = {}; const char* raygenName = "rayGenShader"; const char* missName = "missShader"; shaderTableDesc.program = rayTracingProgram; @@ -593,19 +562,16 @@ struct RayTracing : public WindowedAppBase void createResultTexture() { - ITextureResource::Desc resultTextureDesc = {}; - resultTextureDesc.type = IResource::Type::Texture2D; - resultTextureDesc.numMipLevels = 1; + TextureDesc resultTextureDesc = {}; + resultTextureDesc.type = TextureType::Texture2D; + resultTextureDesc.mipCount = 1; resultTextureDesc.size.width = windowWidth; resultTextureDesc.size.height = windowHeight; resultTextureDesc.size.depth = 1; + resultTextureDesc.usage = TextureUsage::UnorderedAccess | TextureUsage::ShaderResource; resultTextureDesc.defaultState = ResourceState::UnorderedAccess; - resultTextureDesc.format = Format::R16G16B16A16_FLOAT; - gResultTexture = gDevice->createTextureResource(resultTextureDesc); - IResourceView::Desc resultUAVDesc = {}; - resultUAVDesc.format = resultTextureDesc.format; - resultUAVDesc.type = IResourceView::Type::UnorderedAccess; - gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); + resultTextureDesc.format = Format::RGBA16Float; + gResultTexture = gDevice->createTexture(resultTextureDesc); } virtual void windowSizeChanged() override @@ -659,53 +625,62 @@ struct RayTracing : public WindowedAppBase memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); } - virtual void renderFrame(int frameBufferIndex) override + virtual void renderFrame(ITexture* texture) override { updateUniforms(); { - ComPtr<ICommandBuffer> renderCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); - IShaderObject* rootObject = nullptr; - renderEncoder->bindPipeline(gRenderPipelineState, &rootObject); + auto commandEncoder = gQueue->createCommandEncoder(); + auto rayTracingPassEncoder = commandEncoder->beginRayTracingPass(); + auto rootObject = rayTracingPassEncoder->bindPipeline(gRenderPipeline, gShaderTable); auto cursor = ShaderCursor(rootObject); - cursor["resultTexture"].setResource(gResultTextureUAV); + cursor["resultTexture"].setBinding(gResultTexture); cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); - cursor["sceneBVH"].setResource(gTLAS); - cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); - renderEncoder->dispatchRays(0, gShaderTable, windowWidth, windowHeight, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - gQueue->executeCommandBuffer(renderCommandBuffer); + cursor["sceneBVH"].setBinding(gTLAS); + cursor["primitiveBuffer"].setBinding(gPrimitiveBuffer); + rayTracingPassEncoder->dispatchRays(0, windowWidth, windowHeight, 1); + rayTracingPassEncoder->end(); + gQueue->submit(commandEncoder->finish()); } { - ComPtr<ICommandBuffer> presentCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto presentEncoder = presentCommandBuffer->encodeRenderCommands( - gRenderPass, - gFramebuffers[frameBufferIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - presentEncoder->setViewportAndScissor(viewport); - auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); - cursor["t"].setResource(gResultTextureUAV); - presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer); - presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - presentEncoder->draw(3); - presentEncoder->endEncoding(); - presentCommandBuffer->close(); - gQueue->executeCommandBuffer(presentCommandBuffer); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPassDesc = {}; + renderPassDesc.colorAttachments = &colorAttachment; + renderPassDesc.colorAttachmentCount = 1; + + auto renderPassEncoder = commandEncoder->beginRenderPass(renderPassDesc); + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + renderState.vertexBuffers[0] = gFullScreenVertexBuffer; + renderState.vertexBufferCount = 1; + renderPassEncoder->setRenderState(renderState); + + auto rootObject = renderPassEncoder->bindPipeline(gPresentPipeline); + auto cursor = ShaderCursor(rootObject); + cursor["t"].setBinding(gResultTexture); + + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 3; + renderPassEncoder->draw(drawArgs); + renderPassEncoder->end(); + gQueue->submit(commandEncoder->finish()); } if (!isTestMode()) { // With that, we are done drawing for one frame, and ready for the next. // - gSwapchain->present(); + gSurface->present(); } } }; diff --git a/examples/ray-tracing/main.cpp b/examples/ray-tracing/main.cpp index fffe5e75f..0b14aef7e 100644 --- a/examples/ray-tracing/main.cpp +++ b/examples/ray-tracing/main.cpp @@ -1,18 +1,19 @@ // main.cpp // This file implements an example of hardware ray-tracing using -// Slang shaders and the `gfx` graphics API. +// Slang shaders and the `slang-rhi` graphics API. #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/vector-math.h" #include "platform/window.h" #include "slang-com-ptr.h" -#include "slang-gfx.h" +#include "slang-rhi.h" +#include "slang-rhi/acceleration-structure-utils.h" +#include "slang-rhi/shader-cursor.h" #include "slang.h" -using namespace gfx; +using namespace rhi; using namespace Slang; static const ExampleResources resourceBase("ray-tracing"); @@ -148,10 +149,7 @@ struct RayTracing : public WindowedAppBase } // Load and compile shader code from souce. - gfx::Result loadShaderProgram( - gfx::IDevice* device, - bool isComputePipeline, - gfx::IShaderProgram** outProgram) + Result loadShaderProgram(IDevice* device, bool isComputePipeline, IShaderProgram** outProgram) { ComPtr<slang::ISession> slangSession; slangSession = device->getSlangSession(); @@ -197,28 +195,24 @@ struct RayTracing : public WindowedAppBase printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); } - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(device->createShaderProgram(programDesc, outProgram)); return SLANG_OK; } - ComPtr<gfx::IPipelineState> gPresentPipelineState; - ComPtr<gfx::IPipelineState> gRenderPipelineState; - ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer; - ComPtr<gfx::IBufferResource> gVertexBuffer; - ComPtr<gfx::IBufferResource> gIndexBuffer; - ComPtr<gfx::IBufferResource> gPrimitiveBuffer; - ComPtr<gfx::IBufferResource> gTransformBuffer; - ComPtr<gfx::IResourceView> gPrimitiveBufferSRV; - ComPtr<gfx::IBufferResource> gInstanceBuffer; - ComPtr<gfx::IBufferResource> gBLASBuffer; - ComPtr<gfx::IAccelerationStructure> gBLAS; - ComPtr<gfx::IBufferResource> gTLASBuffer; - ComPtr<gfx::IAccelerationStructure> gTLAS; - ComPtr<gfx::ITextureResource> gResultTexture; - ComPtr<gfx::IResourceView> gResultTextureUAV; + ComPtr<IRenderPipeline> gPresentPipeline; + ComPtr<IComputePipeline> gRenderPipeline; + ComPtr<IBuffer> gFullScreenVertexBuffer; + ComPtr<IBuffer> gVertexBuffer; + ComPtr<IBuffer> gIndexBuffer; + ComPtr<IBuffer> gPrimitiveBuffer; + ComPtr<IBuffer> gTransformBuffer; + ComPtr<IBuffer> gInstanceBuffer; + ComPtr<IAccelerationStructure> gBLAS; + ComPtr<IAccelerationStructure> gTLAS; + ComPtr<ITexture> gResultTexture; uint64_t lastTime = 0; @@ -302,230 +296,199 @@ struct RayTracing : public WindowedAppBase gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; } - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::ShaderResource; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + BufferDesc vertexBufferDesc; + vertexBufferDesc.size = kVertexCount * sizeof(Vertex); + vertexBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + vertexBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; + gVertexBuffer = gDevice->createBuffer(vertexBufferDesc, &kVertexData[0]); if (!gVertexBuffer) return SLANG_FAIL; - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); - indexBufferDesc.defaultState = ResourceState::ShaderResource; - gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); + BufferDesc indexBufferDesc; + indexBufferDesc.size = kIndexCount * sizeof(int32_t); + indexBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + indexBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; + gIndexBuffer = gDevice->createBuffer(indexBufferDesc, &kIndexData[0]); if (!gIndexBuffer) return SLANG_FAIL; - IBufferResource::Desc primitiveBufferDesc; - primitiveBufferDesc.type = IResource::Type::Buffer; - primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); + BufferDesc primitiveBufferDesc; + primitiveBufferDesc.size = kPrimitiveCount * sizeof(Primitive); primitiveBufferDesc.elementSize = sizeof(Primitive); + primitiveBufferDesc.usage = BufferUsage::ShaderResource; primitiveBufferDesc.defaultState = ResourceState::ShaderResource; - gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); + gPrimitiveBuffer = gDevice->createBuffer(primitiveBufferDesc, &kPrimitiveData[0]); if (!gPrimitiveBuffer) return SLANG_FAIL; - IResourceView::Desc primitiveSRVDesc = {}; - primitiveSRVDesc.format = Format::Unknown; - primitiveSRVDesc.type = IResourceView::Type::ShaderResource; - gPrimitiveBufferSRV = - gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); - - IBufferResource::Desc transformBufferDesc; - transformBufferDesc.type = IResource::Type::Buffer; - transformBufferDesc.sizeInBytes = sizeof(float) * 12; - transformBufferDesc.defaultState = ResourceState::ShaderResource; + BufferDesc transformBufferDesc; + transformBufferDesc.size = sizeof(float) * 12; + transformBufferDesc.usage = BufferUsage::AccelerationStructureBuildInput; + transformBufferDesc.defaultState = ResourceState::AccelerationStructureBuildInput; float transformData[12] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); + gTransformBuffer = gDevice->createBuffer(transformBufferDesc, &transformData); if (!gTransformBuffer) return SLANG_FAIL; // Build bottom level acceleration structure. { - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; - accelerationStructureBuildInputs.flags = - IAccelerationStructure::BuildFlags::AllowCompaction; - IAccelerationStructure::GeometryDesc geomDesc; - geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; - geomDesc.type = IAccelerationStructure::GeometryType::Triangles; - geomDesc.content.triangles.indexCount = kIndexCount; - geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); - geomDesc.content.triangles.indexFormat = Format::R32_UINT; - geomDesc.content.triangles.vertexCount = kVertexCount; - geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); - geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; - geomDesc.content.triangles.vertexStride = sizeof(Vertex); - geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); - accelerationStructureBuildInputs.geometryDescs = &geomDesc; + AccelerationStructureBuildInput buildInput = {}; + buildInput.type = AccelerationStructureBuildInputType::Triangles; + buildInput.triangles.vertexBuffers[0] = gVertexBuffer; + buildInput.triangles.vertexBufferCount = 1; + buildInput.triangles.vertexFormat = Format::RGB32Float; + buildInput.triangles.vertexCount = kVertexCount; + buildInput.triangles.vertexStride = sizeof(Vertex); + buildInput.triangles.indexBuffer = gIndexBuffer; + buildInput.triangles.indexFormat = IndexFormat::Uint32; + buildInput.triangles.indexCount = kIndexCount; + buildInput.triangles.preTransformBuffer = gTransformBuffer; + buildInput.triangles.flags = AccelerationStructureGeometryFlags::Opaque; + + AccelerationStructureBuildDesc buildDesc = {}; + buildDesc.inputs = &buildInput; + buildDesc.inputCount = 1; + buildDesc.flags = AccelerationStructureBuildFlags::AllowCompaction; // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, - &accelerationStructurePrebuildInfo)); + AccelerationStructureSizes sizes; + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructureSizes(buildDesc, &sizes)); + // Allocate buffers for acceleration structure. - IBufferResource::Desc asDraftBufferDesc; - asDraftBufferDesc.type = IResource::Type::Buffer; - asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; - asDraftBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; - ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); - if (!draftBuffer) - return SLANG_FAIL; - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; + BufferDesc scratchBufferDesc; + scratchBufferDesc.usage = BufferUsage::UnorderedAccess; scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = - gDevice->createBufferResource(scratchBufferDesc); + scratchBufferDesc.size = sizes.scratchSize; + ComPtr<IBuffer> scratchBuffer = gDevice->createBuffer(scratchBufferDesc); if (!scratchBuffer) return SLANG_FAIL; // Build acceleration structure. ComPtr<IQueryPool> compactedSizeQuery; - IQueryPool::Desc queryPoolDesc; + QueryPoolDesc queryPoolDesc; queryPoolDesc.count = 1; queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; SLANG_RETURN_ON_FAIL( gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); ComPtr<IAccelerationStructure> draftAS; - IAccelerationStructure::CreateDesc draftCreateDesc; - draftCreateDesc.buffer = draftBuffer; - draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; - draftCreateDesc.offset = 0; - draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + AccelerationStructureDesc draftCreateDesc; + draftCreateDesc.size = sizes.accelerationStructureSize; SLANG_RETURN_ON_FAIL( gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); compactedSizeQuery->reset(); - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = draftAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + auto commandEncoder = gQueue->createCommandEncoder(); AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; compactedSizeQueryDesc.queryPool = compactedSizeQuery; compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; - encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + commandEncoder->buildAccelerationStructure( + buildDesc, + draftAS, + nullptr, + scratchBuffer, + 1, + &compactedSizeQueryDesc); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); uint64_t compactedSize = 0; compactedSizeQuery->getResult(0, 1, &compactedSize); - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (gfx::Size)compactedSize; - gBLASBuffer = gDevice->createBufferResource(asBufferDesc); - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gBLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::BottomLevel; - createDesc.offset = 0; - createDesc.size = (gfx::Size)compactedSize; + AccelerationStructureDesc createDesc; + createDesc.size = compactedSize; gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); - commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - encoder = commandBuffer->encodeRayTracingCommands(); - encoder->copyAccelerationStructure( + commandEncoder = gQueue->createCommandEncoder(); + commandEncoder->copyAccelerationStructure( gBLAS, draftAS, AccelerationStructureCopyMode::Compact); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); } // Build top level acceleration structure. { - List<IAccelerationStructure::InstanceDesc> instanceDescs; - instanceDescs.setCount(1); - instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); - instanceDescs[0].flags = - IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; - instanceDescs[0].instanceContributionToHitGroupIndex = 0; - instanceDescs[0].instanceID = 0; - instanceDescs[0].instanceMask = 0xFF; + AccelerationStructureInstanceDescType nativeInstanceDescType = + getAccelerationStructureInstanceDescType(gDevice); + Size nativeInstanceDescSize = + getAccelerationStructureInstanceDescSize(nativeInstanceDescType); + + std::vector<AccelerationStructureInstanceDescGeneric> instanceDescs; + instanceDescs.resize(1); float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = - instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); + instanceDescs[0].instanceID = 0; + instanceDescs[0].instanceMask = 0xFF; + instanceDescs[0].instanceContributionToHitGroupIndex = 0; + instanceDescs[0].flags = AccelerationStructureInstanceFlags::TriangleFacingCullDisable; + instanceDescs[0].accelerationStructure = gBLAS->getHandle(); + + std::vector<uint8_t> nativeInstanceDescs(instanceDescs.size() * nativeInstanceDescSize); + convertAccelerationStructureInstanceDescs( + instanceDescs.size(), + nativeInstanceDescType, + nativeInstanceDescs.data(), + nativeInstanceDescSize, + instanceDescs.data(), + sizeof(AccelerationStructureInstanceDescGeneric)); + + BufferDesc instanceBufferDesc; + instanceBufferDesc.size = + instanceDescs.size() * sizeof(AccelerationStructureInstanceDescGeneric); + instanceBufferDesc.usage = BufferUsage::ShaderResource; instanceBufferDesc.defaultState = ResourceState::ShaderResource; - gInstanceBuffer = - gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); + gInstanceBuffer = gDevice->createBuffer(instanceBufferDesc, nativeInstanceDescs.data()); if (!gInstanceBuffer) return SLANG_FAIL; - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; - accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); + AccelerationStructureBuildInput buildInput = {}; + buildInput.type = AccelerationStructureBuildInputType::Instances; + buildInput.instances.instanceBuffer = gInstanceBuffer; + buildInput.instances.instanceCount = 1; + buildInput.instances.instanceStride = nativeInstanceDescSize; + + AccelerationStructureBuildDesc buildDesc = {}; + buildDesc.inputs = &buildInput; + buildDesc.inputCount = 1; // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, - &accelerationStructurePrebuildInfo)); - - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; - gTLASBuffer = gDevice->createBufferResource(asBufferDesc); - - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; + AccelerationStructureSizes sizes; + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructureSizes(buildDesc, &sizes)); + + BufferDesc scratchBufferDesc; + scratchBufferDesc.usage = BufferUsage::UnorderedAccess; scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = - gDevice->createBufferResource(scratchBufferDesc); - - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gTLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::TopLevel; - createDesc.offset = 0; - createDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + scratchBufferDesc.size = sizes.scratchSize; + ComPtr<IBuffer> scratchBuffer = gDevice->createBuffer(scratchBufferDesc); + + AccelerationStructureDesc createDesc; + createDesc.size = sizes.accelerationStructureSize; SLANG_RETURN_ON_FAIL( gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = gTLAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - encoder->buildAccelerationStructure(buildDesc, 0, nullptr); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + auto commandEncoder = gQueue->createCommandEncoder(); + commandEncoder + ->buildAccelerationStructure(buildDesc, gTLAS, nullptr, scratchBuffer, 0, nullptr); + gQueue->submit(commandEncoder->finish()); gQueue->waitOnHost(); } - IBufferResource::Desc fullScreenVertexBufferDesc; - fullScreenVertexBufferDesc.type = IResource::Type::Buffer; - fullScreenVertexBufferDesc.sizeInBytes = + BufferDesc fullScreenVertexBufferDesc; + fullScreenVertexBufferDesc.size = FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); + fullScreenVertexBufferDesc.usage = BufferUsage::VertexBuffer; fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gFullScreenVertexBuffer = gDevice->createBufferResource( - fullScreenVertexBufferDesc, - &FullScreenTriangle::kVertices[0]); + gFullScreenVertexBuffer = + gDevice->createBuffer(fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]); if (!gFullScreenVertexBuffer) return SLANG_FAIL; InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + {"POSITION", 0, Format::RG32Float, offsetof(FullScreenTriangle::Vertex, position)}, }; auto inputLayout = gDevice->createInputLayout( sizeof(FullScreenTriangle::Vertex), @@ -536,20 +499,26 @@ struct RayTracing : public WindowedAppBase ComPtr<IShaderProgram> shaderProgram; SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); - GraphicsPipelineStateDesc desc; + ColorTargetDesc colorTarget; + colorTarget.format = Format::RGBA16Float; + RenderPipelineDesc desc; desc.inputLayout = inputLayout; desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); - if (!gPresentPipelineState) + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = false; + desc.depthStencil.depthWriteEnable = false; + desc.primitiveTopology = PrimitiveTopology::TriangleList; + gPresentPipeline = gDevice->createRenderPipeline(desc); + if (!gPresentPipeline) return SLANG_FAIL; ComPtr<IShaderProgram> computeProgram; SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, computeProgram.writeRef())); - ComputePipelineStateDesc computeDesc; + ComputePipelineDesc computeDesc; computeDesc.program = computeProgram; - gRenderPipelineState = gDevice->createComputePipelineState(computeDesc); - if (!gRenderPipelineState) + gRenderPipeline = gDevice->createComputePipeline(computeDesc); + if (!gRenderPipeline) return SLANG_FAIL; createResultTexture(); @@ -558,19 +527,16 @@ struct RayTracing : public WindowedAppBase void createResultTexture() { - ITextureResource::Desc resultTextureDesc = {}; - resultTextureDesc.type = IResource::Type::Texture2D; - resultTextureDesc.numMipLevels = 1; + TextureDesc resultTextureDesc = {}; + resultTextureDesc.type = TextureType::Texture2D; + resultTextureDesc.mipCount = 1; resultTextureDesc.size.width = windowWidth; resultTextureDesc.size.height = windowHeight; resultTextureDesc.size.depth = 1; + resultTextureDesc.usage = TextureUsage::UnorderedAccess | TextureUsage::ShaderResource; resultTextureDesc.defaultState = ResourceState::UnorderedAccess; - resultTextureDesc.format = Format::R16G16B16A16_FLOAT; - gResultTexture = gDevice->createTextureResource(resultTextureDesc); - IResourceView::Desc resultUAVDesc = {}; - resultUAVDesc.format = resultTextureDesc.format; - resultUAVDesc.type = IResourceView::Type::UnorderedAccess; - gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); + resultTextureDesc.format = Format::RGBA16Float; + gResultTexture = gDevice->createTexture(resultTextureDesc); } virtual void windowSizeChanged() override @@ -624,52 +590,65 @@ struct RayTracing : public WindowedAppBase memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); } - virtual void renderFrame(int frameBufferIndex) override + virtual void renderFrame(ITexture* texture) override { updateUniforms(); { - ComPtr<ICommandBuffer> renderCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeComputeCommands(); - auto rootObject = renderEncoder->bindPipeline(gRenderPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(0)); - cursor["resultTexture"].setResource(gResultTextureUAV); + auto commandEncoder = gQueue->createCommandEncoder(); + auto computePassEncoder = commandEncoder->beginComputePass(); + auto rootObject = computePassEncoder->bindPipeline(gRenderPipeline); + auto cursor = ShaderCursor(rootObject); + cursor["resultTexture"].setBinding(gResultTexture); cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); - cursor["sceneBVH"].setResource(gTLAS); - cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); - renderEncoder->dispatchCompute((windowWidth + 15) / 16, (windowHeight + 15) / 16, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - gQueue->executeCommandBuffer(renderCommandBuffer); + cursor["sceneBVH"].setBinding(gTLAS); + cursor["primitiveBuffer"].setBinding(gPrimitiveBuffer); + computePassEncoder->dispatchCompute( + (windowWidth + 15) / 16, + (windowHeight + 15) / 16, + 1); + computePassEncoder->end(); + gQueue->submit(commandEncoder->finish()); } { - ComPtr<ICommandBuffer> presentCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto presentEncoder = presentCommandBuffer->encodeRenderCommands( - gRenderPass, - gFramebuffers[frameBufferIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - presentEncoder->setViewportAndScissor(viewport); - auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); - cursor["t"].setResource(gResultTextureUAV); - presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer); - presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - presentEncoder->draw(3); - presentEncoder->endEncoding(); - presentCommandBuffer->close(); - gQueue->executeCommandBuffer(presentCommandBuffer); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPassDesc = {}; + renderPassDesc.colorAttachments = &colorAttachment; + renderPassDesc.colorAttachmentCount = 1; + + auto renderPassEncoder = commandEncoder->beginRenderPass(renderPassDesc); + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + renderState.vertexBuffers[0] = gFullScreenVertexBuffer; + renderState.vertexBufferCount = 1; + renderPassEncoder->setRenderState(renderState); + + auto rootObject = renderPassEncoder->bindPipeline(gPresentPipeline); + auto cursor = ShaderCursor(rootObject); + cursor["t"].setBinding(gResultTexture); + + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 3; + renderPassEncoder->draw(drawArgs); + renderPassEncoder->end(); + gQueue->submit(commandEncoder->finish()); } if (!isTestMode()) { // With that, we are done drawing for one frame, and ready for the next. // - gSwapchain->present(); + gSurface->present(); } } }; diff --git a/examples/reflection-parameter-blocks/main.cpp b/examples/reflection-parameter-blocks/main.cpp index 873e785d0..04e2b19c0 100644 --- a/examples/reflection-parameter-blocks/main.cpp +++ b/examples/reflection-parameter-blocks/main.cpp @@ -21,15 +21,17 @@ // with a certain amount of boilerplate that isn't especially // interesting to discuss. +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" #include "slang-com-ptr.h" +#include "slang-rhi.h" #include "slang.h" -typedef SlangResult Result; -#include "core/slang-basic.h" -#include "examples/example-base/example-base.h" +typedef SlangResult Result; using Slang::ComPtr; using Slang::String; using Slang::List; +using namespace rhi; // The example code currently only supports Vulkan, but the // code is factored with the intention that it could be extended @@ -47,7 +49,7 @@ static const char* kSourceFileName = "shader.slang"; struct PipelineLayoutReflectionContext { - gfx::IDevice* _gfxDevice = nullptr; + IDevice* _rhiDevice = nullptr; slang::ISession* _slangSession = nullptr; slang::ProgramLayout* _slangProgramLayout = nullptr; slang::IBlob* _slangCompiledProgramBlob = nullptr; @@ -529,16 +531,16 @@ struct PipelineLayoutReflectionContext_Vulkan : PipelineLayoutReflectionContext Result createAndValidatePipelineLayout() { // Here we do a little bit of complicated interaction with - // the `gfx` library to allow us to call raw Vulkan API - // functions on the same device that `gfx` kindly set up + // the `slang-rhi` library to allow us to call raw Vulkan API + // functions on the same device that `slang-rhi` kindly set up // for us. // - gfx::IDevice::InteropHandles handles; - SLANG_RETURN_ON_FAIL(_gfxDevice->getNativeDeviceHandles(&handles)); + DeviceNativeHandles handle; + SLANG_RETURN_ON_FAIL(_rhiDevice->getNativeDeviceHandles(&handle)); - vkAPI.instance = (VkInstance)handles.handles[0].handleValue; - vkAPI.physicalDevice = (VkPhysicalDevice)handles.handles[1].handleValue; - vkAPI.device = (VkDevice)handles.handles[2].handleValue; + vkAPI.instance = (VkInstance)handle.handles[0].value; + vkAPI.physicalDevice = (VkPhysicalDevice)handle.handles[1].value; + vkAPI.device = (VkDevice)handle.handles[2].value; vkAPI.initGlobalProcs(); vkAPI.initInstanceProcs(); @@ -575,25 +577,23 @@ struct ReflectionParameterBlocksExampleApp : public TestBase { parseOption(argc, argv); - // We start by initializing the `gfx` system, so that + // We start by initializing the `slang-rhi` system, so that // it can handle most of the details of getting a // Vulkan device up and running. -#ifdef _DEBUG - gfx::gfxEnableDebugLayer(true); -#endif - gfx::IDevice::Desc deviceDesc = {}; - deviceDesc.deviceType = gfx::DeviceType::Vulkan; + DeviceDesc deviceDesc = {}; + deviceDesc.deviceType = DeviceType::Vulkan; - ComPtr<gfx::IDevice> gfxDevice; - SLANG_RETURN_ON_FAIL(gfxCreateDevice(&deviceDesc, gfxDevice.writeRef())); + ComPtr<IDevice> rhiDevice = getRHI()->createDevice(deviceDesc); + if (!rhiDevice) + return SLANG_FAIL; - // The `gfx` library also creates a Slang session as + // The `slang-rhi` library also creates a Slang session as // part of its startup, so we will use the session // it already created for the compilation in // this example. // - auto slangSession = gfxDevice->getSlangSession(); + auto slangSession = rhiDevice->getSlangSession(); // Next we go through the fairly routine steps needed to // compile a Slang program from source. @@ -672,7 +672,7 @@ struct ReflectionParameterBlocksExampleApp : public TestBase // PipelineLayoutReflectionContext_Vulkan context; - context._gfxDevice = gfxDevice; + context._rhiDevice = rhiDevice; context._slangSession = slangSession; context._slangProgramLayout = programLayout; context._slangCompiledProgramBlob = programBinary; diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp index 1010cdcb9..aafcc1505 100644 --- a/examples/shader-object/main.cpp +++ b/examples/shader-object/main.cpp @@ -3,8 +3,8 @@ // This file provides the application code for the `shader-object` example. // -// This example uses the Slang gfx layer to target different APIs. -// The goal is to demonstrate how the Shader Object model implemented in `gfx` layer +// This example uses the Slang slang-rhi layer to target different APIs. +// The goal is to demonstrate how the Shader Object model implemented in `slang-rhi` layer // simplifies shader specialization and parameter binding when using `interface` typed // shader parameters. // @@ -14,29 +14,30 @@ using Slang::ComPtr; #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" -#include "slang-gfx.h" +#include "slang-rhi.h" -using namespace gfx; +#include <slang-rhi/shader-cursor.h> + +using namespace rhi; static const ExampleResources resourceBase("shader-object"); static TestBase testBase; -// Loads the shader code defined in `shader-object.slang` for use by the `gfx` layer. +// Loads the shader code defined in `shader-object.slang` for use by the `slang-rhi` layer. // Result loadShaderProgram( - gfx::IDevice* device, - ComPtr<gfx::IShaderProgram>& outShaderProgram, + IDevice* device, + ComPtr<IShaderProgram>& outShaderProgram, slang::ProgramLayout*& slangReflection) { // We need to obtain a compilation session (`slang::ISession`) that will provide // a scope to all the compilation and loading of code we do. // - // Our example application uses the `gfx` graphics API abstraction layer, which already + // Our example application uses the `slang-rhi` graphics API abstraction layer, which already // creates a Slang compilation session for us, so we just grab and use it here. ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + slangSession = device->getSlangSession(); // Once the session has been obtained, we can start loading code into it. // @@ -119,12 +120,12 @@ Result loadShaderProgram( // At this point, `composedProgram` represents the shader program // we want to run, and the compute shader there have been checked. - // We can create a `gfx::IShaderProgram` object from `composedProgram` + // We can create a `IShaderProgram` object from `composedProgram` // so it may be used by the graphics layer. - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = composedProgram.get(); - auto shaderProgram = device->createProgram(programDesc); + auto shaderProgram = device->createShaderProgram(programDesc); outShaderProgram = shaderProgram; return SLANG_OK; @@ -135,68 +136,53 @@ int exampleMain(int argc, char** argv) { testBase.parseOption(argc, argv); - // Creates a `gfx` renderer, which provides the main interface for + // Creates a `slang-rhi` renderer, which provides the main interface for // interacting with the graphics API. - Slang::ComPtr<gfx::IDevice> device; - IDevice::Desc deviceDesc = {}; - SLANG_RETURN_ON_FAIL(gfxCreateDevice(&deviceDesc, device.writeRef())); - - Slang::ComPtr<gfx::ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - SLANG_RETURN_ON_FAIL( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + Slang::ComPtr<IDevice> device; + DeviceDesc deviceDesc = {}; + device = getRHI()->createDevice(deviceDesc); + if (!device) + return SLANG_FAIL; // Now we can load the shader code. - // A `gfx::IShaderProgram` object for use in the `gfx` layer. - ComPtr<gfx::IShaderProgram> shaderProgram; + // A `IShaderProgram` object for use in the `slang-rhi` layer. + ComPtr<IShaderProgram> shaderProgram; // A composed `IComponentType` that gives us reflection info on the shader code. slang::ProgramLayout* slangReflection; SLANG_RETURN_ON_FAIL(loadShaderProgram(device, shaderProgram, slangReflection)); // Create a pipeline state with the loaded shader. - gfx::ComputePipelineStateDesc pipelineDesc = {}; + ComputePipelineDesc pipelineDesc = {}; pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - SLANG_RETURN_ON_FAIL( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + ComPtr<IComputePipeline> pipelineState; + pipelineState = device->createComputePipeline(pipelineDesc); + if (!pipelineState) + return SLANG_FAIL; // Create and initiate our input/output buffer. const int numberCount = 4; float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; + BufferDesc bufferDesc = {}; + bufferDesc.size = numberCount * sizeof(float); + bufferDesc.format = Format::Undefined; bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); + bufferDesc.usage = BufferUsage::ShaderResource | BufferUsage::UnorderedAccess | + BufferUsage::CopyDestination | BufferUsage::CopySource; bufferDesc.defaultState = ResourceState::UnorderedAccess; bufferDesc.memoryType = MemoryType::DeviceLocal; - ComPtr<gfx::IBufferResource> numbersBuffer; - SLANG_RETURN_ON_FAIL( - device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); - - // Create a resource view for the buffer. - ComPtr<gfx::IResourceView> bufferView; - gfx::IResourceView::Desc viewDesc = {}; - viewDesc.type = gfx::IResourceView::Type::UnorderedAccess; - viewDesc.format = gfx::Format::Unknown; - SLANG_RETURN_ON_FAIL( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + ComPtr<IBuffer> numbersBuffer; + numbersBuffer = device->createBuffer(bufferDesc, (void*)initialData); + if (!numbersBuffer) + return SLANG_FAIL; // We have done all the set up work, now it is time to start recording a command buffer for // GPU execution. { - ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + auto queue = device->getQueue(QueueType::Graphics); + auto commandEncoder = queue->createCommandEncoder(); + auto encoder = commandEncoder->beginComputePass(); // Now comes the interesting part: binding the shader parameter for the // compute kernel that we about to launch. We would like to construct @@ -213,41 +199,38 @@ int exampleMain(int argc, char** argv) slangReflection->findTypeByName("AddTransformer"); // Now we can use this type to create a shader object that can be bound to the root object. - ComPtr<gfx::IShaderObject> transformer; - SLANG_RETURN_ON_FAIL(device->createShaderObject( - addTransformerType, - ShaderObjectContainerType::None, - transformer.writeRef())); + ComPtr<IShaderObject> transformer; + transformer = + device->createShaderObject(addTransformerType, ShaderObjectContainerType::None); + if (!transformer) + return SLANG_FAIL; + // Set the `c` field of the `AddTransformer`. float c = 1.0f; - gfx::ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); // We can set parameters directly with `rootObject`, but that requires us to use // the Slang reflection API to obtain the proper offsets into the root object for each // parameter. We implemented these logic in the `ShaderCursor` helper class, which // simplifies the user code to find shader parameters. Here we demonstrate how to set // parameters with `ShaderCursor`. - gfx::ShaderCursor entryPointCursor( + ShaderCursor entryPointCursor( rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); + // Bind buffer to the entry point. + entryPointCursor.getPath("buffer").setBinding(numbersBuffer); // Bind the previously created transformer object to root object. entryPointCursor.getPath("transformer").setObject(transformer); encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); + encoder->end(); + queue->submit(commandEncoder->finish()); queue->waitOnHost(); } // Read back the results. ComPtr<ISlangBlob> resultBlob; - SLANG_RETURN_ON_FAIL(device->readBufferResource( - numbersBuffer, - 0, - numberCount * sizeof(float), - resultBlob.writeRef())); + SLANG_RETURN_ON_FAIL( + device->readBuffer(numbersBuffer, 0, numberCount * sizeof(float), resultBlob.writeRef())); auto result = reinterpret_cast<const float*>(resultBlob->getBufferPointer()); for (int i = 0; i < numberCount; i++) printf("%f\n", result[i]); diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp index 42054beae..549dbef73 100644 --- a/examples/shader-toy/main.cpp +++ b/examples/shader-toy/main.cpp @@ -21,16 +21,16 @@ using Slang::ComPtr; // #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/performance-counter.h" #include "platform/window.h" -#include "slang-gfx.h" +#include "slang-rhi.h" +#include "slang-rhi/shader-cursor.h" #include <chrono> static const ExampleResources resourceBase("shader-toy"); -using namespace gfx; +using namespace rhi; // In order to display a shader toy effect using rasterization-based shader // execution we need to render a full-screen triangle. We will define a @@ -83,15 +83,15 @@ struct ShaderToyApp : public WindowedAppBase // The main interesting part of the host application code is where we // load, compile, inspect, and compose the Slang shader code. // - Result loadShaderProgram(gfx::IDevice* device, ComPtr<gfx::IShaderProgram>& outShaderProgram) + Result loadShaderProgram(IDevice* device, ComPtr<IShaderProgram>& outShaderProgram) { // We need to obatin a compilation session (`slang::ISession`) that will provide // a scope to all the compilation and loading of code we do. // - // Our example application uses the `gfx` graphics API abstraction layer, which already - // creates a Slang compilation session for us, so we just grab and use it here. + // Our example application uses the `slang-rhi` graphics API abstraction layer, which + // already creates a Slang compilation session for us, so we just grab and use it here. ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + slangSession = device->getSlangSession(); // Once the session has been obtained, we can start loading code into it. // @@ -269,16 +269,17 @@ struct ShaderToyApp : public WindowedAppBase diagnoseIfNeeded(diagnosticsBlob); SLANG_RETURN_ON_FAIL(result); - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram.get(); - auto shaderProgram = device->createProgram(programDesc); + auto shaderProgram = device->createShaderProgram(programDesc); outShaderProgram = shaderProgram; return SLANG_OK; } ComPtr<IShaderProgram> gShaderProgram; - ComPtr<gfx::IPipelineState> gPipelineState; - ComPtr<gfx::IBufferResource> gVertexBuffer; + ComPtr<IPipeline> gPipeline; + ComPtr<IBuffer> gVertexBuffer; + const Format format = Format::RG32Float; Result initialize() { @@ -296,7 +297,7 @@ struct ShaderToyApp : public WindowedAppBase } InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + {"POSITION", 0, format, offsetof(FullScreenTriangle::Vertex, position)}, }; auto inputLayout = gDevice->createInputLayout( sizeof(FullScreenTriangle::Vertex), @@ -305,29 +306,32 @@ struct ShaderToyApp : public WindowedAppBase if (!inputLayout) return SLANG_FAIL; - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = + BufferDesc vertexBufferDesc; + vertexBufferDesc.size = FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gVertexBuffer = - gDevice->createBufferResource(vertexBufferDesc, &FullScreenTriangle::kVertices[0]); + vertexBufferDesc.elementSize = sizeof(FullScreenTriangle::Vertex); + vertexBufferDesc.usage = BufferUsage::VertexBuffer; + gVertexBuffer = gDevice->createBuffer(vertexBufferDesc, &FullScreenTriangle::kVertices[0]); if (!gVertexBuffer) return SLANG_FAIL; SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram)); // Create pipeline. - GraphicsPipelineStateDesc desc; + ColorTargetDesc colorTarget; + colorTarget.format = Format::RGBA8Unorm; + RenderPipelineDesc desc; desc.inputLayout = inputLayout; desc.program = gShaderProgram; - desc.framebufferLayout = gFramebufferLayout; - auto pipelineState = gDevice->createGraphicsPipelineState(desc); - if (!pipelineState) + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = false; + desc.depthStencil.depthWriteEnable = false; + desc.primitiveTopology = PrimitiveTopology::TriangleList; + gPipeline = gDevice->createRenderPipeline(desc); + if (!gPipeline) return SLANG_FAIL; - gPipelineState = pipelineState; - return SLANG_OK; } @@ -341,9 +345,9 @@ struct ShaderToyApp : public WindowedAppBase bool firstTime = true; platform::TimePoint startTime; - virtual void renderFrame(int frameIndex) override + virtual void renderFrame(ITexture* texture) override { - auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); + auto commandEncoder = gQueue->createCommandEncoder(); if (firstTime) { startTime = platform::PerformanceCounter::now(); @@ -373,29 +377,43 @@ struct ShaderToyApp : public WindowedAppBase } // Encode render commands. - auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - encoder->setViewportAndScissor(viewport); - auto rootObject = encoder->bindPipeline(gPipelineState); + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; + + auto encoder = commandEncoder->beginRenderPass(renderPass); + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; + + auto rootObject = encoder->bindPipeline(static_cast<IRenderPipeline*>(gPipeline.get())); auto constantBuffer = rootObject->getObject(ShaderOffset()); constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms)); - encoder->setVertexBuffer(0, gVertexBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - encoder->draw(3); - encoder->endEncoding(); - commandBuffer->close(); + renderState.vertexBuffers[0] = gVertexBuffer; + renderState.vertexBufferCount = 1; + encoder->setRenderState(renderState); - gQueue->executeCommandBuffer(commandBuffer); + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 3; + encoder->draw(drawArgs); - // We may not have a swapchain if we're running in test mode - SLANG_ASSERT(isTestMode() || gSwapchain); - if (gSwapchain) - gSwapchain->present(); + encoder->end(); + + gQueue->submit(commandEncoder->finish()); + + if (!isTestMode()) + { + gSurface->present(); + } } void handleEvent(const platform::MouseEventArgs& event) diff --git a/examples/triangle/main.cpp b/examples/triangle/main.cpp index 4d4779f73..6f61a6c76 100644 --- a/examples/triangle/main.cpp +++ b/examples/triangle/main.cpp @@ -34,12 +34,13 @@ // #include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "gfx-util/shader-cursor.h" #include "platform/window.h" #include "slang-com-ptr.h" -#include "slang-gfx.h" +#include "slang-rhi.h" -using namespace gfx; +#include <slang-rhi/shader-cursor.h> + +using namespace rhi; using namespace Slang; static const ExampleResources resourceBase("triangle"); @@ -88,7 +89,7 @@ struct HelloWorld : public WindowedAppBase // In addition, an application may want to receive reflection information // about the program, which is what a `slang::ProgramLayout` provides. // - gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram) + Result loadShaderProgram(IDevice* device, IShaderProgram** outProgram) { // We need to obtain a compilation session (`slang::ISession`) that will provide // a scope to all the compilation and loading of code we do. @@ -183,9 +184,9 @@ struct HelloWorld : public WindowedAppBase // to extract compiled kernel code and load it into the API-specific // program representation. // - gfx::IShaderProgram::Desc programDesc = {}; + ShaderProgramDesc programDesc = {}; programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + SLANG_RETURN_ON_FAIL(device->createShaderProgram(programDesc, outProgram)); if (isTestMode()) { @@ -212,8 +213,9 @@ struct HelloWorld : public WindowedAppBase // of them come from the utility library we are using to simplify // building an example program. // - ComPtr<gfx::IPipelineState> gPipelineState; - ComPtr<gfx::IBufferResource> gVertexBuffer; + ComPtr<IPipeline> gPipeline; + ComPtr<IBuffer> gVertexBuffer; + const Format format = Format::RGB32Float; // Now that we've covered the function that actually loads and // compiles our Slang shade code, we can go through the rest @@ -231,8 +233,8 @@ struct HelloWorld : public WindowedAppBase // First, we create an input layout: // InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)}, - {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)}, + {"POSITION", 0, format, offsetof(Vertex, position)}, + {"COLOR", 0, format, offsetof(Vertex, color)}, }; auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2); if (!inputLayout) @@ -241,11 +243,12 @@ struct HelloWorld : public WindowedAppBase // Next we allocate a vertex buffer for our pre-initialized // vertex data. // - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + BufferDesc vertexBufferDesc; + vertexBufferDesc.format = format; + vertexBufferDesc.size = kVertexCount * sizeof(Vertex); + vertexBufferDesc.elementSize = sizeof(Vertex); + vertexBufferDesc.usage = BufferUsage::VertexBuffer; + gVertexBuffer = gDevice->createBuffer(vertexBufferDesc, &kVertexData[0]); if (!gVertexBuffer) return SLANG_FAIL; @@ -258,16 +261,20 @@ struct HelloWorld : public WindowedAppBase // Following the D3D12/Vulkan style of API, we need a pipeline state object // (PSO) to encapsulate the configuration of the overall graphics pipeline. // - GraphicsPipelineStateDesc desc; + ColorTargetDesc colorTarget; + colorTarget.format = format; + RenderPipelineDesc desc; desc.inputLayout = inputLayout; desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - auto pipelineState = gDevice->createGraphicsPipelineState(desc); - if (!pipelineState) + desc.targetCount = 1; + desc.targets = &colorTarget; + desc.depthStencil.depthTestEnable = false; + desc.depthStencil.depthWriteEnable = false; + desc.primitiveTopology = PrimitiveTopology::TriangleList; + gPipeline = gDevice->createRenderPipeline(desc); + if (!gPipeline) return SLANG_FAIL; - gPipelineState = pipelineState; - return SLANG_OK; } @@ -276,18 +283,27 @@ struct HelloWorld : public WindowedAppBase // nothing really Slang-specific here, so the commentary doesn't need // to be very detailed. // - virtual void renderFrame(int frameBufferIndex) override + virtual void renderFrame(ITexture* texture) override { - ComPtr<ICommandBuffer> commandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = - commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + auto commandEncoder = gQueue->createCommandEncoder(); + + ComPtr<ITextureView> textureView = gDevice->createTextureView(texture, {}); + RenderPassColorAttachment colorAttachment = {}; + colorAttachment.view = textureView; + colorAttachment.loadOp = LoadOp::Clear; + + RenderPassDesc renderPass = {}; + renderPass.colorAttachments = &colorAttachment; + renderPass.colorAttachmentCount = 1; - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); + auto renderEncoder = commandEncoder->beginRenderPass(renderPass); + + + RenderState renderState = {}; + renderState.viewports[0] = Viewport::fromSize(windowWidth, windowHeight); + renderState.viewportCount = 1; + renderState.scissorRects[0] = ScissorRect::fromSize(windowWidth, windowHeight); + renderState.scissorRectCount = 1; // In order to bind shader parameters to the pipeline, we need // to know how those parameters were assigned to locations/bindings/registers @@ -319,14 +335,15 @@ struct HelloWorld : public WindowedAppBase // This method will return a transient root shader object for us to write our // shader parameters into. // - auto rootObject = renderEncoder->bindPipeline(gPipelineState); + auto rootObject = + renderEncoder->bindPipeline(static_cast<IRenderPipeline*>(gPipeline.get())); // We will update the model-view-projection matrix that is passed // into the shader code via the `Uniforms` buffer on a per-frame // basis, even though the data that is loaded does not change // per-frame (we always use an identity matrix). // - auto deviceInfo = gDevice->getDeviceInfo(); + auto deviceInfo = gDevice->getInfo(); // We know that `rootObject` is a root shader object created // from our program, and that it is set up to hold values for @@ -361,9 +378,7 @@ struct HelloWorld : public WindowedAppBase // Once we have formed a cursor that "points" at the // model-view projection matrix, we can set its data directly. // - rootCursor["Uniforms"]["modelViewProjection"].setData( - deviceInfo.identityProjectionMatrix, - sizeof(float) * 16); + rootCursor["Uniforms"]["modelViewProjection"].setData(kIdentity, sizeof(float) * 16); // // Some readers might be concerned about the performance of // the above operations because of the use of strings. For @@ -384,21 +399,24 @@ struct HelloWorld : public WindowedAppBase // We also need to set up a few pieces of fixed-function pipeline // state that are not bound by the pipeline state above. // - renderEncoder->setVertexBuffer(0, gVertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + renderState.vertexBuffers[0] = gVertexBuffer; + renderState.vertexBufferCount = 1; + renderEncoder->setRenderState(renderState); // Finally, we are ready to issue a draw call for a single triangle. // - renderEncoder->draw(3); - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + DrawArguments drawArgs = {}; + drawArgs.vertexCount = 3; + renderEncoder->draw(drawArgs); + + renderEncoder->end(); + gQueue->submit(commandEncoder->finish()); if (!isTestMode()) { // With that, we are done drawing for one frame, and ready for the next. // - gSwapchain->present(); + gSurface->present(); } } }; |
