diff options
| author | Yong He <yonghe@outlook.com> | 2021-03-31 11:35:17 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-31 11:35:17 -0700 |
| commit | 3f1632a1450a5879f337b4bd178e48880cd583f8 (patch) | |
| tree | db4adc2ac0f6113dfd4a97a0e2f7a0c4312ef48b /examples | |
| parent | 5fde038b1a6b3c8b335cd5b380c3ee8d15403052 (diff) | |
`gfx` explicit transient resource management. (#1774)
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/example-base/example-base.cpp | 160 | ||||
| -rw-r--r-- | examples/example-base/example-base.h | 52 | ||||
| -rw-r--r-- | examples/gpu-printing/main.cpp | 6 | ||||
| -rw-r--r-- | examples/hello-world/main.cpp | 165 | ||||
| -rw-r--r-- | examples/shader-object/main.cpp | 10 | ||||
| -rw-r--r-- | examples/shader-toy/main.cpp | 182 |
6 files changed, 250 insertions, 325 deletions
diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp new file mode 100644 index 000000000..b06bbdf7e --- /dev/null +++ b/examples/example-base/example-base.cpp @@ -0,0 +1,160 @@ +#include "example-base.h" + +using namespace Slang; +using namespace gfx; + +Slang::Result WindowedAppBase::initializeBase(const char* title, int width, int height) +{ + // Create a window for our application to render into. + // + platform::WindowDesc windowDesc; + windowDesc.title = title; + windowDesc.width = width; + windowDesc.height = height; + windowWidth = width; + windowHeight = height; + windowDesc.style = platform::WindowStyle::Default; + gWindow = platform::Application::createWindow(windowDesc); + gWindow->events.mainLoop = [this]() { mainLoop(); }; + gWindow->events.sizeChanged = Slang::Action<>(this, &WindowedAppBase::windowSizeChanged); + + // Initialize the rendering layer. + IDevice::Desc deviceDesc = {}; + gfx::Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); + if (SLANG_FAILED(res)) + return res; + + auto deviceInfo = gDevice->getDeviceInfo(); + Slang::StringBuilder titleSb; + titleSb << title << " (" << deviceInfo.apiName << ": " << deviceInfo.adapterName << ")"; + gWindow->setText(titleSb.getBuffer()); + + ICommandQueue::Desc queueDesc = {}; + queueDesc.type = ICommandQueue::QueueType::Graphics; + gQueue = gDevice->createCommandQueue(queueDesc); + + // Create swapchain and framebuffers. + gfx::ISwapchain::Desc swapchainDesc = {}; + swapchainDesc.format = gfx::Format::RGBA_Unorm_UInt8; + 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); + + IFramebufferLayout::AttachmentLayout renderTargetLayout = {gSwapchain->getDesc().format, 1}; + IFramebufferLayout::AttachmentLayout depthLayout = {gfx::Format::D_Float32, 1}; + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &renderTargetLayout; + framebufferLayoutDesc.depthStencil = &depthLayout; + SLANG_RETURN_ON_FAIL( + gDevice->createFramebufferLayout(framebufferLayoutDesc, gFramebufferLayout.writeRef())); + + createSwapchainFramebuffers(); + + 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::AttachmentAccessDesc renderTargetAccess = {}; + IRenderPassLayout::AttachmentAccessDesc depthStencilAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; + renderTargetAccess.initialState = ResourceState::Undefined; + renderTargetAccess.finalState = ResourceState::Present; + depthStencilAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; + depthStencilAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; + depthStencilAccess.initialState = ResourceState::Undefined; + depthStencilAccess.finalState = ResourceState::DepthWrite; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + renderPassDesc.depthStencilAccess = &depthStencilAccess; + gRenderPass = gDevice->createRenderPassLayout(renderPassDesc); + + return SLANG_OK; +} + +void WindowedAppBase::mainLoop() +{ + int frameBufferIndex = gSwapchain->acquireNextImage(); + if (frameBufferIndex == -1) + return; + + gTransientHeaps[frameBufferIndex]->synchronizeAndReset(); + renderFrame(frameBufferIndex); +} + +void WindowedAppBase::createSwapchainFramebuffers() +{ + gFramebuffers.clear(); + for (uint32_t i = 0; i < kSwapchainImageCount; i++) + { + gfx::ITextureResource::Desc depthBufferDesc; + depthBufferDesc.setDefaults(gfx::IResource::Usage::DepthWrite); + depthBufferDesc.init2D( + gfx::IResource::Type::Texture2D, + gfx::Format::D_Float32, + gSwapchain->getDesc().width, + gSwapchain->getDesc().height, + 0); + + ComPtr<gfx::ITextureResource> depthBufferResource = gDevice->createTextureResource( + gfx::IResource::Usage::DepthWrite, depthBufferDesc, nullptr); + ComPtr<gfx::ITextureResource> colorBuffer; + gSwapchain->getImage(i, colorBuffer.writeRef()); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = gSwapchain->getDesc().format; + 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::D_Float32; + 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::windowSizeChanged() +{ + // Wait for the GPU to finish. + gQueue->wait(); + + 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; + } + } +} diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h new file mode 100644 index 000000000..ab7522f06 --- /dev/null +++ b/examples/example-base/example-base.h @@ -0,0 +1,52 @@ +#pragma once + +#include "slang-gfx.h" +#include "tools/platform/window.h" +#include "source/core/slang-basic.h" + +struct WindowedAppBase +{ +protected: + static const int kSwapchainImageCount = 2; + + Slang::RefPtr<platform::Window> gWindow; + uint32_t windowWidth; + uint32_t windowHeight; + + Slang::ComPtr<gfx::IDevice> gDevice; + + 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::Result initializeBase(const char* titile, int width, int height); + void createSwapchainFramebuffers(); + void mainLoop(); + + virtual void windowSizeChanged(); + +protected: + virtual void renderFrame(int framebufferIndex) = 0; +public: + platform::Window* getWindow() { return gWindow.Ptr(); } + virtual void finalize() { gQueue->wait(); } +}; + +template<typename TApp> +int innerMain() +{ + TApp app; + + if (SLANG_FAILED(app.initialize())) + { + return -1; + } + + platform::Application::run(app.getWindow()); + + app.finalize(); + return 0; +} diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp index 0315d4827..a0acb8159 100644 --- a/examples/gpu-printing/main.cpp +++ b/examples/gpu-printing/main.cpp @@ -113,9 +113,13 @@ Result execute() printBufferViewDesc.type = IResourceView::Type::UnorderedAccess; auto printBufferView = gDevice->createBufferView(printBuffer, 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 = queue->createCommandBuffer(); + auto commandBuffer = transientHeap->createCommandBuffer(); auto encoder = commandBuffer->encodeComputeCommands(); auto rootShaderObject = gDevice->createRootShaderObject(gProgram); encoder->setPipelineState(gPipelineState); diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp index b3bee9c07..19413948a 100644 --- a/examples/hello-world/main.cpp +++ b/examples/hello-world/main.cpp @@ -37,6 +37,7 @@ #include "tools/platform/window.h" #include "slang-com-ptr.h" #include "source/core/slang-basic.h" +#include "examples/example-base/example-base.h" using namespace gfx; using namespace Slang; @@ -62,7 +63,7 @@ static const Vertex kVertexData[kVertexCount] = // The example application will be implemented as a `struct`, so that // we can scope the resources it allocates without using global variables. // -struct HelloWorld +struct HelloWorld : public WindowedAppBase { // Many Slang API functions return detailed diagnostic information @@ -197,12 +198,6 @@ gfx::Result loadShaderProgram( // we have just defined. // -// We will hard-code the size of our rendering window. -// -int gWindowWidth = 1024; -int gWindowHeight = 768; -const uint32_t kSwapchainImageCount = 2; - // We will define global variables for the various platform and // graphics API objects that our application needs: // @@ -210,16 +205,9 @@ const uint32_t kSwapchainImageCount = 2; // of them come from the utility library we are using to simplify // building an example program. // -RefPtr<platform::Window> gWindow; -Slang::ComPtr<gfx::IDevice> gDevice; - ComPtr<gfx::IPipelineState> gPipelineState; ComPtr<gfx::IShaderObject> gRootObject; -ComPtr<gfx::ISwapchain> gSwapchain; -List<ComPtr<gfx::IFramebuffer>> gFramebuffers; ComPtr<gfx::IBufferResource> gVertexBuffer; -ComPtr<gfx::IRenderPassLayout> gRenderPass; -ComPtr<gfx::ICommandQueue> gQueue; // Now that we've covered the function that actually loads and // compiles our Slang shade code, we can go through the rest @@ -229,29 +217,9 @@ Slang::Result initialize() { // Create a window for our application to render into. // - platform::WindowDesc windowDesc; - windowDesc.title = "Hello, World!"; - windowDesc.width = gWindowWidth; - windowDesc.height = gWindowHeight; - windowDesc.style = platform::WindowStyle::FixedSize; - gWindow = platform::Application::createWindow(windowDesc); - gWindow->events.mainLoop = [this]() { renderFrame(); }; - // Initialize the rendering layer. - // - // Note: for now we are hard-coding logic to use the - // Direct3D11 back-end for the graphics API abstraction. - // A future version of this example may support multiple - // platforms/APIs. - // - IDevice::Desc deviceDesc = {}; - 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); - - // Now we will create objects needed to configur the "input assembler" + initializeBase("hello-world", 1024, 768); + + // We will create objects needed to configur the "input assembler" // (IA) stage of the D3D pipeline. // // First, we create an input layout: @@ -315,95 +283,19 @@ Slang::Result initialize() SLANG_RETURN_ON_FAIL(gDevice->createRootShaderObject(shaderProgram, rootObject.writeRef())); gRootObject = rootObject; - // Create swapchain and framebuffers. - gfx::ISwapchain::Desc swapchainDesc = {}; - swapchainDesc.format = gfx::Format::RGBA_Unorm_UInt8; - swapchainDesc.width = gWindowWidth; - swapchainDesc.height = gWindowHeight; - swapchainDesc.imageCount = kSwapchainImageCount; - swapchainDesc.queue = gQueue; - gfx::WindowHandle windowHandle = gWindow->getNativeHandle().convert<gfx::WindowHandle>(); - gSwapchain = gDevice->createSwapchain(swapchainDesc, windowHandle); - - IFramebufferLayout::AttachmentLayout renderTargetLayout = {gSwapchain->getDesc().format, 1}; - IFramebufferLayout::AttachmentLayout depthLayout = {gfx::Format::D_Float32, 1}; - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &renderTargetLayout; - framebufferLayoutDesc.depthStencil = &depthLayout; - ComPtr<IFramebufferLayout> framebufferLayout; - SLANG_RETURN_ON_FAIL( - gDevice->createFramebufferLayout(framebufferLayoutDesc, framebufferLayout.writeRef())); - - for (uint32_t i = 0; i < kSwapchainImageCount; i++) - { - gfx::ITextureResource::Desc depthBufferDesc = {}; - depthBufferDesc.setDefaults(gfx::IResource::Usage::DepthWrite); - depthBufferDesc.init2D( - gfx::IResource::Type::Texture2D, - gfx::Format::D_Float32, - gSwapchain->getDesc().width, - gSwapchain->getDesc().height, - 0); - - ComPtr<gfx::ITextureResource> depthBufferResource = gDevice->createTextureResource( - gfx::IResource::Usage::DepthWrite, depthBufferDesc, nullptr); - ComPtr<gfx::ITextureResource> colorBuffer; - gSwapchain->getImage(i, colorBuffer.writeRef()); - - gfx::IResourceView::Desc colorBufferViewDesc = {}; - colorBufferViewDesc.format = gSwapchain->getDesc().format; - 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 = {}; - depthBufferViewDesc.format = gfx::Format::D_Float32; - 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 = framebufferLayout; - ComPtr<gfx::IFramebuffer> frameBuffer = gDevice->createFramebuffer(framebufferDesc); - gFramebuffers.add(frameBuffer); - } - // 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 = framebufferLayout; + desc.framebufferLayout = gFramebufferLayout; auto pipelineState = gDevice->createGraphicsPipelineState(desc); if (!pipelineState) return SLANG_FAIL; gPipelineState = pipelineState; - gfx::IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::AttachmentAccessDesc renderTargetAccess = {}; - IRenderPassLayout::AttachmentAccessDesc depthStencilAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; - renderTargetAccess.initialState = ResourceState::Undefined; - renderTargetAccess.finalState = ResourceState::Present; - depthStencilAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; - depthStencilAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; - depthStencilAccess.initialState = ResourceState::Undefined; - depthStencilAccess.finalState = ResourceState::DepthWrite; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - renderPassDesc.depthStencilAccess = &depthStencilAccess; - gRenderPass = gDevice->createRenderPassLayout(renderPassDesc); - return SLANG_OK; } @@ -412,17 +304,15 @@ Slang::Result initialize() // nothing really Slang-specific here, so the commentary doesn't need // to be very detailed. // -void renderFrame() +virtual void renderFrame(int frameBufferIndex) override { - uint32_t frameBufferIndex = gSwapchain->acquireNextImage(); - - ComPtr<ICommandBuffer> commandBuffer = gQueue->createCommandBuffer(); + ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); gfx::Viewport viewport = {}; viewport.maxZ = 1.0f; - viewport.extentX = (float)gWindowWidth; - viewport.extentY = (float)gWindowHeight; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; renderEncoder->setViewportAndScissor(viewport); // We will update the model-view-projection matrix that is passed @@ -510,39 +400,8 @@ void renderFrame() gSwapchain->present(); } -void finalize() -{ - gQueue->wait(); - gSwapchain = nullptr; -} - }; -// This "inner" main function is used by the platform abstraction -// layer to deal with differences in how an entry point needs -// to be defined for different platforms. -// -int innerMain() -{ - // We construct an instance of our example application - // `struct` type, and then walk through the lifecyle - // of the application. - - HelloWorld app; - - if (SLANG_FAILED(app.initialize())) - { - return -1; - } - - platform::Application::run(app.gWindow); - - app.finalize(); - - return 0; -} - // This macro instantiates an appropriate main function to -// invoke the `innerMain` above. -// -PLATFORM_UI_MAIN(innerMain) +// run the application defined above. +PLATFORM_UI_MAIN(innerMain<HelloWorld>) diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp index aaafc010a..9329a5418 100644 --- a/examples/shader-object/main.cpp +++ b/examples/shader-object/main.cpp @@ -136,8 +136,15 @@ int main() // interacting with the graphics API. Slang::ComPtr<gfx::IDevice> device; IDevice::Desc deviceDesc = {}; + deviceDesc.deviceType = DeviceType::Vulkan; 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())); + // Now we can load the shader code. // A `gfx::IShaderProgram` object for use in the `gfx` layer. ComPtr<gfx::IShaderProgram> shaderProgram; @@ -212,7 +219,8 @@ int main() { ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = queue->createCommandBuffer(); + + auto commandBuffer = transientHeap->createCommandBuffer(); auto encoder = commandBuffer->encodeComputeCommands(); encoder->setPipelineState(pipelineState); encoder->bindRootShaderObject(rootObject); diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp index c4424b294..a142c3c15 100644 --- a/examples/shader-toy/main.cpp +++ b/examples/shader-toy/main.cpp @@ -23,6 +23,7 @@ using Slang::ComPtr; #include "tools/gfx-util/shader-cursor.h" #include "tools/platform/window.h" #include "tools/platform/performance-counter.h" +#include "examples/example-base/example-base.h" #include "source/core/slang-basic.h" #include <chrono> @@ -54,7 +55,7 @@ const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangl // The application itself will be encapsulated in a C++ `struct` type // so that it can easily scope its state without use of global variables. // -struct ShaderToyApp +struct ShaderToyApp : public WindowedAppBase { // The uniform data used by the shader is defined here as a simple @@ -284,48 +285,17 @@ Result loadShaderProgram(gfx::IDevice* device, ComPtr<gfx::IShaderProgram>& outS return SLANG_OK; } -int gWindowWidth = 1024; -int gWindowHeight = 768; -static const uint32_t kSwapchainImageCount = 2; - -Slang::RefPtr<platform::Window> gWindow; -Slang::ComPtr<gfx::IDevice> gDevice; ComPtr<IShaderProgram> gShaderProgram; ComPtr<gfx::IShaderObject> gRootObject[kSwapchainImageCount]; -ComPtr<gfx::IFramebufferLayout> gFramebufferLayout; ComPtr<gfx::IPipelineState> gPipelineState; ComPtr<gfx::IBufferResource> gVertexBuffer; -ComPtr<gfx::ISwapchain> gSwapchain; -Slang::List<ComPtr<gfx::IFramebuffer>> gFramebuffers; -ComPtr<gfx::IRenderPassLayout> gRenderPass; -ComPtr<gfx::ICommandQueue> gQueue; Result initialize() { - platform::WindowDesc windowDesc; - const char* title = "Slang Shader Toy"; - windowDesc.title = title; - windowDesc.width = gWindowWidth; - windowDesc.height = gWindowHeight; - gWindow = platform::Application::createWindow(windowDesc); - gWindow->events.mainLoop = [this]() { renderFrame(); }; + initializeBase("Shader Toy", 1024, 768); gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; - gWindow->events.sizeChanged = Slang::Action<>(this, &ShaderToyApp::windowSizeChanged); - - IDevice::Desc deviceDesc; - Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); - if(SLANG_FAILED(res)) return res; - - auto deviceInfo = gDevice->getDeviceInfo(); - Slang::StringBuilder titleSb; - titleSb << title << " (" << deviceInfo.apiName << ": " << deviceInfo.adapterName << ")"; - gWindow->setText(titleSb.getBuffer()); - - ICommandQueue::Desc queueDesc = {}; - queueDesc.type = ICommandQueue::QueueType::Graphics; - gQueue = gDevice->createCommandQueue(queueDesc); InputElementDesc inputElements[] = { { "POSITION", 0, Format::RG_Float32, offsetof(FullScreenTriangle::Vertex, position) }, @@ -346,26 +316,6 @@ Result initialize() SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram)); - // Create swapchain and framebuffers. - gfx::ISwapchain::Desc swapchainDesc = {}; - swapchainDesc.format = gfx::Format::RGBA_Unorm_UInt8; - swapchainDesc.width = gWindowWidth; - swapchainDesc.height = gWindowHeight; - swapchainDesc.imageCount = kSwapchainImageCount; - swapchainDesc.queue = gQueue; - gSwapchain = gDevice->createSwapchain(swapchainDesc, gWindow->getNativeHandle().convert<gfx::WindowHandle>()); - - IFramebufferLayout::AttachmentLayout renderTargetLayout = {gSwapchain->getDesc().format, 1}; - IFramebufferLayout::AttachmentLayout depthLayout = {gfx::Format::D_Float32, 1}; - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &renderTargetLayout; - framebufferLayoutDesc.depthStencil = &depthLayout; - SLANG_RETURN_ON_FAIL( - gDevice->createFramebufferLayout(framebufferLayoutDesc, gFramebufferLayout.writeRef())); - - createSwapchainFramebuffers(); - // Create pipeline. GraphicsPipelineStateDesc desc; desc.inputLayout = inputLayout; @@ -377,23 +327,6 @@ Result initialize() gPipelineState = pipelineState; - // Create render pass. - gfx::IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = gFramebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::AttachmentAccessDesc renderTargetAccess = {}; - IRenderPassLayout::AttachmentAccessDesc depthStencilAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; - renderTargetAccess.initialState = ResourceState::Undefined; - renderTargetAccess.finalState = ResourceState::Present; - depthStencilAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; - depthStencilAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; - depthStencilAccess.initialState = ResourceState::Undefined; - depthStencilAccess.finalState = ResourceState::DepthWrite; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - renderPassDesc.depthStencilAccess = &depthStencilAccess; - gRenderPass = gDevice->createRenderPassLayout(renderPassDesc); return SLANG_OK; } @@ -407,13 +340,9 @@ float clickMouseY = 0.0f; bool firstTime = true; platform::TimePoint startTime; -void renderFrame() +virtual void renderFrame(int frameIndex) override { - auto frameIndex = gSwapchain->acquireNextImage(); - if (frameIndex == -1) - return; - - auto commandBuffer = gQueue->createCommandBuffer(); + auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); if( firstTime ) { startTime = platform::PerformanceCounter::now(); @@ -438,8 +367,8 @@ void renderFrame() uniforms.iMouse[2] = isMouseDown ? clickMouseX : -clickMouseX; uniforms.iMouse[3] = isMouseClick ? clickMouseY : -clickMouseY; uniforms.iTime = platform::PerformanceCounter::getElapsedTimeInSeconds(startTime); - uniforms.iResolution[0] = float(gWindowWidth); - uniforms.iResolution[1] = float(gWindowHeight); + uniforms.iResolution[0] = float(windowWidth); + uniforms.iResolution[1] = float(windowHeight); } gRootObject[frameIndex] = gDevice->createRootShaderObject(gShaderProgram); @@ -451,8 +380,8 @@ void renderFrame() gfx::Viewport viewport = {}; viewport.maxZ = 1.0f; - viewport.extentX = (float)gWindowWidth; - viewport.extentY = (float)gWindowHeight; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; encoder->setViewportAndScissor(viewport); encoder->setPipelineState(gPipelineState); encoder->bindRootShaderObject(gRootObject[frameIndex]); @@ -466,101 +395,14 @@ void renderFrame() gSwapchain->present(); } -void finalize() -{ - gQueue->wait(); -} - void handleEvent(const platform::MouseEventArgs& event) { isMouseDown = ((int)event.buttons & (int)platform::ButtonState::Enum::LeftButton) != 0; lastMouseX = (float)event.x; lastMouseY = (float)event.y; } - -void createSwapchainFramebuffers() -{ - gFramebuffers.clear(); - for (uint32_t i = 0; i < kSwapchainImageCount; i++) - { - gfx::ITextureResource::Desc depthBufferDesc; - depthBufferDesc.setDefaults(gfx::IResource::Usage::DepthWrite); - depthBufferDesc.init2D( - gfx::IResource::Type::Texture2D, - gfx::Format::D_Float32, - gSwapchain->getDesc().width, - gSwapchain->getDesc().height, - 0); - - ComPtr<gfx::ITextureResource> depthBufferResource = gDevice->createTextureResource( - gfx::IResource::Usage::DepthWrite, depthBufferDesc, nullptr); - ComPtr<gfx::ITextureResource> colorBuffer; - gSwapchain->getImage(i, colorBuffer.writeRef()); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = gSwapchain->getDesc().format; - 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::D_Float32; - 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 windowSizeChanged() -{ - // Wait for the GPU to finish. - gQueue->wait(); - - 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(); - gWindowWidth = clientRect.width; - gWindowHeight = clientRect.height; - } - } -} - }; -int innerMain() -{ - ShaderToyApp app; - - if (SLANG_FAILED(app.initialize())) - { - return -1; - } - - platform::Application::run(app.gWindow); - - app.finalize(); - - return 0; -} - -PLATFORM_UI_MAIN(innerMain) +// This macro instantiates an appropriate main function to +// run the application defined above. +PLATFORM_UI_MAIN(innerMain<ShaderToyApp>) |
