summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-02-24 15:43:43 -0800
committerGitHub <noreply@github.com>2021-02-24 15:43:43 -0800
commit9b7a007c31072bc9aebd1134aa4f1bfd28a4c541 (patch)
treeb71a48eb30b3b09ab4e77e40dc1c68ecd854ef82 /examples
parentd66b30729029bdb43892e05c9c80fd56ac95a24f (diff)
Explicit swapchain interface in `gfx`. (#1726)
* Explicit swapchain interface in `gfx`. * Correctly return nullptr when `IRenderer` creation failed. * Fix crashes on CUDA tests. * Cleanups.
Diffstat (limited to 'examples')
-rw-r--r--examples/gpu-printing/main.cpp13
-rw-r--r--examples/hello-world/main.cpp102
-rw-r--r--examples/heterogeneous-hello-world/main.cpp7
-rw-r--r--examples/model-viewer/main.cpp135
-rw-r--r--examples/shader-object/main.cpp5
-rw-r--r--examples/shader-toy/main.cpp98
6 files changed, 284 insertions, 76 deletions
diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp
index 63b1939a6..4f79147f6 100644
--- a/examples/gpu-printing/main.cpp
+++ b/examples/gpu-printing/main.cpp
@@ -64,7 +64,6 @@ int gWindowWidth = 640;
int gWindowHeight = 480;
gfx::ApplicationContext* gAppContext;
-gfx::Window* gWindow;
ComPtr<gfx::IRenderer> gRenderer;
ComPtr<slang::ISession> gSlangSession;
@@ -112,17 +111,9 @@ ComPtr<gfx::IShaderProgram> loadComputeProgram(slang::IModule* slangModule, char
Result execute()
{
- WindowDesc windowDesc;
- windowDesc.title = "GPU Printing";
- windowDesc.width = gWindowWidth;
- windowDesc.height = gWindowHeight;
- gWindow = createWindow(windowDesc);
-
IRenderer::Desc rendererDesc;
rendererDesc.rendererType = gfx::RendererType::DirectX11;
- rendererDesc.width = gWindowWidth;
- rendererDesc.height = gWindowHeight;
- Result res = gfxCreateRenderer(&rendererDesc, getPlatformWindowHandle(gWindow), gRenderer.writeRef());
+ Result res = gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
if(SLANG_FAILED(res)) return res;
gSlangSession = createSlangSession(gRenderer);
@@ -157,7 +148,7 @@ Result execute()
// Once we have the descriptor set layout, we can allocate
// and fill in a descriptor set to hold our parameters.
//
- auto descriptorSet = gRenderer->createDescriptorSet(descriptorSetLayout);
+ auto descriptorSet = gRenderer->createDescriptorSet(descriptorSetLayout, IDescriptorSet::Flag::Transient);
if(!descriptorSet) return SLANG_FAIL;
// descriptorSet->setConstantBuffer(0, 0, gConstantBuffer);
diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp
index 49fe2ec67..f0ea3eb2a 100644
--- a/examples/hello-world/main.cpp
+++ b/examples/hello-world/main.cpp
@@ -201,6 +201,7 @@ gfx::Result loadShaderProgram(
//
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:
@@ -213,10 +214,10 @@ gfx::ApplicationContext* gAppContext;
gfx::Window* gWindow;
Slang::ComPtr<gfx::IRenderer> gRenderer;
-//ComPtr<gfx::IShaderObjectLayout> gRootLayout;
ComPtr<gfx::IPipelineState> gPipelineState;
ComPtr<gfx::IShaderObject> gRootObject;
-
+ComPtr<gfx::ISwapchain> gSwapchain;
+List<ComPtr<gfx::IFramebuffer>> gFramebuffers;
ComPtr<gfx::IBufferResource> gVertexBuffer;
// Now that we've covered the function that actually loads and
@@ -242,9 +243,7 @@ Slang::Result initialize()
//
IRenderer::Desc rendererDesc = {};
rendererDesc.rendererType = gfx::RendererType::DirectX11;
- rendererDesc.width = gWindowWidth;
- rendererDesc.height = gWindowHeight;
- gfx::Result res = gfxCreateRenderer(&rendererDesc, getPlatformWindowHandle(gWindow), gRenderer.writeRef());
+ gfx::Result res = gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
if(SLANG_FAILED(res)) return res;
// Now we will create objects needed to configur the "input assembler"
@@ -311,15 +310,76 @@ Slang::Result initialize()
SLANG_RETURN_ON_FAIL(gRenderer->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;
+ gSwapchain = gRenderer->createSwapchain(
+ swapchainDesc, gfx::WindowHandle::FromHwnd(getPlatformWindowHandle(gWindow)));
+
+ 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(
+ gRenderer->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 = gRenderer->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 =
+ gRenderer->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 =
+ gRenderer->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 = gRenderer->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.renderTargetCount = 1;
+ desc.framebufferLayout = framebufferLayout;
auto pipelineState = gRenderer->createGraphicsPipelineState(desc);
- if(!pipelineState) return SLANG_FAIL;
+ if (!pipelineState)
+ return SLANG_FAIL;
gPipelineState = pipelineState;
@@ -338,6 +398,17 @@ Slang::Result initialize()
//
void renderFrame()
{
+ gRenderer->beginFrame();
+ uint32_t frameBufferIndex = gSwapchain->acquireNextImage();
+ gRenderer->setFramebuffer(gFramebuffers[frameBufferIndex]);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)gWindowWidth;
+ viewport.extentY = (float)gWindowHeight;
+ gRenderer->setViewportAndScissor(viewport);
+
+
// We start by clearing our framebuffer, which only has a color target.
//
static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
@@ -349,13 +420,15 @@ void renderFrame()
// basis, even though the data that is loaded does not change
// per-frame (we always use an identity matrix).
//
- static const float kIdentity[] =
+ float identityMatrix[] =
{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
+ gfxGetIdentityProjection(gfxGetProjectionStyle(gRenderer->getRendererType()), identityMatrix);
+
//
// We know that `gRootObject` is a root shader object created
// from our program, and that it is set up to hold values for
@@ -390,7 +463,7 @@ void renderFrame()
// Once we have formed a cursor that "points" at the
// model-view projection matrix, we can set its data directly.
//
- rootCursor["Uniforms"]["modelViewProjection"].setData(kIdentity, sizeof(kIdentity));
+ rootCursor["Uniforms"]["modelViewProjection"].setData(identityMatrix, sizeof(identityMatrix));
//
// Some readers might be concerned about the performance o
// the above operations because of the use of strings. For
@@ -427,14 +500,17 @@ void renderFrame()
// With that, we are done drawing for one frame, and ready for the next.
//
- gRenderer->presentFrame();
+ gRenderer->makeSwapchainImagePresentable(gSwapchain);
+
+ gRenderer->endFrame();
+
+ gSwapchain->present();
}
void finalize()
{
- // All of our graphics API objects are reference-counted,
- // so there isn't any additional cleanup work that needs
- // to be done in this simple example.
+ gRenderer->waitForGpu();
+ destroyWindow(gWindow);
}
};
diff --git a/examples/heterogeneous-hello-world/main.cpp b/examples/heterogeneous-hello-world/main.cpp
index ff44ecc45..010434bfa 100644
--- a/examples/heterogeneous-hello-world/main.cpp
+++ b/examples/heterogeneous-hello-world/main.cpp
@@ -124,9 +124,8 @@ gfx::IRenderer* createRenderer(
//
IRenderer::Desc rendererDesc = {};
rendererDesc.rendererType = gfx::RendererType::DirectX11;
- rendererDesc.width = windowWidth;
- rendererDesc.height = windowHeight;
- Result res = gfxCreateRenderer(&rendererDesc, getPlatformWindowHandle(window), gRenderer.writeRef());
+ Result res = gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
+
if (SLANG_FAILED(res)) return nullptr;
return gRenderer;
}
@@ -196,7 +195,7 @@ gfx::IDescriptorSet* buildDescriptorSet(
// Once we have the descriptor set layout, we can allocate
// and fill in a descriptor set to hold our parameters.
//
- gDescriptorSet = renderer->createDescriptorSet(descriptorSetLayout);
+ gDescriptorSet = renderer->createDescriptorSet(descriptorSetLayout, gfx::IDescriptorSet::Flag::Transient);
if(!gDescriptorSet) return nullptr;
// Once we have the bufferResource created, we can fill in
diff --git a/examples/model-viewer/main.cpp b/examples/model-viewer/main.cpp
index f18a2cc58..c9693e529 100644
--- a/examples/model-viewer/main.cpp
+++ b/examples/model-viewer/main.cpp
@@ -548,7 +548,7 @@ struct ParameterBlockEncoder
// A top-level encoder will unmap the underlying constant
// buffer (if any) when it goes out of scope.
//
- ~ParameterBlockEncoder();
+ void finishEncoding();
// The underlying descriptor set being filled in.
//
@@ -669,7 +669,7 @@ RefPtr<ParameterBlock> allocateParameterBlockImpl(
// resource parameters (including the primary constant buffer, if any).
//
auto descriptorSet = renderer->createDescriptorSet(
- layout->descriptorSetLayout);
+ layout->descriptorSetLayout, gfx::IDescriptorSet::Flag::Transient);
// If the parameter block has any ordinary data, then it requires
// a "primary" constant buffer to hold that data.
@@ -743,10 +743,7 @@ ParameterBlockEncoder ParameterBlock::beginEncoding()
return encoder;
}
-// When a "top-level" encoder goes out of scope,
-// we need to unmap the parameter block.
-//
-ParameterBlockEncoder::~ParameterBlockEncoder()
+void ParameterBlockEncoder::finishEncoding()
{
if (parameterBlock && uniformData)
{
@@ -801,7 +798,8 @@ struct EffectVariant : RefObject
RefPtr<EffectVariant> createEffectVaraint(
Effect* effect,
UInt parameterBlockCount,
- ParameterBlockLayout* const* parameterBlockLayouts)
+ ParameterBlockLayout* const* parameterBlockLayouts,
+ IFramebufferLayout* framebufferLayout)
{
// One note to make at the very start is that the creation
// of a specialized variant is based on the *layout* of
@@ -982,7 +980,7 @@ RefPtr<EffectVariant> createEffectVaraint(
pipelineStateDesc.program = specializedProgram;
pipelineStateDesc.pipelineLayout = pipelineLayout;
pipelineStateDesc.inputLayout = effect->inputLayout;
- pipelineStateDesc.renderTargetCount = effect->renderTargetCount;
+ pipelineStateDesc.framebufferLayout = framebufferLayout;
auto pipelineState = renderer->createGraphicsPipelineState(pipelineStateDesc);
RefPtr<EffectVariant> variant = new EffectVariant();
@@ -1040,7 +1038,8 @@ struct ShaderCache : RefObject
// on demand in case of a miss.
//
RefPtr<EffectVariant> getEffectVariant(
- VariantKey const& key)
+ VariantKey const& key,
+ IFramebufferLayout* framebufferLayout)
{
RefPtr<EffectVariant> variant;
if(variants.TryGetValue(key, variant))
@@ -1049,7 +1048,8 @@ struct ShaderCache : RefObject
variant = createEffectVaraint(
key.effect,
key.parameterBlockCount,
- key.parameterBlockLayouts);
+ key.parameterBlockLayouts,
+ framebufferLayout);
variants.Add(key, variant);
return variant;
@@ -1224,7 +1224,7 @@ public:
pipelineStateDirty = true;
}
- void flushState()
+ void flushState(IFramebufferLayout* framebufferLayout)
{
// The `flushState()` operation must be used by the application
// any time it binds a different effect or parameter block(s),
@@ -1248,7 +1248,7 @@ public:
// be present in the cache, and this function returns
// without much effort.
//
- auto variant = shaderCache->getEffectVariant(variantKey);
+ auto variant = shaderCache->getEffectVariant(variantKey, framebufferLayout);
// In order to adapt to a change in shader variant,
// we simply bind its PSO into the GPU state, and
@@ -1342,6 +1342,7 @@ struct SimpleMaterial : Material
encoder.writeField(0, diffuseColor);
encoder.writeField(1, specularColor);
encoder.writeField(2, specularity);
+ encoder.finishEncoding();
return parameterBlock;
}
@@ -1811,6 +1812,7 @@ struct LightEnv : public RefObject
ParameterBlockEncoder encoder = parameterBlock->beginEncoding();
fillInParameterBlock(encoder);
+ encoder.finishEncoding();
return parameterBlock;
}
@@ -1911,7 +1913,9 @@ struct ModelViewer {
Window* gWindow;
Slang::ComPtr<gfx::IRenderer> gRenderer;
-ComPtr<gfx::IResourceView> gDepthTarget;
+ComPtr<gfx::ISwapchain> gSwapchain;
+ComPtr<IFramebufferLayout> gFramebufferLayout;
+Slang::List<ComPtr<gfx::IFramebuffer>> gFramebuffers;
// We keep a pointer to the one effect we are using (for a forward
// rendering pass), plus the parameter-block layouts for our `PerView`
@@ -1946,6 +1950,7 @@ void loadAndAddModel(
int gWindowWidth = 1024;
int gWindowHeight = 768;
+const uint32_t kSwapchainImageCount = 2;
// Our "simulation" state consists of just a few values.
//
@@ -2052,9 +2057,7 @@ Result initialize()
IRenderer::Desc rendererDesc = {};
rendererDesc.rendererType = gfx::RendererType::DirectX11;
- rendererDesc.width = gWindowWidth;
- rendererDesc.height = gWindowHeight;
- gfxCreateRenderer(&rendererDesc, getPlatformWindowHandle(gWindow), gRenderer.writeRef());
+ gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
InputElementDesc inputElements[] = {
{"POSITION", 0, Format::RGB_Float32, offsetof(Model::Vertex, position) },
@@ -2066,23 +2069,64 @@ Result initialize()
3);
if(!inputLayout) return SLANG_FAIL;
- // Because we are rendering more than a single triangle this time, we
- // require a depth buffer to resolve visibility.
- //
- ITextureResource::Desc depthBufferDesc = gRenderer->getSwapChainTextureDesc();
- depthBufferDesc.format = Format::D_Float32;
- depthBufferDesc.setDefaults(IResource::Usage::DepthWrite);
- auto depthTexture = gRenderer->createTextureResource(
- IResource::Usage::DepthWrite,
- depthBufferDesc);
- if(!depthTexture) return SLANG_FAIL;
-
- IResourceView::Desc textureViewDesc;
- textureViewDesc.type = IResourceView::Type::DepthStencil;
- auto depthTarget = gRenderer->createTextureView(depthTexture, textureViewDesc);
- if (!depthTarget) return SLANG_FAIL;
-
- gDepthTarget = depthTarget;
+ // Create swapchain and framebuffers.
+ gfx::ISwapchain::Desc swapchainDesc = {};
+ swapchainDesc.format = gfx::Format::RGBA_Unorm_UInt8;
+ swapchainDesc.width = gWindowWidth;
+ swapchainDesc.height = gWindowHeight;
+ swapchainDesc.imageCount = kSwapchainImageCount;
+ gSwapchain = gRenderer->createSwapchain(
+ swapchainDesc, gfx::WindowHandle::FromHwnd(getPlatformWindowHandle(gWindow)));
+
+ 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(
+ gRenderer->createFramebufferLayout(framebufferLayoutDesc, gFramebufferLayout.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 = gRenderer->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 =
+ gRenderer->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 =
+ gRenderer->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 = gRenderer->createFramebuffer(framebufferDesc);
+ gFramebuffers.add(frameBuffer);
+ }
// Unlike the earlier example, we will not generate final shader kernel
// code during initialization. Instead, we simply load the shader module
@@ -2157,7 +2201,7 @@ Result initialize()
// We will do some GUI rendering in this app, using "Dear, IMGUI",
// so we need to do the appropriate initialization work here.
- gui = new GUI(gWindow, gRenderer);
+ gui = new GUI(gWindow, gRenderer, gFramebufferLayout);
showWindow(gWindow);
@@ -2170,6 +2214,7 @@ Result initialize()
//
void renderFrame()
{
+ gRenderer->beginFrame();
gui->beginFrame();
// In order to see that things are rendering properly we need some
@@ -2213,7 +2258,15 @@ void renderFrame()
// Some of the basic rendering setup is identical to the previous example.
//
- gRenderer->setDepthStencilTarget(gDepthTarget);
+ auto frameIndex = gSwapchain->acquireNextImage();
+ gRenderer->setFramebuffer(gFramebuffers[frameIndex]);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)gWindowWidth;
+ viewport.extentY = (float)gWindowHeight;
+ gRenderer->setViewportAndScissor(viewport);
+
static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
gRenderer->setClearColor(kClearColor);
gRenderer->clearFrame();
@@ -2245,6 +2298,7 @@ void renderFrame()
auto encoder = viewParameterBlock->beginEncoding();
encoder.writeField(0, viewProjection);
encoder.writeField(1, cameraPosition);
+ encoder.finishEncoding();
}
//
// Note: the assignment of indices to parameter blocks is driven
@@ -2288,6 +2342,7 @@ void renderFrame()
auto encoder = modelParameterBlock->beginEncoding();
encoder.writeField(0, modelTransform);
encoder.writeField(1, inverseTransposeModelTransform);
+ encoder.finishEncoding();
}
context.setParameterBlock(1, modelParameterBlock);
@@ -2321,7 +2376,7 @@ void renderFrame()
// material changed, a shader switch might be
// required).
//
- context.flushState();
+ context.flushState(gFramebufferLayout);
gRenderer->drawIndexed(mesh->indexCount, mesh->firstIndex);
}
@@ -2348,7 +2403,11 @@ void renderFrame()
ImGui::End();
gui->endFrame();
- gRenderer->presentFrame();
+
+ gRenderer->makeSwapchainImagePresentable(gSwapchain);
+ gRenderer->endFrame();
+ gSwapchain->present();
+
}
void finalize()
@@ -2359,7 +2418,9 @@ void finalize()
// that we aren't relying on C++ global destructors to tear
// down our application cleanly.
//
+ gRenderer->waitForGpu();
SimpleMaterial::gParameterBlockLayout = nullptr;
+ destroyWindow(gWindow);
}
};
diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp
index b61cf30e4..9b1b4de72 100644
--- a/examples/shader-object/main.cpp
+++ b/examples/shader-object/main.cpp
@@ -137,7 +137,7 @@ int main()
Slang::ComPtr<gfx::IRenderer> renderer;
IRenderer::Desc rendererDesc = {};
rendererDesc.rendererType = RendererType::CUDA;
- SLANG_RETURN_ON_FAIL(gfxCreateRenderer(&rendererDesc, nullptr, renderer.writeRef()));
+ SLANG_RETURN_ON_FAIL(gfxCreateRenderer(&rendererDesc, renderer.writeRef()));
// Now we can load the shader code.
// A `gfx::IShaderProgram` object for use in the `gfx` layer.
@@ -211,10 +211,11 @@ int main()
// We have set up all required parameters in entry-point object, now it is time
// to bind the pipeline and root object and launch the kernel.
+ renderer->beginFrame();
renderer->setPipelineState(pipelineState);
SLANG_RETURN_ON_FAIL(renderer->bindRootShaderObject(gfx::PipelineType::Compute, rootObject));
renderer->dispatchCompute(1, 1, 1);
-
+ renderer->endFrame();
// Read back the results.
renderer->waitForGpu();
float* result = (float*)renderer->map(numbersBuffer, gfx::MapFlavor::HostRead);
diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp
index 89aa74ccb..697bb1044 100644
--- a/examples/shader-toy/main.cpp
+++ b/examples/shader-toy/main.cpp
@@ -327,6 +327,7 @@ Result loadShaderProgram(gfx::IRenderer* renderer, ComPtr<gfx::IShaderProgram>&
int gWindowWidth = 1024;
int gWindowHeight = 768;
+const uint32_t kSwapchainImageCount = 2;
gfx::ApplicationContext* gAppContext;
gfx::Window* gWindow;
@@ -336,6 +337,8 @@ ComPtr<gfx::IPipelineLayout> gPipelineLayout;
ComPtr<gfx::IPipelineState> gPipelineState;
ComPtr<gfx::IDescriptorSet> gDescriptorSet;
ComPtr<gfx::IBufferResource> gVertexBuffer;
+ComPtr<gfx::ISwapchain> gSwapchain;
+Slang::List<ComPtr<gfx::IFramebuffer>> gFramebuffers;
Result initialize()
{
@@ -349,9 +352,7 @@ Result initialize()
IRenderer::Desc rendererDesc;
rendererDesc.rendererType = RendererType::DirectX11;
- rendererDesc.width = gWindowWidth;
- rendererDesc.height = gWindowHeight;
- Result res = gfxCreateRenderer(&rendererDesc, getPlatformWindowHandle(gWindow), gRenderer.writeRef());
+ Result res = gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
if(SLANG_FAILED(res)) return res;
int constantBufferSize = sizeof(Uniforms);
@@ -409,20 +410,82 @@ Result initialize()
gPipelineLayout = pipelineLayout;
- auto descriptorSet = gRenderer->createDescriptorSet(descriptorSetLayout);
+ auto descriptorSet = gRenderer->createDescriptorSet(descriptorSetLayout, IDescriptorSet::Flag::Transient);
if(!descriptorSet) return SLANG_FAIL;
descriptorSet->setConstantBuffer(0, 0, gConstantBuffer);
gDescriptorSet = descriptorSet;
+ // Create swapchain and framebuffers.
+ gfx::ISwapchain::Desc swapchainDesc = {};
+ swapchainDesc.format = gfx::Format::RGBA_Unorm_UInt8;
+ swapchainDesc.width = gWindowWidth;
+ swapchainDesc.height = gWindowHeight;
+ swapchainDesc.imageCount = kSwapchainImageCount;
+ gSwapchain = gRenderer->createSwapchain(
+ swapchainDesc, gfx::WindowHandle::FromHwnd(getPlatformWindowHandle(gWindow)));
+
+ 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(
+ gRenderer->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 = gRenderer->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 =
+ gRenderer->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 =
+ gRenderer->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 = gRenderer->createFramebuffer(framebufferDesc);
+ gFramebuffers.add(frameBuffer);
+ }
+
+ // Create pipeline.
GraphicsPipelineStateDesc desc;
- desc.pipelineLayout = gPipelineLayout;
desc.inputLayout = inputLayout;
desc.program = shaderProgram;
- desc.renderTargetCount = 1;
+ desc.framebufferLayout = framebufferLayout;
+ desc.pipelineLayout = pipelineLayout;
auto pipelineState = gRenderer->createGraphicsPipelineState(desc);
- if(!pipelineState) return SLANG_FAIL;
+ if (!pipelineState)
+ return SLANG_FAIL;
gPipelineState = pipelineState;
@@ -443,12 +506,21 @@ uint64_t startTime = 0;
void renderFrame()
{
+ gRenderer->beginFrame();
+ auto frameIndex = gSwapchain->acquireNextImage();
+ gRenderer->setFramebuffer(gFramebuffers[frameIndex]);
if( firstTime )
{
startTime = getCurrentTime();
firstTime = false;
}
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)gWindowWidth;
+ viewport.extentY = (float)gWindowHeight;
+ gRenderer->setViewportAndScissor(viewport);
+
static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
gRenderer->setClearColor(kClearColor);
gRenderer->clearFrame();
@@ -483,10 +555,18 @@ void renderFrame()
gRenderer->draw(3);
- gRenderer->presentFrame();
+ gRenderer->makeSwapchainImagePresentable(gSwapchain);
+
+ gRenderer->endFrame();
+
+ gSwapchain->present();
}
-void finalize() { destroyWindow(gWindow); }
+void finalize()
+{
+ gRenderer->waitForGpu();
+ destroyWindow(gWindow);
+}
void handleEvent(Event const& event)
{