summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-03-31 11:35:17 -0700
committerGitHub <noreply@github.com>2021-03-31 11:35:17 -0700
commit3f1632a1450a5879f337b4bd178e48880cd583f8 (patch)
treedb4adc2ac0f6113dfd4a97a0e2f7a0c4312ef48b /examples
parent5fde038b1a6b3c8b335cd5b380c3ee8d15403052 (diff)
`gfx` explicit transient resource management. (#1774)
Diffstat (limited to 'examples')
-rw-r--r--examples/example-base/example-base.cpp160
-rw-r--r--examples/example-base/example-base.h52
-rw-r--r--examples/gpu-printing/main.cpp6
-rw-r--r--examples/hello-world/main.cpp165
-rw-r--r--examples/shader-object/main.cpp10
-rw-r--r--examples/shader-toy/main.cpp182
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>)