diff options
| author | Yong He <yonghe@outlook.com> | 2021-02-24 15:43:43 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-24 15:43:43 -0800 |
| commit | 9b7a007c31072bc9aebd1134aa4f1bfd28a4c541 (patch) | |
| tree | b71a48eb30b3b09ab4e77e40dc1c68ecd854ef82 /examples | |
| parent | d66b30729029bdb43892e05c9c80fd56ac95a24f (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.cpp | 13 | ||||
| -rw-r--r-- | examples/hello-world/main.cpp | 102 | ||||
| -rw-r--r-- | examples/heterogeneous-hello-world/main.cpp | 7 | ||||
| -rw-r--r-- | examples/model-viewer/main.cpp | 135 | ||||
| -rw-r--r-- | examples/shader-object/main.cpp | 5 | ||||
| -rw-r--r-- | examples/shader-toy/main.cpp | 98 |
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) { |
