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 | |
| 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.
42 files changed, 4063 insertions, 1669 deletions
diff --git a/build/visual-studio/core/core.vcxproj b/build/visual-studio/core/core.vcxproj index 2bf02ecdd..01a7e3eb2 100644 --- a/build/visual-studio/core/core.vcxproj +++ b/build/visual-studio/core/core.vcxproj @@ -219,6 +219,7 @@ <ClInclude Include="..\..\..\source\core\slang-type-text-util.h" /> <ClInclude Include="..\..\..\source\core\slang-type-traits.h" /> <ClInclude Include="..\..\..\source\core\slang-uint-set.h" /> + <ClInclude Include="..\..\..\source\core\slang-virtual-object-pool.h" /> <ClInclude Include="..\..\..\source\core\slang-visual-studio-compiler-util.h" /> <ClInclude Include="..\..\..\source\core\slang-writer.h" /> <ClInclude Include="..\..\..\source\core\slang-zip-file-system.h" /> diff --git a/build/visual-studio/core/core.vcxproj.filters b/build/visual-studio/core/core.vcxproj.filters index 99cc6ba6a..3c2a7371d 100644 --- a/build/visual-studio/core/core.vcxproj.filters +++ b/build/visual-studio/core/core.vcxproj.filters @@ -156,6 +156,9 @@ <ClInclude Include="..\..\..\source\core\slang-uint-set.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\core\slang-virtual-object-pool.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\source\core\slang-visual-studio-compiler-util.h"> <Filter>Header Files</Filter> </ClInclude> diff --git a/build/visual-studio/gfx/gfx.vcxproj b/build/visual-studio/gfx/gfx.vcxproj index 91c6a9441..0968e8c6c 100644 --- a/build/visual-studio/gfx/gfx.vcxproj +++ b/build/visual-studio/gfx/gfx.vcxproj @@ -196,6 +196,7 @@ <ClInclude Include="..\..\..\tools\gfx\slang-context.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\render-vk.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-api.h" /> + <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-descriptor-allocator.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-device-queue.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-module.h" /> <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-swap-chain.h" /> @@ -217,6 +218,7 @@ <ClCompile Include="..\..\..\tools\gfx\renderer-shared.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\render-vk.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-api.cpp" /> + <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-descriptor-allocator.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-device-queue.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-module.cpp" /> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-swap-chain.cpp" /> diff --git a/build/visual-studio/gfx/gfx.vcxproj.filters b/build/visual-studio/gfx/gfx.vcxproj.filters index cf800961a..1dc6581d6 100644 --- a/build/visual-studio/gfx/gfx.vcxproj.filters +++ b/build/visual-studio/gfx/gfx.vcxproj.filters @@ -60,6 +60,9 @@ <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-api.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-descriptor-allocator.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="..\..\..\tools\gfx\vulkan\vk-device-queue.h"> <Filter>Header Files</Filter> </ClInclude> @@ -119,6 +122,9 @@ <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-api.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-descriptor-allocator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\..\..\tools\gfx\vulkan\vk-device-queue.cpp"> <Filter>Source Files</Filter> </ClCompile> 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) { diff --git a/external/wglext.h b/external/wglext.h new file mode 100644 index 000000000..a25543ad8 --- /dev/null +++ b/external/wglext.h @@ -0,0 +1,1056 @@ +#ifndef __wgl_wglext_h_ +#define __wgl_wglext_h_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* + ** Copyright 2013-2020 The Khronos Group Inc. + ** SPDX-License-Identifier: MIT + ** + ** This header is generated from the Khronos OpenGL / OpenGL ES XML + ** API Registry. The current version of the Registry, generator scripts + ** used to make the header, and the header can be found at + ** https://github.com/KhronosGroup/OpenGL-Registry + */ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +# define WIN32_LEAN_AND_MEAN 1 +# include <windows.h> +#endif + +#define WGL_WGLEXT_VERSION 20200813 + + /* Generated C header for: + * API: wgl + * Versions considered: .* + * Versions emitted: _nomatch_^ + * Default extensions included: wgl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef WGL_ARB_buffer_region +# define WGL_ARB_buffer_region 1 +# define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +# define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +# define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +# define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 + typedef HANDLE(WINAPI* PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC, int iLayerPlane, UINT uType); + typedef VOID(WINAPI* PFNWGLDELETEBUFFERREGIONARBPROC)(HANDLE hRegion); + typedef BOOL(WINAPI* PFNWGLSAVEBUFFERREGIONARBPROC)( + HANDLE hRegion, int x, int y, int width, int height); + typedef BOOL(WINAPI* PFNWGLRESTOREBUFFERREGIONARBPROC)( + HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +# ifdef WGL_WGLEXT_PROTOTYPES + HANDLE WINAPI wglCreateBufferRegionARB(HDC hDC, int iLayerPlane, UINT uType); + VOID WINAPI wglDeleteBufferRegionARB(HANDLE hRegion); + BOOL WINAPI wglSaveBufferRegionARB(HANDLE hRegion, int x, int y, int width, int height); + BOOL WINAPI wglRestoreBufferRegionARB( + HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +# endif +#endif /* WGL_ARB_buffer_region */ + +#ifndef WGL_ARB_context_flush_control +# define WGL_ARB_context_flush_control 1 +# define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +# define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +# define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif /* WGL_ARB_context_flush_control */ + +#ifndef WGL_ARB_create_context +# define WGL_ARB_create_context 1 +# define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +# define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +# define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +# define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +# define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +# define WGL_CONTEXT_FLAGS_ARB 0x2094 +# define ERROR_INVALID_VERSION_ARB 0x2095 + typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)( + HDC hDC, HGLRC hShareContext, const int* attribList); +# ifdef WGL_WGLEXT_PROTOTYPES + HGLRC WINAPI wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int* attribList); +# endif +#endif /* WGL_ARB_create_context */ + +#ifndef WGL_ARB_create_context_no_error +# define WGL_ARB_create_context_no_error 1 +# define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 +#endif /* WGL_ARB_create_context_no_error */ + +#ifndef WGL_ARB_create_context_profile +# define WGL_ARB_create_context_profile 1 +# define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +# define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +# define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +# define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif /* WGL_ARB_create_context_profile */ + +#ifndef WGL_ARB_create_context_robustness +# define WGL_ARB_create_context_robustness 1 +# define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +# define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +# define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +# define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* WGL_ARB_create_context_robustness */ + +#ifndef WGL_ARB_extensions_string +# define WGL_ARB_extensions_string 1 + typedef const char*(WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); +# ifdef WGL_WGLEXT_PROTOTYPES + const char* WINAPI wglGetExtensionsStringARB(HDC hdc); +# endif +#endif /* WGL_ARB_extensions_string */ + +#ifndef WGL_ARB_framebuffer_sRGB +# define WGL_ARB_framebuffer_sRGB 1 +# define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif /* WGL_ARB_framebuffer_sRGB */ + +#ifndef WGL_ARB_make_current_read +# define WGL_ARB_make_current_read 1 +# define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +# define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 + typedef BOOL(WINAPI* PFNWGLMAKECONTEXTCURRENTARBPROC)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + typedef HDC(WINAPI* PFNWGLGETCURRENTREADDCARBPROC)(void); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC WINAPI wglGetCurrentReadDCARB(void); +# endif +#endif /* WGL_ARB_make_current_read */ + +#ifndef WGL_ARB_multisample +# define WGL_ARB_multisample 1 +# define WGL_SAMPLE_BUFFERS_ARB 0x2041 +# define WGL_SAMPLES_ARB 0x2042 +#endif /* WGL_ARB_multisample */ + +#ifndef WGL_ARB_pbuffer +# define WGL_ARB_pbuffer 1 + DECLARE_HANDLE(HPBUFFERARB); +# define WGL_DRAW_TO_PBUFFER_ARB 0x202D +# define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +# define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +# define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +# define WGL_PBUFFER_LARGEST_ARB 0x2033 +# define WGL_PBUFFER_WIDTH_ARB 0x2034 +# define WGL_PBUFFER_HEIGHT_ARB 0x2035 +# define WGL_PBUFFER_LOST_ARB 0x2036 + typedef HPBUFFERARB(WINAPI* PFNWGLCREATEPBUFFERARBPROC)( + HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); + typedef HDC(WINAPI* PFNWGLGETPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer); + typedef int(WINAPI* PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer, HDC hDC); + typedef BOOL(WINAPI* PFNWGLDESTROYPBUFFERARBPROC)(HPBUFFERARB hPbuffer); + typedef BOOL(WINAPI* PFNWGLQUERYPBUFFERARBPROC)( + HPBUFFERARB hPbuffer, int iAttribute, int* piValue); +# ifdef WGL_WGLEXT_PROTOTYPES + HPBUFFERARB WINAPI wglCreatePbufferARB( + HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); + HDC WINAPI wglGetPbufferDCARB(HPBUFFERARB hPbuffer); + int WINAPI wglReleasePbufferDCARB(HPBUFFERARB hPbuffer, HDC hDC); + BOOL WINAPI wglDestroyPbufferARB(HPBUFFERARB hPbuffer); + BOOL WINAPI wglQueryPbufferARB(HPBUFFERARB hPbuffer, int iAttribute, int* piValue); +# endif +#endif /* WGL_ARB_pbuffer */ + +#ifndef WGL_ARB_pixel_format +# define WGL_ARB_pixel_format 1 +# define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +# define WGL_DRAW_TO_WINDOW_ARB 0x2001 +# define WGL_DRAW_TO_BITMAP_ARB 0x2002 +# define WGL_ACCELERATION_ARB 0x2003 +# define WGL_NEED_PALETTE_ARB 0x2004 +# define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +# define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +# define WGL_SWAP_METHOD_ARB 0x2007 +# define WGL_NUMBER_OVERLAYS_ARB 0x2008 +# define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +# define WGL_TRANSPARENT_ARB 0x200A +# define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +# define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +# define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +# define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +# define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +# define WGL_SHARE_DEPTH_ARB 0x200C +# define WGL_SHARE_STENCIL_ARB 0x200D +# define WGL_SHARE_ACCUM_ARB 0x200E +# define WGL_SUPPORT_GDI_ARB 0x200F +# define WGL_SUPPORT_OPENGL_ARB 0x2010 +# define WGL_DOUBLE_BUFFER_ARB 0x2011 +# define WGL_STEREO_ARB 0x2012 +# define WGL_PIXEL_TYPE_ARB 0x2013 +# define WGL_COLOR_BITS_ARB 0x2014 +# define WGL_RED_BITS_ARB 0x2015 +# define WGL_RED_SHIFT_ARB 0x2016 +# define WGL_GREEN_BITS_ARB 0x2017 +# define WGL_GREEN_SHIFT_ARB 0x2018 +# define WGL_BLUE_BITS_ARB 0x2019 +# define WGL_BLUE_SHIFT_ARB 0x201A +# define WGL_ALPHA_BITS_ARB 0x201B +# define WGL_ALPHA_SHIFT_ARB 0x201C +# define WGL_ACCUM_BITS_ARB 0x201D +# define WGL_ACCUM_RED_BITS_ARB 0x201E +# define WGL_ACCUM_GREEN_BITS_ARB 0x201F +# define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +# define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +# define WGL_DEPTH_BITS_ARB 0x2022 +# define WGL_STENCIL_BITS_ARB 0x2023 +# define WGL_AUX_BUFFERS_ARB 0x2024 +# define WGL_NO_ACCELERATION_ARB 0x2025 +# define WGL_GENERIC_ACCELERATION_ARB 0x2026 +# define WGL_FULL_ACCELERATION_ARB 0x2027 +# define WGL_SWAP_EXCHANGE_ARB 0x2028 +# define WGL_SWAP_COPY_ARB 0x2029 +# define WGL_SWAP_UNDEFINED_ARB 0x202A +# define WGL_TYPE_RGBA_ARB 0x202B +# define WGL_TYPE_COLORINDEX_ARB 0x202C + typedef BOOL(WINAPI* PFNWGLGETPIXELFORMATATTRIBIVARBPROC)( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int* piAttributes, + int* piValues); + typedef BOOL(WINAPI* PFNWGLGETPIXELFORMATATTRIBFVARBPROC)( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int* piAttributes, + FLOAT* pfValues); + typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)( + HDC hdc, + const int* piAttribIList, + const FLOAT* pfAttribFList, + UINT nMaxFormats, + int* piFormats, + UINT* nNumFormats); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetPixelFormatAttribivARB( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int* piAttributes, + int* piValues); + BOOL WINAPI wglGetPixelFormatAttribfvARB( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int* piAttributes, + FLOAT* pfValues); + BOOL WINAPI wglChoosePixelFormatARB( + HDC hdc, + const int* piAttribIList, + const FLOAT* pfAttribFList, + UINT nMaxFormats, + int* piFormats, + UINT* nNumFormats); +# endif +#endif /* WGL_ARB_pixel_format */ + +#ifndef WGL_ARB_pixel_format_float +# define WGL_ARB_pixel_format_float 1 +# define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif /* WGL_ARB_pixel_format_float */ + +#ifndef WGL_ARB_render_texture +# define WGL_ARB_render_texture 1 +# define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +# define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +# define WGL_TEXTURE_FORMAT_ARB 0x2072 +# define WGL_TEXTURE_TARGET_ARB 0x2073 +# define WGL_MIPMAP_TEXTURE_ARB 0x2074 +# define WGL_TEXTURE_RGB_ARB 0x2075 +# define WGL_TEXTURE_RGBA_ARB 0x2076 +# define WGL_NO_TEXTURE_ARB 0x2077 +# define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +# define WGL_TEXTURE_1D_ARB 0x2079 +# define WGL_TEXTURE_2D_ARB 0x207A +# define WGL_MIPMAP_LEVEL_ARB 0x207B +# define WGL_CUBE_MAP_FACE_ARB 0x207C +# define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +# define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +# define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +# define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +# define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +# define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +# define WGL_FRONT_LEFT_ARB 0x2083 +# define WGL_FRONT_RIGHT_ARB 0x2084 +# define WGL_BACK_LEFT_ARB 0x2085 +# define WGL_BACK_RIGHT_ARB 0x2086 +# define WGL_AUX0_ARB 0x2087 +# define WGL_AUX1_ARB 0x2088 +# define WGL_AUX2_ARB 0x2089 +# define WGL_AUX3_ARB 0x208A +# define WGL_AUX4_ARB 0x208B +# define WGL_AUX5_ARB 0x208C +# define WGL_AUX6_ARB 0x208D +# define WGL_AUX7_ARB 0x208E +# define WGL_AUX8_ARB 0x208F +# define WGL_AUX9_ARB 0x2090 + typedef BOOL(WINAPI* PFNWGLBINDTEXIMAGEARBPROC)(HPBUFFERARB hPbuffer, int iBuffer); + typedef BOOL(WINAPI* PFNWGLRELEASETEXIMAGEARBPROC)(HPBUFFERARB hPbuffer, int iBuffer); + typedef BOOL(WINAPI* PFNWGLSETPBUFFERATTRIBARBPROC)( + HPBUFFERARB hPbuffer, const int* piAttribList); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglBindTexImageARB(HPBUFFERARB hPbuffer, int iBuffer); + BOOL WINAPI wglReleaseTexImageARB(HPBUFFERARB hPbuffer, int iBuffer); + BOOL WINAPI wglSetPbufferAttribARB(HPBUFFERARB hPbuffer, const int* piAttribList); +# endif +#endif /* WGL_ARB_render_texture */ + +#ifndef WGL_ARB_robustness_application_isolation +# define WGL_ARB_robustness_application_isolation 1 +# define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifndef WGL_ARB_robustness_share_group_isolation +# define WGL_ARB_robustness_share_group_isolation 1 +#endif /* WGL_ARB_robustness_share_group_isolation */ + +#ifndef WGL_3DFX_multisample +# define WGL_3DFX_multisample 1 +# define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +# define WGL_SAMPLES_3DFX 0x2061 +#endif /* WGL_3DFX_multisample */ + +#ifndef WGL_3DL_stereo_control +# define WGL_3DL_stereo_control 1 +# define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +# define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +# define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +# define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 + typedef BOOL(WINAPI* PFNWGLSETSTEREOEMITTERSTATE3DLPROC)(HDC hDC, UINT uState); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglSetStereoEmitterState3DL(HDC hDC, UINT uState); +# endif +#endif /* WGL_3DL_stereo_control */ + +#ifndef WGL_AMD_gpu_association +# define WGL_AMD_gpu_association 1 +# define WGL_GPU_VENDOR_AMD 0x1F00 +# define WGL_GPU_RENDERER_STRING_AMD 0x1F01 +# define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +# define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +# define WGL_GPU_RAM_AMD 0x21A3 +# define WGL_GPU_CLOCK_AMD 0x21A4 +# define WGL_GPU_NUM_PIPES_AMD 0x21A5 +# define WGL_GPU_NUM_SIMD_AMD 0x21A6 +# define WGL_GPU_NUM_RB_AMD 0x21A7 +# define WGL_GPU_NUM_SPI_AMD 0x21A8 + typedef UINT(WINAPI* PFNWGLGETGPUIDSAMDPROC)(UINT maxCount, UINT* ids); + typedef INT(WINAPI* PFNWGLGETGPUINFOAMDPROC)( + UINT id, INT property, GLenum dataType, UINT size, void* data); + typedef UINT(WINAPI* PFNWGLGETCONTEXTGPUIDAMDPROC)(HGLRC hglrc); + typedef HGLRC(WINAPI* PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC)(UINT id); + typedef HGLRC(WINAPI* PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC)( + UINT id, HGLRC hShareContext, const int* attribList); + typedef BOOL(WINAPI* PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC)(HGLRC hglrc); + typedef BOOL(WINAPI* PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC)(HGLRC hglrc); + typedef HGLRC(WINAPI* PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC)(void); + typedef VOID(WINAPI* PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC)( + HGLRC dstCtx, + GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter); +# ifdef WGL_WGLEXT_PROTOTYPES + UINT WINAPI wglGetGPUIDsAMD(UINT maxCount, UINT* ids); + INT WINAPI wglGetGPUInfoAMD(UINT id, INT property, GLenum dataType, UINT size, void* data); + UINT WINAPI wglGetContextGPUIDAMD(HGLRC hglrc); + HGLRC WINAPI wglCreateAssociatedContextAMD(UINT id); + HGLRC WINAPI + wglCreateAssociatedContextAttribsAMD(UINT id, HGLRC hShareContext, const int* attribList); + BOOL WINAPI wglDeleteAssociatedContextAMD(HGLRC hglrc); + BOOL WINAPI wglMakeAssociatedContextCurrentAMD(HGLRC hglrc); + HGLRC WINAPI wglGetCurrentAssociatedContextAMD(void); + VOID WINAPI wglBlitContextFramebufferAMD( + HGLRC dstCtx, + GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter); +# endif +#endif /* WGL_AMD_gpu_association */ + +#ifndef WGL_ATI_pixel_format_float +# define WGL_ATI_pixel_format_float 1 +# define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif /* WGL_ATI_pixel_format_float */ + +#ifndef WGL_ATI_render_texture_rectangle +# define WGL_ATI_render_texture_rectangle 1 +# define WGL_TEXTURE_RECTANGLE_ATI 0x21A5 +#endif /* WGL_ATI_render_texture_rectangle */ + +#ifndef WGL_EXT_colorspace +# define WGL_EXT_colorspace 1 +# define WGL_COLORSPACE_EXT 0x309D +# define WGL_COLORSPACE_SRGB_EXT 0x3089 +# define WGL_COLORSPACE_LINEAR_EXT 0x308A +#endif /* WGL_EXT_colorspace */ + +#ifndef WGL_EXT_create_context_es2_profile +# define WGL_EXT_create_context_es2_profile 1 +# define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es2_profile */ + +#ifndef WGL_EXT_create_context_es_profile +# define WGL_EXT_create_context_es_profile 1 +# define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es_profile */ + +#ifndef WGL_EXT_depth_float +# define WGL_EXT_depth_float 1 +# define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif /* WGL_EXT_depth_float */ + +#ifndef WGL_EXT_display_color_table +# define WGL_EXT_display_color_table 1 + typedef GLboolean(WINAPI* PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC)(GLushort id); + typedef GLboolean(WINAPI* PFNWGLLOADDISPLAYCOLORTABLEEXTPROC)( + const GLushort* table, GLuint length); + typedef GLboolean(WINAPI* PFNWGLBINDDISPLAYCOLORTABLEEXTPROC)(GLushort id); + typedef VOID(WINAPI* PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC)(GLushort id); +# ifdef WGL_WGLEXT_PROTOTYPES + GLboolean WINAPI wglCreateDisplayColorTableEXT(GLushort id); + GLboolean WINAPI wglLoadDisplayColorTableEXT(const GLushort* table, GLuint length); + GLboolean WINAPI wglBindDisplayColorTableEXT(GLushort id); + VOID WINAPI wglDestroyDisplayColorTableEXT(GLushort id); +# endif +#endif /* WGL_EXT_display_color_table */ + +#ifndef WGL_EXT_extensions_string +# define WGL_EXT_extensions_string 1 + typedef const char*(WINAPI* PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); +# ifdef WGL_WGLEXT_PROTOTYPES + const char* WINAPI wglGetExtensionsStringEXT(void); +# endif +#endif /* WGL_EXT_extensions_string */ + +#ifndef WGL_EXT_framebuffer_sRGB +# define WGL_EXT_framebuffer_sRGB 1 +# define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif /* WGL_EXT_framebuffer_sRGB */ + +#ifndef WGL_EXT_make_current_read +# define WGL_EXT_make_current_read 1 +# define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 + typedef BOOL(WINAPI* PFNWGLMAKECONTEXTCURRENTEXTPROC)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + typedef HDC(WINAPI* PFNWGLGETCURRENTREADDCEXTPROC)(void); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglMakeContextCurrentEXT(HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC WINAPI wglGetCurrentReadDCEXT(void); +# endif +#endif /* WGL_EXT_make_current_read */ + +#ifndef WGL_EXT_multisample +# define WGL_EXT_multisample 1 +# define WGL_SAMPLE_BUFFERS_EXT 0x2041 +# define WGL_SAMPLES_EXT 0x2042 +#endif /* WGL_EXT_multisample */ + +#ifndef WGL_EXT_pbuffer +# define WGL_EXT_pbuffer 1 + DECLARE_HANDLE(HPBUFFEREXT); +# define WGL_DRAW_TO_PBUFFER_EXT 0x202D +# define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +# define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +# define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +# define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +# define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +# define WGL_PBUFFER_LARGEST_EXT 0x2033 +# define WGL_PBUFFER_WIDTH_EXT 0x2034 +# define WGL_PBUFFER_HEIGHT_EXT 0x2035 + typedef HPBUFFEREXT(WINAPI* PFNWGLCREATEPBUFFEREXTPROC)( + HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); + typedef HDC(WINAPI* PFNWGLGETPBUFFERDCEXTPROC)(HPBUFFEREXT hPbuffer); + typedef int(WINAPI* PFNWGLRELEASEPBUFFERDCEXTPROC)(HPBUFFEREXT hPbuffer, HDC hDC); + typedef BOOL(WINAPI* PFNWGLDESTROYPBUFFEREXTPROC)(HPBUFFEREXT hPbuffer); + typedef BOOL(WINAPI* PFNWGLQUERYPBUFFEREXTPROC)( + HPBUFFEREXT hPbuffer, int iAttribute, int* piValue); +# ifdef WGL_WGLEXT_PROTOTYPES + HPBUFFEREXT WINAPI wglCreatePbufferEXT( + HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); + HDC WINAPI wglGetPbufferDCEXT(HPBUFFEREXT hPbuffer); + int WINAPI wglReleasePbufferDCEXT(HPBUFFEREXT hPbuffer, HDC hDC); + BOOL WINAPI wglDestroyPbufferEXT(HPBUFFEREXT hPbuffer); + BOOL WINAPI wglQueryPbufferEXT(HPBUFFEREXT hPbuffer, int iAttribute, int* piValue); +# endif +#endif /* WGL_EXT_pbuffer */ + +#ifndef WGL_EXT_pixel_format +# define WGL_EXT_pixel_format 1 +# define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +# define WGL_DRAW_TO_WINDOW_EXT 0x2001 +# define WGL_DRAW_TO_BITMAP_EXT 0x2002 +# define WGL_ACCELERATION_EXT 0x2003 +# define WGL_NEED_PALETTE_EXT 0x2004 +# define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +# define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +# define WGL_SWAP_METHOD_EXT 0x2007 +# define WGL_NUMBER_OVERLAYS_EXT 0x2008 +# define WGL_NUMBER_UNDERLAYS_EXT 0x2009 +# define WGL_TRANSPARENT_EXT 0x200A +# define WGL_TRANSPARENT_VALUE_EXT 0x200B +# define WGL_SHARE_DEPTH_EXT 0x200C +# define WGL_SHARE_STENCIL_EXT 0x200D +# define WGL_SHARE_ACCUM_EXT 0x200E +# define WGL_SUPPORT_GDI_EXT 0x200F +# define WGL_SUPPORT_OPENGL_EXT 0x2010 +# define WGL_DOUBLE_BUFFER_EXT 0x2011 +# define WGL_STEREO_EXT 0x2012 +# define WGL_PIXEL_TYPE_EXT 0x2013 +# define WGL_COLOR_BITS_EXT 0x2014 +# define WGL_RED_BITS_EXT 0x2015 +# define WGL_RED_SHIFT_EXT 0x2016 +# define WGL_GREEN_BITS_EXT 0x2017 +# define WGL_GREEN_SHIFT_EXT 0x2018 +# define WGL_BLUE_BITS_EXT 0x2019 +# define WGL_BLUE_SHIFT_EXT 0x201A +# define WGL_ALPHA_BITS_EXT 0x201B +# define WGL_ALPHA_SHIFT_EXT 0x201C +# define WGL_ACCUM_BITS_EXT 0x201D +# define WGL_ACCUM_RED_BITS_EXT 0x201E +# define WGL_ACCUM_GREEN_BITS_EXT 0x201F +# define WGL_ACCUM_BLUE_BITS_EXT 0x2020 +# define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +# define WGL_DEPTH_BITS_EXT 0x2022 +# define WGL_STENCIL_BITS_EXT 0x2023 +# define WGL_AUX_BUFFERS_EXT 0x2024 +# define WGL_NO_ACCELERATION_EXT 0x2025 +# define WGL_GENERIC_ACCELERATION_EXT 0x2026 +# define WGL_FULL_ACCELERATION_EXT 0x2027 +# define WGL_SWAP_EXCHANGE_EXT 0x2028 +# define WGL_SWAP_COPY_EXT 0x2029 +# define WGL_SWAP_UNDEFINED_EXT 0x202A +# define WGL_TYPE_RGBA_EXT 0x202B +# define WGL_TYPE_COLORINDEX_EXT 0x202C + typedef BOOL(WINAPI* PFNWGLGETPIXELFORMATATTRIBIVEXTPROC)( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + int* piAttributes, + int* piValues); + typedef BOOL(WINAPI* PFNWGLGETPIXELFORMATATTRIBFVEXTPROC)( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + int* piAttributes, + FLOAT* pfValues); + typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATEXTPROC)( + HDC hdc, + const int* piAttribIList, + const FLOAT* pfAttribFList, + UINT nMaxFormats, + int* piFormats, + UINT* nNumFormats); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetPixelFormatAttribivEXT( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + int* piAttributes, + int* piValues); + BOOL WINAPI wglGetPixelFormatAttribfvEXT( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + int* piAttributes, + FLOAT* pfValues); + BOOL WINAPI wglChoosePixelFormatEXT( + HDC hdc, + const int* piAttribIList, + const FLOAT* pfAttribFList, + UINT nMaxFormats, + int* piFormats, + UINT* nNumFormats); +# endif +#endif /* WGL_EXT_pixel_format */ + +#ifndef WGL_EXT_pixel_format_packed_float +# define WGL_EXT_pixel_format_packed_float 1 +# define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif /* WGL_EXT_pixel_format_packed_float */ + +#ifndef WGL_EXT_swap_control +# define WGL_EXT_swap_control 1 + typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval); + typedef int(WINAPI* PFNWGLGETSWAPINTERVALEXTPROC)(void); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglSwapIntervalEXT(int interval); + int WINAPI wglGetSwapIntervalEXT(void); +# endif +#endif /* WGL_EXT_swap_control */ + +#ifndef WGL_EXT_swap_control_tear +# define WGL_EXT_swap_control_tear 1 +#endif /* WGL_EXT_swap_control_tear */ + +#ifndef WGL_I3D_digital_video_control +# define WGL_I3D_digital_video_control 1 +# define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +# define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +# define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +# define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 + typedef BOOL(WINAPI* PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC)( + HDC hDC, int iAttribute, int* piValue); + typedef BOOL(WINAPI* PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC)( + HDC hDC, int iAttribute, const int* piValue); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetDigitalVideoParametersI3D(HDC hDC, int iAttribute, int* piValue); + BOOL WINAPI wglSetDigitalVideoParametersI3D(HDC hDC, int iAttribute, const int* piValue); +# endif +#endif /* WGL_I3D_digital_video_control */ + +#ifndef WGL_I3D_gamma +# define WGL_I3D_gamma 1 +# define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +# define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F + typedef BOOL(WINAPI* PFNWGLGETGAMMATABLEPARAMETERSI3DPROC)( + HDC hDC, int iAttribute, int* piValue); + typedef BOOL(WINAPI* PFNWGLSETGAMMATABLEPARAMETERSI3DPROC)( + HDC hDC, int iAttribute, const int* piValue); + typedef BOOL(WINAPI* PFNWGLGETGAMMATABLEI3DPROC)( + HDC hDC, int iEntries, USHORT* puRed, USHORT* puGreen, USHORT* puBlue); + typedef BOOL(WINAPI* PFNWGLSETGAMMATABLEI3DPROC)( + HDC hDC, int iEntries, const USHORT* puRed, const USHORT* puGreen, const USHORT* puBlue); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetGammaTableParametersI3D(HDC hDC, int iAttribute, int* piValue); + BOOL WINAPI wglSetGammaTableParametersI3D(HDC hDC, int iAttribute, const int* piValue); + BOOL WINAPI + wglGetGammaTableI3D(HDC hDC, int iEntries, USHORT* puRed, USHORT* puGreen, USHORT* puBlue); + BOOL WINAPI wglSetGammaTableI3D( + HDC hDC, int iEntries, const USHORT* puRed, const USHORT* puGreen, const USHORT* puBlue); +# endif +#endif /* WGL_I3D_gamma */ + +#ifndef WGL_I3D_genlock +# define WGL_I3D_genlock 1 +# define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +# define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +# define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +# define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 +# define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +# define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +# define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +# define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +# define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C + typedef BOOL(WINAPI* PFNWGLENABLEGENLOCKI3DPROC)(HDC hDC); + typedef BOOL(WINAPI* PFNWGLDISABLEGENLOCKI3DPROC)(HDC hDC); + typedef BOOL(WINAPI* PFNWGLISENABLEDGENLOCKI3DPROC)(HDC hDC, BOOL* pFlag); + typedef BOOL(WINAPI* PFNWGLGENLOCKSOURCEI3DPROC)(HDC hDC, UINT uSource); + typedef BOOL(WINAPI* PFNWGLGETGENLOCKSOURCEI3DPROC)(HDC hDC, UINT* uSource); + typedef BOOL(WINAPI* PFNWGLGENLOCKSOURCEEDGEI3DPROC)(HDC hDC, UINT uEdge); + typedef BOOL(WINAPI* PFNWGLGETGENLOCKSOURCEEDGEI3DPROC)(HDC hDC, UINT* uEdge); + typedef BOOL(WINAPI* PFNWGLGENLOCKSAMPLERATEI3DPROC)(HDC hDC, UINT uRate); + typedef BOOL(WINAPI* PFNWGLGETGENLOCKSAMPLERATEI3DPROC)(HDC hDC, UINT* uRate); + typedef BOOL(WINAPI* PFNWGLGENLOCKSOURCEDELAYI3DPROC)(HDC hDC, UINT uDelay); + typedef BOOL(WINAPI* PFNWGLGETGENLOCKSOURCEDELAYI3DPROC)(HDC hDC, UINT* uDelay); + typedef BOOL(WINAPI* PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC)( + HDC hDC, UINT* uMaxLineDelay, UINT* uMaxPixelDelay); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglEnableGenlockI3D(HDC hDC); + BOOL WINAPI wglDisableGenlockI3D(HDC hDC); + BOOL WINAPI wglIsEnabledGenlockI3D(HDC hDC, BOOL* pFlag); + BOOL WINAPI wglGenlockSourceI3D(HDC hDC, UINT uSource); + BOOL WINAPI wglGetGenlockSourceI3D(HDC hDC, UINT* uSource); + BOOL WINAPI wglGenlockSourceEdgeI3D(HDC hDC, UINT uEdge); + BOOL WINAPI wglGetGenlockSourceEdgeI3D(HDC hDC, UINT* uEdge); + BOOL WINAPI wglGenlockSampleRateI3D(HDC hDC, UINT uRate); + BOOL WINAPI wglGetGenlockSampleRateI3D(HDC hDC, UINT* uRate); + BOOL WINAPI wglGenlockSourceDelayI3D(HDC hDC, UINT uDelay); + BOOL WINAPI wglGetGenlockSourceDelayI3D(HDC hDC, UINT* uDelay); + BOOL WINAPI + wglQueryGenlockMaxSourceDelayI3D(HDC hDC, UINT* uMaxLineDelay, UINT* uMaxPixelDelay); +# endif +#endif /* WGL_I3D_genlock */ + +#ifndef WGL_I3D_image_buffer +# define WGL_I3D_image_buffer 1 +# define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +# define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 + typedef LPVOID(WINAPI* PFNWGLCREATEIMAGEBUFFERI3DPROC)(HDC hDC, DWORD dwSize, UINT uFlags); + typedef BOOL(WINAPI* PFNWGLDESTROYIMAGEBUFFERI3DPROC)(HDC hDC, LPVOID pAddress); + typedef BOOL(WINAPI* PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC)( + HDC hDC, const HANDLE* pEvent, const LPVOID* pAddress, const DWORD* pSize, UINT count); + typedef BOOL(WINAPI* PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC)( + HDC hDC, const LPVOID* pAddress, UINT count); +# ifdef WGL_WGLEXT_PROTOTYPES + LPVOID WINAPI wglCreateImageBufferI3D(HDC hDC, DWORD dwSize, UINT uFlags); + BOOL WINAPI wglDestroyImageBufferI3D(HDC hDC, LPVOID pAddress); + BOOL WINAPI wglAssociateImageBufferEventsI3D( + HDC hDC, const HANDLE* pEvent, const LPVOID* pAddress, const DWORD* pSize, UINT count); + BOOL WINAPI wglReleaseImageBufferEventsI3D(HDC hDC, const LPVOID* pAddress, UINT count); +# endif +#endif /* WGL_I3D_image_buffer */ + +#ifndef WGL_I3D_swap_frame_lock +# define WGL_I3D_swap_frame_lock 1 + typedef BOOL(WINAPI* PFNWGLENABLEFRAMELOCKI3DPROC)(void); + typedef BOOL(WINAPI* PFNWGLDISABLEFRAMELOCKI3DPROC)(void); + typedef BOOL(WINAPI* PFNWGLISENABLEDFRAMELOCKI3DPROC)(BOOL* pFlag); + typedef BOOL(WINAPI* PFNWGLQUERYFRAMELOCKMASTERI3DPROC)(BOOL* pFlag); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglEnableFrameLockI3D(void); + BOOL WINAPI wglDisableFrameLockI3D(void); + BOOL WINAPI wglIsEnabledFrameLockI3D(BOOL* pFlag); + BOOL WINAPI wglQueryFrameLockMasterI3D(BOOL* pFlag); +# endif +#endif /* WGL_I3D_swap_frame_lock */ + +#ifndef WGL_I3D_swap_frame_usage +# define WGL_I3D_swap_frame_usage 1 + typedef BOOL(WINAPI* PFNWGLGETFRAMEUSAGEI3DPROC)(float* pUsage); + typedef BOOL(WINAPI* PFNWGLBEGINFRAMETRACKINGI3DPROC)(void); + typedef BOOL(WINAPI* PFNWGLENDFRAMETRACKINGI3DPROC)(void); + typedef BOOL(WINAPI* PFNWGLQUERYFRAMETRACKINGI3DPROC)( + DWORD* pFrameCount, DWORD* pMissedFrames, float* pLastMissedUsage); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetFrameUsageI3D(float* pUsage); + BOOL WINAPI wglBeginFrameTrackingI3D(void); + BOOL WINAPI wglEndFrameTrackingI3D(void); + BOOL WINAPI + wglQueryFrameTrackingI3D(DWORD* pFrameCount, DWORD* pMissedFrames, float* pLastMissedUsage); +# endif +#endif /* WGL_I3D_swap_frame_usage */ + +#ifndef WGL_NV_DX_interop +# define WGL_NV_DX_interop 1 +# define WGL_ACCESS_READ_ONLY_NV 0x00000000 +# define WGL_ACCESS_READ_WRITE_NV 0x00000001 +# define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 + typedef BOOL(WINAPI* PFNWGLDXSETRESOURCESHAREHANDLENVPROC)(void* dxObject, HANDLE shareHandle); + typedef HANDLE(WINAPI* PFNWGLDXOPENDEVICENVPROC)(void* dxDevice); + typedef BOOL(WINAPI* PFNWGLDXCLOSEDEVICENVPROC)(HANDLE hDevice); + typedef HANDLE(WINAPI* PFNWGLDXREGISTEROBJECTNVPROC)( + HANDLE hDevice, void* dxObject, GLuint name, GLenum type, GLenum access); + typedef BOOL(WINAPI* PFNWGLDXUNREGISTEROBJECTNVPROC)(HANDLE hDevice, HANDLE hObject); + typedef BOOL(WINAPI* PFNWGLDXOBJECTACCESSNVPROC)(HANDLE hObject, GLenum access); + typedef BOOL(WINAPI* PFNWGLDXLOCKOBJECTSNVPROC)(HANDLE hDevice, GLint count, HANDLE* hObjects); + typedef BOOL(WINAPI* PFNWGLDXUNLOCKOBJECTSNVPROC)( + HANDLE hDevice, GLint count, HANDLE* hObjects); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglDXSetResourceShareHandleNV(void* dxObject, HANDLE shareHandle); + HANDLE WINAPI wglDXOpenDeviceNV(void* dxDevice); + BOOL WINAPI wglDXCloseDeviceNV(HANDLE hDevice); + HANDLE WINAPI wglDXRegisterObjectNV( + HANDLE hDevice, void* dxObject, GLuint name, GLenum type, GLenum access); + BOOL WINAPI wglDXUnregisterObjectNV(HANDLE hDevice, HANDLE hObject); + BOOL WINAPI wglDXObjectAccessNV(HANDLE hObject, GLenum access); + BOOL WINAPI wglDXLockObjectsNV(HANDLE hDevice, GLint count, HANDLE* hObjects); + BOOL WINAPI wglDXUnlockObjectsNV(HANDLE hDevice, GLint count, HANDLE* hObjects); +# endif +#endif /* WGL_NV_DX_interop */ + +#ifndef WGL_NV_DX_interop2 +# define WGL_NV_DX_interop2 1 +#endif /* WGL_NV_DX_interop2 */ + +#ifndef WGL_NV_copy_image +# define WGL_NV_copy_image 1 + typedef BOOL(WINAPI* PFNWGLCOPYIMAGESUBDATANVPROC)( + HGLRC hSrcRC, + GLuint srcName, + GLenum srcTarget, + GLint srcLevel, + GLint srcX, + GLint srcY, + GLint srcZ, + HGLRC hDstRC, + GLuint dstName, + GLenum dstTarget, + GLint dstLevel, + GLint dstX, + GLint dstY, + GLint dstZ, + GLsizei width, + GLsizei height, + GLsizei depth); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglCopyImageSubDataNV( + HGLRC hSrcRC, + GLuint srcName, + GLenum srcTarget, + GLint srcLevel, + GLint srcX, + GLint srcY, + GLint srcZ, + HGLRC hDstRC, + GLuint dstName, + GLenum dstTarget, + GLint dstLevel, + GLint dstX, + GLint dstY, + GLint dstZ, + GLsizei width, + GLsizei height, + GLsizei depth); +# endif +#endif /* WGL_NV_copy_image */ + +#ifndef WGL_NV_delay_before_swap +# define WGL_NV_delay_before_swap 1 + typedef BOOL(WINAPI* PFNWGLDELAYBEFORESWAPNVPROC)(HDC hDC, GLfloat seconds); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglDelayBeforeSwapNV(HDC hDC, GLfloat seconds); +# endif +#endif /* WGL_NV_delay_before_swap */ + +#ifndef WGL_NV_float_buffer +# define WGL_NV_float_buffer 1 +# define WGL_FLOAT_COMPONENTS_NV 0x20B0 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +# define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +# define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +# define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +# define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif /* WGL_NV_float_buffer */ + +#ifndef WGL_NV_gpu_affinity +# define WGL_NV_gpu_affinity 1 + DECLARE_HANDLE(HGPUNV); + struct _GPU_DEVICE + { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; + }; + typedef struct _GPU_DEVICE* PGPU_DEVICE; +# define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 +# define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 + typedef BOOL(WINAPI* PFNWGLENUMGPUSNVPROC)(UINT iGpuIndex, HGPUNV* phGpu); + typedef BOOL(WINAPI* PFNWGLENUMGPUDEVICESNVPROC)( + HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); + typedef HDC(WINAPI* PFNWGLCREATEAFFINITYDCNVPROC)(const HGPUNV* phGpuList); + typedef BOOL(WINAPI* PFNWGLENUMGPUSFROMAFFINITYDCNVPROC)( + HDC hAffinityDC, UINT iGpuIndex, HGPUNV* hGpu); + typedef BOOL(WINAPI* PFNWGLDELETEDCNVPROC)(HDC hdc); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglEnumGpusNV(UINT iGpuIndex, HGPUNV* phGpu); + BOOL WINAPI wglEnumGpuDevicesNV(HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); + HDC WINAPI wglCreateAffinityDCNV(const HGPUNV* phGpuList); + BOOL WINAPI wglEnumGpusFromAffinityDCNV(HDC hAffinityDC, UINT iGpuIndex, HGPUNV* hGpu); + BOOL WINAPI wglDeleteDCNV(HDC hdc); +# endif +#endif /* WGL_NV_gpu_affinity */ + +#ifndef WGL_NV_multigpu_context +# define WGL_NV_multigpu_context 1 +# define WGL_CONTEXT_MULTIGPU_ATTRIB_NV 0x20AA +# define WGL_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB +# define WGL_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC +# define WGL_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD +# define WGL_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE +#endif /* WGL_NV_multigpu_context */ + +#ifndef WGL_NV_multisample_coverage +# define WGL_NV_multisample_coverage 1 +# define WGL_COVERAGE_SAMPLES_NV 0x2042 +# define WGL_COLOR_SAMPLES_NV 0x20B9 +#endif /* WGL_NV_multisample_coverage */ + +#ifndef WGL_NV_present_video +# define WGL_NV_present_video 1 + DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +# define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 + typedef int(WINAPI* PFNWGLENUMERATEVIDEODEVICESNVPROC)( + HDC hDc, HVIDEOOUTPUTDEVICENV* phDeviceList); + typedef BOOL(WINAPI* PFNWGLBINDVIDEODEVICENVPROC)( + HDC hDc, + unsigned int uVideoSlot, + HVIDEOOUTPUTDEVICENV hVideoDevice, + const int* piAttribList); + typedef BOOL(WINAPI* PFNWGLQUERYCURRENTCONTEXTNVPROC)(int iAttribute, int* piValue); +# ifdef WGL_WGLEXT_PROTOTYPES + int WINAPI wglEnumerateVideoDevicesNV(HDC hDc, HVIDEOOUTPUTDEVICENV* phDeviceList); + BOOL WINAPI wglBindVideoDeviceNV( + HDC hDc, + unsigned int uVideoSlot, + HVIDEOOUTPUTDEVICENV hVideoDevice, + const int* piAttribList); + BOOL WINAPI wglQueryCurrentContextNV(int iAttribute, int* piValue); +# endif +#endif /* WGL_NV_present_video */ + +#ifndef WGL_NV_render_depth_texture +# define WGL_NV_render_depth_texture 1 +# define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +# define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +# define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +# define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif /* WGL_NV_render_depth_texture */ + +#ifndef WGL_NV_render_texture_rectangle +# define WGL_NV_render_texture_rectangle 1 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +# define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +# define WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#endif /* WGL_NV_render_texture_rectangle */ + +#ifndef WGL_NV_swap_group +# define WGL_NV_swap_group 1 + typedef BOOL(WINAPI* PFNWGLJOINSWAPGROUPNVPROC)(HDC hDC, GLuint group); + typedef BOOL(WINAPI* PFNWGLBINDSWAPBARRIERNVPROC)(GLuint group, GLuint barrier); + typedef BOOL(WINAPI* PFNWGLQUERYSWAPGROUPNVPROC)(HDC hDC, GLuint* group, GLuint* barrier); + typedef BOOL(WINAPI* PFNWGLQUERYMAXSWAPGROUPSNVPROC)( + HDC hDC, GLuint* maxGroups, GLuint* maxBarriers); + typedef BOOL(WINAPI* PFNWGLQUERYFRAMECOUNTNVPROC)(HDC hDC, GLuint* count); + typedef BOOL(WINAPI* PFNWGLRESETFRAMECOUNTNVPROC)(HDC hDC); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglJoinSwapGroupNV(HDC hDC, GLuint group); + BOOL WINAPI wglBindSwapBarrierNV(GLuint group, GLuint barrier); + BOOL WINAPI wglQuerySwapGroupNV(HDC hDC, GLuint* group, GLuint* barrier); + BOOL WINAPI wglQueryMaxSwapGroupsNV(HDC hDC, GLuint* maxGroups, GLuint* maxBarriers); + BOOL WINAPI wglQueryFrameCountNV(HDC hDC, GLuint* count); + BOOL WINAPI wglResetFrameCountNV(HDC hDC); +# endif +#endif /* WGL_NV_swap_group */ + +#ifndef WGL_NV_vertex_array_range +# define WGL_NV_vertex_array_range 1 + typedef void*(WINAPI* PFNWGLALLOCATEMEMORYNVPROC)( + GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); + typedef void(WINAPI* PFNWGLFREEMEMORYNVPROC)(void* pointer); +# ifdef WGL_WGLEXT_PROTOTYPES + void* WINAPI + wglAllocateMemoryNV(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); + void WINAPI wglFreeMemoryNV(void* pointer); +# endif +#endif /* WGL_NV_vertex_array_range */ + +#ifndef WGL_NV_video_capture +# define WGL_NV_video_capture 1 + DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +# define WGL_UNIQUE_ID_NV 0x20CE +# define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF + typedef BOOL(WINAPI* PFNWGLBINDVIDEOCAPTUREDEVICENVPROC)( + UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); + typedef UINT(WINAPI* PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC)( + HDC hDc, HVIDEOINPUTDEVICENV* phDeviceList); + typedef BOOL(WINAPI* PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC)(HDC hDc, HVIDEOINPUTDEVICENV hDevice); + typedef BOOL(WINAPI* PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC)( + HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int* piValue); + typedef BOOL(WINAPI* PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC)( + HDC hDc, HVIDEOINPUTDEVICENV hDevice); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglBindVideoCaptureDeviceNV(UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); + UINT WINAPI wglEnumerateVideoCaptureDevicesNV(HDC hDc, HVIDEOINPUTDEVICENV* phDeviceList); + BOOL WINAPI wglLockVideoCaptureDeviceNV(HDC hDc, HVIDEOINPUTDEVICENV hDevice); + BOOL WINAPI wglQueryVideoCaptureDeviceNV( + HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int* piValue); + BOOL WINAPI wglReleaseVideoCaptureDeviceNV(HDC hDc, HVIDEOINPUTDEVICENV hDevice); +# endif +#endif /* WGL_NV_video_capture */ + +#ifndef WGL_NV_video_output +# define WGL_NV_video_output 1 + DECLARE_HANDLE(HPVIDEODEV); +# define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +# define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +# define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +# define WGL_VIDEO_OUT_COLOR_NV 0x20C3 +# define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +# define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +# define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +# define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +# define WGL_VIDEO_OUT_FRAME 0x20C8 +# define WGL_VIDEO_OUT_FIELD_1 0x20C9 +# define WGL_VIDEO_OUT_FIELD_2 0x20CA +# define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +# define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC + typedef BOOL(WINAPI* PFNWGLGETVIDEODEVICENVPROC)( + HDC hDC, int numDevices, HPVIDEODEV* hVideoDevice); + typedef BOOL(WINAPI* PFNWGLRELEASEVIDEODEVICENVPROC)(HPVIDEODEV hVideoDevice); + typedef BOOL(WINAPI* PFNWGLBINDVIDEOIMAGENVPROC)( + HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); + typedef BOOL(WINAPI* PFNWGLRELEASEVIDEOIMAGENVPROC)(HPBUFFERARB hPbuffer, int iVideoBuffer); + typedef BOOL(WINAPI* PFNWGLSENDPBUFFERTOVIDEONVPROC)( + HPBUFFERARB hPbuffer, int iBufferType, unsigned long* pulCounterPbuffer, BOOL bBlock); + typedef BOOL(WINAPI* PFNWGLGETVIDEOINFONVPROC)( + HPVIDEODEV hpVideoDevice, + unsigned long* pulCounterOutputPbuffer, + unsigned long* pulCounterOutputVideo); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetVideoDeviceNV(HDC hDC, int numDevices, HPVIDEODEV* hVideoDevice); + BOOL WINAPI wglReleaseVideoDeviceNV(HPVIDEODEV hVideoDevice); + BOOL WINAPI + wglBindVideoImageNV(HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); + BOOL WINAPI wglReleaseVideoImageNV(HPBUFFERARB hPbuffer, int iVideoBuffer); + BOOL WINAPI wglSendPbufferToVideoNV( + HPBUFFERARB hPbuffer, int iBufferType, unsigned long* pulCounterPbuffer, BOOL bBlock); + BOOL WINAPI wglGetVideoInfoNV( + HPVIDEODEV hpVideoDevice, + unsigned long* pulCounterOutputPbuffer, + unsigned long* pulCounterOutputVideo); +# endif +#endif /* WGL_NV_video_output */ + +#ifndef WGL_OML_sync_control +# define WGL_OML_sync_control 1 + typedef BOOL(WINAPI* PFNWGLGETSYNCVALUESOMLPROC)(HDC hdc, INT64* ust, INT64* msc, INT64* sbc); + typedef BOOL(WINAPI* PFNWGLGETMSCRATEOMLPROC)(HDC hdc, INT32* numerator, INT32* denominator); + typedef INT64(WINAPI* PFNWGLSWAPBUFFERSMSCOMLPROC)( + HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); + typedef INT64(WINAPI* PFNWGLSWAPLAYERBUFFERSMSCOMLPROC)( + HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); + typedef BOOL(WINAPI* PFNWGLWAITFORMSCOMLPROC)( + HDC hdc, + INT64 target_msc, + INT64 divisor, + INT64 remainder, + INT64* ust, + INT64* msc, + INT64* sbc); + typedef BOOL(WINAPI* PFNWGLWAITFORSBCOMLPROC)( + HDC hdc, INT64 target_sbc, INT64* ust, INT64* msc, INT64* sbc); +# ifdef WGL_WGLEXT_PROTOTYPES + BOOL WINAPI wglGetSyncValuesOML(HDC hdc, INT64* ust, INT64* msc, INT64* sbc); + BOOL WINAPI wglGetMscRateOML(HDC hdc, INT32* numerator, INT32* denominator); + INT64 WINAPI wglSwapBuffersMscOML(HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); + INT64 WINAPI wglSwapLayerBuffersMscOML( + HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); + BOOL WINAPI wglWaitForMscOML( + HDC hdc, + INT64 target_msc, + INT64 divisor, + INT64 remainder, + INT64* ust, + INT64* msc, + INT64* sbc); + BOOL WINAPI wglWaitForSbcOML(HDC hdc, INT64 target_sbc, INT64* ust, INT64* msc, INT64* sbc); +# endif +#endif /* WGL_OML_sync_control */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/slang-gfx.h b/slang-gfx.h index 7b77650e8..5fad16e8f 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -160,6 +160,7 @@ enum class Format R_Float32, RGBA_Unorm_UInt8, + BGRA_Unorm_UInt8, R_UInt16, R_UInt32, @@ -594,6 +595,7 @@ public: int numMipLevels; ///< Number of mip levels - if 0 will create all mip levels Format format; ///< The resources format SampleDesc sampleDesc; ///< How the resource is sampled + float optimalClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f}; }; /// The ordering of the subResources is @@ -795,10 +797,23 @@ public: UnorderedAccess, }; + struct RenderTargetDesc + { + // The resource shape of this render target view. + IResource::Type shape; + uint32_t mipSlice; + uint32_t arrayIndex; + uint32_t arraySize; + uint32_t planeIndex; + }; + struct Desc { Type type; Format format; + + // Fields for `RenderTarget` and `DepthStencil` views. + RenderTargetDesc renderTarget; }; }; #define SLANG_UUID_IResourceView \ @@ -810,6 +825,15 @@ public: class IDescriptorSet : public ISlangUnknown { public: + struct Flag + { + enum Enum + { + None = 0, + Transient = 1, + Persistent = 2 + }; + }; virtual SLANG_NO_THROW void SLANG_MCALL setConstantBuffer(UInt range, UInt index, IBufferResource* buffer) = 0; virtual SLANG_NO_THROW void SLANG_MCALL setResource(UInt range, UInt index, IResourceView* view) = 0; @@ -917,6 +941,9 @@ struct DepthStencilOpDesc StencilOp stencilDepthFailOp = StencilOp::Keep; StencilOp stencilPassOp = StencilOp::Keep; ComparisonFunc stencilFunc = ComparisonFunc::Always; + uint32_t stencilCompareMask = 0xFFFFFFFF; + uint32_t stencilWriteMask = 0xFFFFFFFF; + uint32_t stencilReference = 0; }; struct DepthStencilDesc @@ -1022,6 +1049,26 @@ struct BlendDesc bool alphaToCoverateEnable = false; }; +class IFramebufferLayout : public ISlangUnknown +{ +public: + struct AttachmentLayout + { + Format format; + int sampleCount; + }; + struct Desc + { + uint32_t renderTargetCount; + AttachmentLayout* renderTargets; + AttachmentLayout* depthStencil; + }; +}; +#define SLANG_UUID_IFramebufferLayout \ + { \ + 0xa838785, 0xc13a, 0x4832, { 0xad, 0x88, 0x64, 0x6, 0xb5, 0x4b, 0x5e, 0xba } \ + } + struct GraphicsPipelineStateDesc { IShaderProgram* program; @@ -1030,8 +1077,8 @@ struct GraphicsPipelineStateDesc // from `program`, which must have been created with Slang reflection info. IPipelineLayout* pipelineLayout = nullptr; - IInputLayout* inputLayout; - UInt renderTargetCount = 0; // Only used if `pipelineLayout` is non-null + IInputLayout* inputLayout; + IFramebufferLayout* framebufferLayout; DepthStencilDesc depthStencil; RasterizerDesc rasterizer; BlendDesc blend; @@ -1073,6 +1120,69 @@ struct Viewport float maxZ = 1.0f; }; +class IFramebuffer : public ISlangUnknown +{ +public: + struct Desc + { + uint32_t renderTargetCount; + IResourceView* const* renderTargetViews; + IResourceView* depthStencilView; + IFramebufferLayout* layout; + }; +}; +#define SLANG_UUID_IFrameBuffer \ + { \ + 0xf0c0d9a, 0x4ef3, 0x4e18, { 0x9b, 0xa9, 0x34, 0x60, 0xea, 0x69, 0x87, 0x95 } \ + } + +class ISwapchain : public ISlangUnknown +{ +public: + struct Desc + { + Format format; + uint32_t width, height; + uint32_t imageCount; + bool enableVSync; + }; + virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() = 0; + virtual SLANG_NO_THROW Result getImage(uint32_t index, ITextureResource** outResource) = 0; + virtual SLANG_NO_THROW Result present() = 0; + virtual SLANG_NO_THROW uint32_t acquireNextImage() = 0; +}; +#define SLANG_UUID_ISwapchain \ + { \ + 0xbe91ba6c, 0x784, 0x4308, { 0xa1, 0x0, 0x19, 0xc3, 0x66, 0x83, 0x44, 0xb2 } \ + } + +struct WindowHandle +{ + enum class Type + { + Unknown, + Win32Handle, + XLibHandle, + }; + Type type; + intptr_t handleValues[2]; + static WindowHandle FromHwnd(void* hwnd) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::Win32Handle; + handle.handleValues[0] = (intptr_t)(hwnd); + return handle; + } + static WindowHandle FromXWindow(void* xdisplay, uint32_t xwindow) + { + WindowHandle handle = {}; + handle.type = WindowHandle::Type::XLibHandle; + handle.handleValues[0] = (intptr_t)(xdisplay); + handle.handleValues[1] = xwindow; + return handle; + } +}; + class IRenderer: public ISlangUnknown { public: @@ -1096,8 +1206,6 @@ public: struct Desc { RendererType rendererType; // The underlying API/Platform of the renderer. - int width = 0; // Width in pixels - int height = 0; // height in pixels const char* adapter = nullptr; // Name to identify the adapter to use int requiredFeatureCount = 0; // Number of required features. const char** requiredFeatures = nullptr; // Array of required feature names, whose size is `requiredFeatureCount`. @@ -1122,10 +1230,10 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) = 0; virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() = 0; - - virtual SLANG_NO_THROW ITextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() = 0; + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() = 0; + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() = 0; /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( @@ -1192,6 +1300,33 @@ public: return view; } + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebufferLayout(IFramebufferLayout::Desc const& desc, IFramebufferLayout** outFrameBuffer) = 0; + inline ComPtr<IFramebufferLayout> createFramebufferLayout(IFramebufferLayout::Desc const& desc) + { + ComPtr<IFramebufferLayout> fb; + SLANG_RETURN_NULL_ON_FAIL(createFramebufferLayout(desc, fb.writeRef())); + return fb; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) = 0; + inline ComPtr<IFramebuffer> createFramebuffer(IFramebuffer::Desc const& desc) + { + ComPtr<IFramebuffer> fb; + SLANG_RETURN_NULL_ON_FAIL(createFramebuffer(desc, fb.writeRef())); + return fb; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + ISwapchain::Desc const& desc, WindowHandle window, ISwapchain** outSwapchain) = 0; + inline ComPtr<ISwapchain> createSwapchain(ISwapchain::Desc const& desc, WindowHandle window) + { + ComPtr<ISwapchain> swapchain; + SLANG_RETURN_NULL_ON_FAIL(createSwapchain(desc, window, swapchain.writeRef())); + return swapchain; + } + virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount, IInputLayout** outLayout) = 0; @@ -1241,12 +1376,12 @@ public: return layout; } - virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) = 0; - inline ComPtr<IDescriptorSet> createDescriptorSet(IDescriptorSetLayout* layout) + inline ComPtr<IDescriptorSet> createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag) { ComPtr<IDescriptorSet> descriptorSet; - SLANG_RETURN_NULL_ON_FAIL(createDescriptorSet(layout, descriptorSet.writeRef())); + SLANG_RETURN_NULL_ON_FAIL(createDescriptorSet(layout, flag, descriptorSet.writeRef())); return descriptorSet; } @@ -1283,8 +1418,12 @@ public: return state; } - /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface(void* buffer, size_t *inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) = 0; + /// Read back texture resource and stores the result in `outBlob`. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* resource, + ISlangBlob** outBlob, + size_t* outRowPitch, + size_t* outPixelSize) = 0; virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) = 0; virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) = 0; @@ -1308,8 +1447,6 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset = 0) = 0; - virtual SLANG_NO_THROW void SLANG_MCALL setDepthStencilTarget(IResourceView* depthStencilView) = 0; - virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) = 0; inline void setViewport(Viewport const& viewport) { @@ -1321,8 +1458,17 @@ public: { setScissorRects(1, &rect); } - + /// Sets the viewport, and sets the scissor rect to match the viewport. + inline void setViewportAndScissor(Viewport const& viewport) + { + setViewports(1, &viewport); + ScissorRect rect = {}; + rect.maxX = static_cast<gfx::Int>(viewport.extentX); + rect.maxY = static_cast<gfx::Int>(viewport.extentY); + setScissorRects(1, &rect); + } virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* framebuffer) = 0; virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex = 0) = 0; virtual SLANG_NO_THROW void SLANG_MCALL drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) = 0; @@ -1372,7 +1518,7 @@ extern "C" SLANG_GFX_API const char* SLANG_MCALL gfxGetRendererName(RendererType type); /// Given a type returns a function that can construct it, or nullptr if there isn't one - SLANG_GFX_API SlangResult SLANG_MCALL gfxCreateRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); + SLANG_GFX_API SlangResult SLANG_MCALL gfxCreateRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } }// renderer_test diff --git a/source/core/slang-virtual-object-pool.h b/source/core/slang-virtual-object-pool.h new file mode 100644 index 000000000..c1247acb7 --- /dev/null +++ b/source/core/slang-virtual-object-pool.h @@ -0,0 +1,119 @@ +#ifndef SLANG_VIRTUAL_POOL_ALLOCATOR_H +#define SLANG_VIRTUAL_POOL_ALLOCATOR_H + +namespace Slang +{ + + /// A virtual free-list allocater. + /// This class doesn't actually allocates memory, instead it operates on a + /// virtual integer space. Can be used to implement various types of object pools + /// that needs to support contiguous allocations of more than one elements. +class VirtualObjectPool +{ +public: + struct FreeListNode + { + int Offset; + int Length; + FreeListNode* prev; + FreeListNode* next; + }; + FreeListNode* freeListHead = nullptr; + +public: + void destroy() + { + auto list = freeListHead; + while (list) + { + auto next = list->next; + delete list; + list = next; + } + freeListHead = nullptr; + } + + ~VirtualObjectPool() { destroy(); } + + void initPool(int numElements) + { + freeListHead = new FreeListNode(); + freeListHead->prev = freeListHead->next = nullptr; + freeListHead->Offset = 0; + freeListHead->Length = numElements; + } + + int alloc(int size) + { + if (!freeListHead) + return -1; + auto freeBlock = freeListHead; + while (freeBlock && freeBlock->Length < size) + freeBlock = freeBlock->next; + if (!freeBlock || freeBlock->Length < size) + return -1; + int result = freeBlock->Offset; + freeBlock->Offset += size; + freeBlock->Length -= size; + if (freeBlock->Length == 0) + { + if (freeBlock->prev) + freeBlock->prev->next = freeBlock->next; + if (freeBlock->next) + freeBlock->next->prev = freeBlock->prev; + if (freeBlock == freeListHead) + freeListHead = freeBlock->next; + delete freeBlock; + } + return result; + } + void free(int offset, int size) + { + if (!freeListHead) + { + freeListHead = new FreeListNode(); + freeListHead->next = freeListHead->prev = nullptr; + freeListHead->Length = size; + freeListHead->Offset = offset; + return; + } + auto freeListNode = freeListHead; + FreeListNode* prevFreeNode = nullptr; + while (freeListNode && freeListNode->Offset < offset + size) + { + prevFreeNode = freeListNode; + freeListNode = freeListNode->next; + } + FreeListNode* newNode = new FreeListNode(); + newNode->Offset = offset; + newNode->Length = size; + newNode->prev = prevFreeNode; + newNode->next = freeListNode; + if (freeListNode) + freeListNode->prev = newNode; + if (prevFreeNode) + prevFreeNode->next = newNode; + if (freeListNode == freeListHead) + freeListHead = newNode; + if (prevFreeNode && prevFreeNode->Offset + prevFreeNode->Length == newNode->Offset) + { + prevFreeNode->Length += newNode->Length; + prevFreeNode->next = freeListNode; + if (freeListNode) + freeListNode->prev = prevFreeNode; + delete newNode; + newNode = prevFreeNode; + } + if (freeListNode && newNode->Offset + newNode->Length == freeListNode->Offset) + { + newNode->Length += freeListNode->Length; + newNode->next = freeListNode->next; + if (freeListNode->next) + freeListNode->next->prev = newNode; + delete freeListNode; + } + } +}; + +} // namespace Slang +#endif diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index 4673cda6e..eabb2d301 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -878,11 +878,11 @@ private: cuCtxDestroy(m_context); } } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle) override + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override { SLANG_RETURN_ON_FAIL(slangContext.initialize(desc.slang, SLANG_PTX, "sm_5_1")); - SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc, inWindowHandle)); + SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc)); SLANG_RETURN_ON_FAIL(_initCuda(reportType)); @@ -950,6 +950,7 @@ private: switch (desc.format) { case Format::R_Float32: + case Format::D_Float32: { format = CU_AD_FORMAT_FLOAT; numChannels = 1; @@ -1362,7 +1363,6 @@ private: ShaderObjectLayoutBase* layout, IShaderObject** outObject) override { - RefPtr<CUDAShaderObject> result = new CUDAShaderObject(); SLANG_RETURN_ON_FAIL(result->init(this, dynamic_cast<CUDAShaderObjectLayout*>(layout))); *outObject = result.detach(); @@ -1560,12 +1560,39 @@ public: SLANG_UNUSED(color); } virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override {} - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() override {} - virtual SLANG_NO_THROW TextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() override + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override {} + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override {} + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) override { - return TextureResource::Desc(); + SLANG_UNUSED(swapchain); + } + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) override + { + SLANG_UNUSED(desc); + SLANG_UNUSED(window); + SLANG_UNUSED(outSwapchain); + return SLANG_FAIL; + } + virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout( + const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) override + { + SLANG_UNUSED(desc); + SLANG_UNUSED(outLayout); + return SLANG_FAIL; + } + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) override + { + SLANG_UNUSED(desc); + SLANG_UNUSED(outFramebuffer); + return SLANG_FAIL; + } + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override + { + SLANG_UNUSED(frameBuffer); } - virtual SLANG_NO_THROW Result SLANG_MCALL createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) override { @@ -1599,9 +1626,10 @@ public: return SLANG_E_NOT_AVAILABLE; } virtual SLANG_NO_THROW Result SLANG_MCALL - createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) override + createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flags, IDescriptorSet** outDescriptorSet) override { SLANG_UNUSED(layout); + SLANG_UNUSED(flags); SLANG_UNUSED(outDescriptorSet); return SLANG_E_NOT_AVAILABLE; } @@ -1612,11 +1640,11 @@ public: SLANG_UNUSED(outState); return SLANG_E_NOT_AVAILABLE; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) override + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override { - SLANG_UNUSED(buffer); - SLANG_UNUSED(inOutBufferSize); + SLANG_UNUSED(texture); + SLANG_UNUSED(outBlob); SLANG_UNUSED(outRowPitch); SLANG_UNUSED(outPixelSize); @@ -1659,11 +1687,6 @@ public: SLANG_UNUSED(offset); } virtual SLANG_NO_THROW void SLANG_MCALL - setDepthStencilTarget(IResourceView* depthStencilView) override - { - SLANG_UNUSED(depthStencilView); - } - virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) override { SLANG_UNUSED(count); @@ -1760,18 +1783,17 @@ SlangResult CUDARootShaderObject::init(IRenderer* renderer, CUDAShaderObjectLayo return SLANG_OK; } -SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { RefPtr<CUDARenderer> result = new CUDARenderer(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc, windowHandle)); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); *outRenderer = result.detach(); return SLANG_OK; } #else -SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { SLANG_UNUSED(desc); - SLANG_UNUSED(windowHandle); *outRenderer = nullptr; return SLANG_OK; } diff --git a/tools/gfx/cuda/render-cuda.h b/tools/gfx/cuda/render-cuda.h index 39d5b60f8..cd8482e37 100644 --- a/tools/gfx/cuda/render-cuda.h +++ b/tools/gfx/cuda/render-cuda.h @@ -5,5 +5,5 @@ namespace gfx { -SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); +SlangResult SLANG_MCALL createCUDARenderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } diff --git a/tools/gfx/d3d/d3d-util.cpp b/tools/gfx/d3d/d3d-util.cpp index f60bd9d3f..cb96c6211 100644 --- a/tools/gfx/d3d/d3d-util.cpp +++ b/tools/gfx/d3d/d3d-util.cpp @@ -35,6 +35,8 @@ using namespace Slang; case Format::RG_Float32: return DXGI_FORMAT_R32G32_FLOAT; case Format::R_Float32: return DXGI_FORMAT_R32_FLOAT; case Format::RGBA_Unorm_UInt8: return DXGI_FORMAT_R8G8B8A8_UNORM; + case Format::BGRA_Unorm_UInt8: return DXGI_FORMAT_B8G8R8A8_UNORM; + case Format::R_UInt16: return DXGI_FORMAT_R16_UINT; case Format::R_UInt32: return DXGI_FORMAT_R32_UINT; diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp index 49fe101fb..c64b1c3bd 100644 --- a/tools/gfx/d3d11/render-d3d11.cpp +++ b/tools/gfx/d3d11/render-d3d11.cpp @@ -1,9 +1,9 @@ // render-d3d11.cpp - #define _CRT_SECURE_NO_WARNINGS #include "render-d3d11.h" #include "core/slang-basic.h" +#include "core/slang-blob.h" //WORKING: #include "options.h" #include "../renderer-shared.h" @@ -63,11 +63,23 @@ public: ~D3D11Renderer() {} // Renderer implementation - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override; virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) override; virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override; - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() override; - virtual SLANG_NO_THROW TextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() override; + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) override + { + SLANG_UNUSED(swapchain); + } + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout( + const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) override; + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override; virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( IResource::Usage initialUsage, @@ -96,8 +108,10 @@ public: const IDescriptorSetLayout::Desc& desc, IDescriptorSetLayout** outLayout) override; virtual SLANG_NO_THROW Result SLANG_MCALL createPipelineLayout(const IPipelineLayout::Desc& desc, IPipelineLayout** outLayout) override; - virtual SLANG_NO_THROW Result SLANG_MCALL - createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSet( + IDescriptorSetLayout* layout, + IDescriptorSet::Flag::Enum flag, + IDescriptorSet** outDescriptorSet) override; virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override; @@ -106,8 +120,8 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( const ComputePipelineStateDesc& desc, IPipelineState** outState) override; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override; virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) override; virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) override; @@ -129,8 +143,6 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) override; virtual SLANG_NO_THROW void SLANG_MCALL - setDepthStencilTarget(IResourceView* depthStencilView) override; - virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) override; virtual SLANG_NO_THROW void SLANG_MCALL setScissorRects(UInt count, ScissorRect const* rects) override; @@ -432,6 +444,175 @@ public: ComPtr<ID3D11RenderTargetView> m_rtv; }; + class FramebufferLayoutImpl + : public IFramebufferLayout + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebufferLayout* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebufferLayout) + return static_cast<IFramebufferLayout*>(this); + return nullptr; + } + + public: + ShortList<IFramebufferLayout::AttachmentLayout> m_renderTargets; + bool m_hasDepthStencil = false; + IFramebufferLayout::AttachmentLayout m_depthStencil; + }; + + class FramebufferImpl + : public IFramebuffer + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebuffer* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer) + return static_cast<IFramebuffer*>(this); + return nullptr; + } + + public: + ShortList<RefPtr<RenderTargetViewImpl>, kMaxRTVs> renderTargetViews; + ShortList<ID3D11RenderTargetView*, kMaxRTVs> d3dRenderTargetViews; + RefPtr<DepthStencilViewImpl> depthStencilView; + ID3D11DepthStencilView* d3dDepthStencilView; + }; + + class SwapchainImpl + : public ISwapchain + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + ISwapchain* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain) + return static_cast<ISwapchain*>(this); + return nullptr; + } + + public: + Result init(D3D11Renderer* renderer, const ISwapchain::Desc& desc, WindowHandle window) + { + // Return fail on non-supported platforms. + switch (window.type) + { + case WindowHandle::Type::Win32Handle: + break; + default: + return SLANG_FAIL; + } + + m_renderer = renderer; + m_desc = desc; + + // Describe the swap chain. + DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; + swapChainDesc.BufferCount = desc.imageCount; + swapChainDesc.BufferDesc.Width = desc.width; + swapChainDesc.BufferDesc.Height = desc.height; + swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(desc.format); + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.OutputWindow = (HWND)window.handleValues[0]; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.Windowed = TRUE; + + if (!desc.enableVSync) + { + swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + } + + // Swap chain needs the queue so that it can force a flush on it. + ComPtr<IDXGISwapChain> swapChain; + SLANG_RETURN_ON_FAIL(m_renderer->m_dxgiFactory->CreateSwapChain( + m_renderer->m_device, &swapChainDesc, swapChain.writeRef())); + SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef())); + + if (!desc.enableVSync) + { + m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject(); + + int maxLatency = desc.imageCount - 2; + + // Make sure the maximum latency is in the range required by dx12 runtime + maxLatency = (maxLatency < 1) ? 1 : maxLatency; + maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) + ? DXGI_MAX_SWAP_CHAIN_BUFFERS + : maxLatency; + + m_swapChain->SetMaximumFrameLatency(maxLatency); + } + + SLANG_RETURN_ON_FAIL(m_renderer->m_dxgiFactory->MakeWindowAssociation( + (HWND)window.handleValues[0], DXGI_MWA_NO_ALT_ENTER)); + + for (uint32_t i = 0; i < desc.imageCount; i++) + { + ComPtr<ID3D11Resource> d3dResource; + m_swapChain->GetBuffer(0, IID_PPV_ARGS(d3dResource.writeRef())); + ITextureResource::Desc imageDesc = {}; + imageDesc.init2D( + IResource::Type::Texture2D, desc.format, desc.width, desc.height, 0); + RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc, IResource::Usage::RenderTarget); + image->m_resource = d3dResource; + m_images.add(image); + } + return SLANG_OK; + } + virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; } + virtual SLANG_NO_THROW Result + getImage(uint32_t index, ITextureResource** outResource) override + { + m_images[index]->addRef(); + *outResource = m_images[index].Ptr(); + return SLANG_OK; + } + virtual SLANG_NO_THROW Result present() override + { + if (m_swapChainWaitableObject) + { + // check if now is good time to present + // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it + // means that no frame is waiting to be be displayed so there is no point doing a + // present. + const bool shouldPresent = + (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT); + if (shouldPresent) + { + m_swapChain->Present(0, 0); + } + } + else + { + if (SLANG_FAILED(m_swapChain->Present(1, 0))) + { + return SLANG_FAIL; + } + } + return SLANG_OK; + } + + virtual SLANG_NO_THROW uint32_t acquireNextImage() override + { + uint32_t count; + m_swapChain->GetLastPresentCount(&count); + return count % m_images.getCount(); + } + + public: + D3D11Renderer* m_renderer = nullptr; + ISwapchain::Desc m_desc; + HANDLE m_swapChainWaitableObject = nullptr; + ComPtr<IDXGISwapChain2> m_swapChain; + ShortList<RefPtr<TextureResourceImpl>> m_images; + }; + class InputLayoutImpl: public IInputLayout, public RefObject { public: @@ -489,16 +670,6 @@ public: } }; - /// Capture a texture to a file - static HRESULT captureTextureToSurface( - ID3D11Device* device, - ID3D11DeviceContext* context, - TextureResourceImpl* texture, - void* buffer, - size_t* inOutBufferSize, - size_t* outRowPitch, - size_t* outPixelSize); - void _flushGraphicsState(); void _flushComputeState(); @@ -506,21 +677,16 @@ public: ComPtr<ID3D11Device> m_device; ComPtr<ID3D11DeviceContext> m_immediateContext; ComPtr<ID3D11Texture2D> m_backBufferTexture; + ComPtr<IDXGIFactory> m_dxgiFactory; - RefPtr<TextureResourceImpl> m_primaryRenderTargetTexture; - RefPtr<RenderTargetViewImpl> m_primaryRenderTargetView; - -// List<ComPtr<ID3D11RenderTargetView> > m_renderTargetViews; -// List<ComPtr<ID3D11Texture2D> > m_renderTargetTextures; - - bool m_renderTargetBindingsDirty = false; + RefPtr<FramebufferImpl> m_currentFramebuffer; ComPtr<PipelineStateImpl> m_currentPipelineState; - ComPtr<ID3D11RenderTargetView> m_rtvBindings[kMaxRTVs]; - ComPtr<ID3D11DepthStencilView> m_dsvBinding; ComPtr<ID3D11UnorderedAccessView> m_uavBindings[int(PipelineType::CountOf)][kMaxUAVs]; - bool m_targetBindingsDirty[int(PipelineType::CountOf)]; + + bool m_framebufferBindingDirty = true; + bool m_shaderBindingDirty = true; Desc m_desc; @@ -529,10 +695,10 @@ public: bool m_nvapi = false; }; -SlangResult SLANG_MCALL createD3D11Renderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +SlangResult SLANG_MCALL createD3D11Renderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { RefPtr<D3D11Renderer> result = new D3D11Renderer(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc, windowHandle)); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); *outRenderer = result.detach(); return SLANG_OK; } @@ -575,87 +741,6 @@ D3D11Renderer::ScopeNVAPI::~ScopeNVAPI() // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!D3D11Renderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!! -/* static */ HRESULT D3D11Renderer::captureTextureToSurface( - ID3D11Device* device, - ID3D11DeviceContext* context, - TextureResourceImpl* texture, - void* buffer, - size_t* inOutBufferSize, - size_t* outRowPitch, - size_t* outPixelSize) -{ - if (!context) return E_INVALIDARG; - if (!texture) return E_INVALIDARG; - - // Don't bother supporting MSAA for right now - if (texture->getDesc()->sampleDesc.numSamples > 1) - { - fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); - return E_INVALIDARG; - } - - size_t bytesPerPixel = sizeof(uint32_t); - size_t rowPitch = int(texture->getDesc()->size.width) * bytesPerPixel; - size_t bufferSize = rowPitch * int(texture->getDesc()->size.height); - if (outRowPitch) - *outRowPitch = rowPitch; - if (outPixelSize) - *outPixelSize = bytesPerPixel; - if (!buffer || *inOutBufferSize == 0) - { - *inOutBufferSize = bufferSize; - return S_OK; - } - if (*inOutBufferSize < bufferSize) - return SLANG_ERROR_INSUFFICIENT_BUFFER; - - D3D11_TEXTURE2D_DESC textureDesc; - auto d3d11Texture = ((ID3D11Texture2D*)texture->m_resource.get()); - d3d11Texture->GetDesc(&textureDesc); - - HRESULT hr = S_OK; - ComPtr<ID3D11Texture2D> stagingTexture; - - if (textureDesc.Usage == D3D11_USAGE_STAGING && (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) - { - stagingTexture = d3d11Texture; - } - else - { - // Modify the descriptor to give us a staging texture - textureDesc.BindFlags = 0; - textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE; - textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - textureDesc.Usage = D3D11_USAGE_STAGING; - - hr = device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef()); - if (FAILED(hr)) - { - fprintf(stderr, "ERROR: failed to create staging texture\n"); - return hr; - } - - context->CopyResource(stagingTexture, d3d11Texture); - } - - // Now just read back texels from the staging textures - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - SLANG_RETURN_ON_FAIL(context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource)); - - for (size_t y = 0; y < textureDesc.Height; y++) - { - memcpy( - (char*)buffer + y * (*outRowPitch), - (char*)mappedResource.pData + y * mappedResource.RowPitch, - *outRowPitch); - } - // Make sure to unmap - context->Unmap(stagingTexture, 0); - return SLANG_OK; - } -} - // !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! static bool _isSupportedNVAPIOp(IUnknown* dev, uint32_t op) @@ -671,13 +756,12 @@ static bool _isSupportedNVAPIOp(IUnknown* dev, uint32_t op) #endif } -SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) +SlangResult D3D11Renderer::initialize(const Desc& desc) { SLANG_RETURN_ON_FAIL(slangContext.initialize(desc.slang, SLANG_DXBC, "sm_5_0")); - SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc, inWindowHandle)); + SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc)); - auto windowHandle = (HWND)inWindowHandle; m_desc = desc; // Rather than statically link against D3D, we load it dynamically. @@ -706,24 +790,6 @@ SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) return SLANG_FAIL; } - // Our swap chain uses RGBA8 with sRGB, with double buffering. - DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - - // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we - // can get consistent output with OpenGL, where setting up sRGB will - // probably be more involved. - // swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferCount = 2; - swapChainDesc.OutputWindow = windowHandle; - swapChainDesc.Windowed = TRUE; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swapChainDesc.Flags = 0; - // We will ask for the highest feature level that can be supported. const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, @@ -757,11 +823,13 @@ SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) combiner.add(DeviceCheckFlag::UseHardwareDevice, ChangeType::OnOff); ///< First try hardware, then reference combiner.add(DeviceCheckFlag::UseFullFeatureLevel, ChangeType::OnOff); ///< First try fully featured, then degrade features + const int numCombinations = combiner.getNumCombinations(); Result res = SLANG_FAIL; for (int i = 0; i < numCombinations; ++i) { const auto deviceCheckFlags = combiner.getCombination(i); + D3DUtil::createFactory(deviceCheckFlags, m_dxgiFactory); // If we have an adapter set on the desc, look it up. We only need to do so for hardware ComPtr<IDXGIAdapter> adapter; @@ -787,36 +855,17 @@ SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) const int startFeatureIndex = (deviceCheckFlags & DeviceCheckFlag::UseFullFeatureLevel) ? 0 : 1; const UINT deviceFlags = (deviceCheckFlags & DeviceCheckFlag::UseDebug) ? D3D11_CREATE_DEVICE_DEBUG : 0; - if (windowHandle) - { - res = D3D11CreateDeviceAndSwapChain_( - adapter, - driverType, - nullptr, // software - deviceFlags, - &featureLevels[startFeatureIndex], - totalNumFeatureLevels - startFeatureIndex, - D3D11_SDK_VERSION, - &swapChainDesc, - m_swapChain.writeRef(), - m_device.writeRef(), - &featureLevel, - m_immediateContext.writeRef()); - } - else - { - res = D3D11CreateDevice_( - adapter, - driverType, - nullptr, - deviceFlags, - &featureLevels[startFeatureIndex], - totalNumFeatureLevels - startFeatureIndex, - D3D11_SDK_VERSION, - m_device.writeRef(), - &featureLevel, - m_immediateContext.writeRef()); - } + res = D3D11CreateDevice_( + adapter, + driverType, + nullptr, + deviceFlags, + &featureLevels[startFeatureIndex], + totalNumFeatureLevels - startFeatureIndex, + D3D11_SDK_VERSION, + m_device.writeRef(), + &featureLevel, + m_immediateContext.writeRef()); // Check if successfully constructed - if so we are done. if (SLANG_SUCCEEDED(res)) { @@ -830,7 +879,6 @@ SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) } // Check we have a swap chain, context and device SLANG_ASSERT(m_immediateContext && m_device); - SLANG_ASSERT(!windowHandle || m_swapChain); } // NVAPI @@ -859,68 +907,6 @@ SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) m_nvapi = true; #endif } - - // TODO: Add support for debugging to help detect leaks: - // - // ComPtr<ID3D11Debug> gDebug; - // m_device->QueryInterface(IID_PPV_ARGS(gDebug.writeRef())); - // - - // After we've created the swap chain, we can request a pointer to the - // back buffer as a D3D11 texture, and create a render-target view from it. - - static const IID kIID_ID3D11Texture2D = { - 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, - 0x95, 0x35, 0xd3, 0x4f, 0x9c }; - if (m_swapChain) - { - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)m_backBufferTexture.writeRef())); - - // for (int i = 0; i < 8; i++) - { - ComPtr<ID3D11Texture2D> texture; - D3D11_TEXTURE2D_DESC textureDesc; - m_backBufferTexture->GetDesc(&textureDesc); - SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, texture.writeRef())); - - ComPtr<ID3D11RenderTargetView> rtv; - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, rtv.writeRef())); - - TextureResource::Desc resourceDesc; - resourceDesc.init2D(IResource::Type::Texture2D, Format::RGBA_Unorm_UInt8, textureDesc.Width, textureDesc.Height, 1); - - ComPtr<ITextureResource> primaryRenderTargetTexture; - SLANG_RETURN_ON_FAIL(createTextureResource(IResource::Usage::RenderTarget, resourceDesc, nullptr, primaryRenderTargetTexture.writeRef())); - - IResourceView::Desc viewDesc; - viewDesc.format = resourceDesc.format; - viewDesc.type = IResourceView::Type::RenderTarget; - ComPtr<IResourceView> primaryRenderTargetView; - SLANG_RETURN_ON_FAIL(createTextureView(primaryRenderTargetTexture, viewDesc, primaryRenderTargetView.writeRef())); - - m_primaryRenderTargetTexture = dynamic_cast<TextureResourceImpl*>(primaryRenderTargetTexture.get()); - m_primaryRenderTargetView = dynamic_cast<RenderTargetViewImpl*>(primaryRenderTargetView.get()); - } - - // m_immediateContext->OMSetRenderTargets(1, m_primaryRenderTargetView->m_rtv.readRef(), nullptr); - m_rtvBindings[0] = m_primaryRenderTargetView->m_rtv; - m_targetBindingsDirty[int(PipelineType::Graphics)] = true; - - // Similarly, we are going to set up a viewport once, and then never - // switch, since this is a simple test app. - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = (float)desc.width; - viewport.Height = (float)desc.height; - viewport.MaxDepth = 1; // TODO(tfoley): use reversed depth - viewport.MinDepth = 0; - m_immediateContext->RSSetViewports(1, &viewport); - } return SLANG_OK; } @@ -931,42 +917,146 @@ void D3D11Renderer::setClearColor(const float color[4]) void D3D11Renderer::clearFrame() { - m_immediateContext->ClearRenderTargetView(m_primaryRenderTargetView->m_rtv, m_clearColor); + for (auto rtv : m_currentFramebuffer->renderTargetViews) + m_immediateContext->ClearRenderTargetView(rtv->m_rtv, m_clearColor); - if(m_dsvBinding) + if (m_currentFramebuffer->depthStencilView) { - m_immediateContext->ClearDepthStencilView(m_dsvBinding, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + m_immediateContext->ClearDepthStencilView( + m_currentFramebuffer->depthStencilView->m_dsv, + D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, + 1.0f, + 0); } } -void D3D11Renderer::presentFrame() +void D3D11Renderer::beginFrame() { } + +void D3D11Renderer::endFrame() {} + +Result D3D11Renderer::createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) { - m_immediateContext->CopyResource(m_backBufferTexture, m_primaryRenderTargetTexture->m_resource); - m_swapChain->Present(0, 0); + RefPtr<SwapchainImpl> swapchain = new SwapchainImpl(); + SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window)); + *outSwapchain = swapchain.detach(); + return SLANG_OK; } -TextureResource::Desc D3D11Renderer::getSwapChainTextureDesc() +Result D3D11Renderer::createFramebufferLayout( + const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) { - D3D11_TEXTURE2D_DESC dxDesc; - ((ID3D11Texture2D*)m_primaryRenderTargetTexture->m_resource.get())->GetDesc(&dxDesc); + RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl(); + layout->m_renderTargets.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + layout->m_renderTargets[i] = desc.renderTargets[i]; + } - TextureResource::Desc desc; - desc.init2D(IResource::Type::Texture2D, Format::Unknown, dxDesc.Width, dxDesc.Height, 1); + if (desc.depthStencil) + { + layout->m_hasDepthStencil = true; + layout->m_depthStencil = *desc.depthStencil; + } + else + { + layout->m_hasDepthStencil = false; + } + *outLayout = layout.detach(); + return SLANG_OK; +} + +Result D3D11Renderer::createFramebuffer( + const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) +{ + RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl(); + framebuffer->renderTargetViews.setCount(desc.renderTargetCount); + framebuffer->d3dRenderTargetViews.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + framebuffer->renderTargetViews[i] = static_cast<RenderTargetViewImpl*>(desc.renderTargetViews[i]); + framebuffer->d3dRenderTargetViews[i] = framebuffer->renderTargetViews[i]->m_rtv; + } + framebuffer->depthStencilView = static_cast<DepthStencilViewImpl*>(desc.depthStencilView); + framebuffer->d3dDepthStencilView = framebuffer->depthStencilView->m_dsv; + *outFramebuffer = framebuffer.detach(); + return SLANG_OK; +} - return desc; +void D3D11Renderer::setFramebuffer(IFramebuffer* frameBuffer) +{ + m_framebufferBindingDirty = true; + m_currentFramebuffer = static_cast<FramebufferImpl*>(frameBuffer); } -SlangResult D3D11Renderer::captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) +SlangResult D3D11Renderer::readTextureResource( + ITextureResource* resource, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) { - return captureTextureToSurface( - m_device, - m_immediateContext, - m_primaryRenderTargetTexture.Ptr(), - buffer, - inOutBufferSize, - outRowPitch, - outPixelSize); + auto texture = static_cast<TextureResourceImpl*>(resource); + // Don't bother supporting MSAA for right now + if (texture->getDesc()->sampleDesc.numSamples > 1) + { + fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); + return E_INVALIDARG; + } + + size_t bytesPerPixel = sizeof(uint32_t); + size_t rowPitch = int(texture->getDesc()->size.width) * bytesPerPixel; + size_t bufferSize = rowPitch * int(texture->getDesc()->size.height); + if (outRowPitch) + *outRowPitch = rowPitch; + if (outPixelSize) + *outPixelSize = bytesPerPixel; + + D3D11_TEXTURE2D_DESC textureDesc; + auto d3d11Texture = ((ID3D11Texture2D*)texture->m_resource.get()); + d3d11Texture->GetDesc(&textureDesc); + + HRESULT hr = S_OK; + ComPtr<ID3D11Texture2D> stagingTexture; + + if (textureDesc.Usage == D3D11_USAGE_STAGING && + (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) + { + stagingTexture = d3d11Texture; + } + else + { + // Modify the descriptor to give us a staging texture + textureDesc.BindFlags = 0; + textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE; + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.Usage = D3D11_USAGE_STAGING; + + hr = m_device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef()); + if (FAILED(hr)) + { + fprintf(stderr, "ERROR: failed to create staging texture\n"); + return hr; + } + + m_immediateContext->CopyResource(stagingTexture, d3d11Texture); + } + + // Now just read back texels from the staging textures + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + SLANG_RETURN_ON_FAIL(m_immediateContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource)); + RefPtr<ListBlob> blob = new ListBlob(); + blob->m_data.setCount(bufferSize); + char* buffer = (char*)blob->m_data.begin(); + for (size_t y = 0; y < textureDesc.Height; y++) + { + memcpy( + (char*)buffer + y * (*outRowPitch), + (char*)mappedResource.pData + y * mappedResource.RowPitch, + *outRowPitch); + } + // Make sure to unmap + m_immediateContext->Unmap(stagingTexture, 0); + *outBlob = blob.detach(); + return SLANG_OK; + } } static D3D11_BIND_FLAG _calcResourceFlag(IResource::BindFlag::Enum bindFlag) @@ -1661,12 +1751,6 @@ void D3D11Renderer::setIndexBuffer(IBufferResource* buffer, Format indexFormat, m_immediateContext->IASetIndexBuffer(((BufferResourceImpl*)buffer)->m_buffer, dxFormat, UINT(offset)); } -void D3D11Renderer::setDepthStencilTarget(IResourceView* depthStencilView) -{ - m_dsvBinding = ((DepthStencilViewImpl*) depthStencilView)->m_dsv; - m_targetBindingsDirty[int(PipelineType::Graphics)] = true; -} - void D3D11Renderer::setViewports(UInt count, Viewport const* viewports) { static const int kMaxViewports = D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX + 1; @@ -2097,9 +2181,10 @@ Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes state->m_depthStencilState = depthStencilState; state->m_rasterizerState = rasterizerState; state->m_blendState = blendState; - state->m_pipelineLayout = (PipelineLayoutImpl*) desc.pipelineLayout; - state->m_inputLayout = (InputLayoutImpl*) desc.inputLayout; - state->m_rtvCount = UINT(desc.renderTargetCount); + state->m_pipelineLayout = static_cast<PipelineLayoutImpl*>(desc.pipelineLayout); + state->m_inputLayout = static_cast<InputLayoutImpl*>(desc.inputLayout); + state->m_rtvCount = (UINT) static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout) + ->m_renderTargets.getCount(); state->m_blendColor[0] = 0; state->m_blendColor[1] = 0; state->m_blendColor[2] = 0; @@ -2258,8 +2343,10 @@ Result D3D11Renderer::createPipelineLayout(const IPipelineLayout::Desc& desc, IP return SLANG_OK; } -Result D3D11Renderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) +Result D3D11Renderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) { + SLANG_UNUSED(flag); + auto layoutImpl = (DescriptorSetLayoutImpl*)layout; RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl(); @@ -2321,19 +2408,19 @@ Result D3D11Renderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescrip void D3D11Renderer::_flushGraphicsState() { auto pipelineType = int(PipelineType::Graphics); - if(m_targetBindingsDirty[pipelineType]) + if (m_framebufferBindingDirty || m_shaderBindingDirty) { - m_targetBindingsDirty[pipelineType] = false; + m_framebufferBindingDirty = false; + m_shaderBindingDirty = false; auto pipelineState = static_cast<GraphicsPipelineStateImpl*>(m_currentPipelineState.get()); - auto rtvCount = pipelineState->m_rtvCount; + auto rtvCount = (UINT)m_currentFramebuffer->renderTargetViews.getCount(); auto uavCount = pipelineState->m_pipelineLayout->m_uavCount; - m_immediateContext->OMSetRenderTargetsAndUnorderedAccessViews( rtvCount, - m_rtvBindings[0].readRef(), - m_dsvBinding, + m_currentFramebuffer->d3dRenderTargetViews.getArrayView().getBuffer(), + m_currentFramebuffer->d3dDepthStencilView, rtvCount, uavCount, m_uavBindings[pipelineType][0].readRef(), @@ -2344,9 +2431,9 @@ void D3D11Renderer::_flushGraphicsState() void D3D11Renderer::_flushComputeState() { auto pipelineType = int(PipelineType::Compute); - if(m_targetBindingsDirty[pipelineType]) + if (m_shaderBindingDirty) { - m_targetBindingsDirty[pipelineType] = false; + m_shaderBindingDirty = false; auto pipelineState = static_cast<ComputePipelineStateImpl*>(m_currentPipelineState.get()); @@ -2568,7 +2655,7 @@ void D3D11Renderer::setDescriptorSet(PipelineType pipelineType, IPipelineLayout* { m_uavBindings[int(pipelineType)][startSlot + ii] = uavs[ii]; } - m_targetBindingsDirty[int(pipelineType)] = true; + m_shaderBindingDirty = true; } } } diff --git a/tools/gfx/d3d11/render-d3d11.h b/tools/gfx/d3d11/render-d3d11.h index 1c81b688c..42887ed1b 100644 --- a/tools/gfx/d3d11/render-d3d11.h +++ b/tools/gfx/d3d11/render-d3d11.h @@ -6,6 +6,6 @@ namespace gfx { -SlangResult SLANG_MCALL createD3D11Renderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); +SlangResult SLANG_MCALL createD3D11Renderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } // gfx diff --git a/tools/gfx/d3d12/descriptor-heap-d3d12.h b/tools/gfx/d3d12/descriptor-heap-d3d12.h index 642ff59db..20d867155 100644 --- a/tools/gfx/d3d12/descriptor-heap-d3d12.h +++ b/tools/gfx/d3d12/descriptor-heap-d3d12.h @@ -6,6 +6,7 @@ #include "slang-com-ptr.h" #include "core/slang-list.h" +#include "core/slang-virtual-object-pool.h" namespace gfx { @@ -76,8 +77,6 @@ struct D3D12HostVisibleDescriptor /// /// Unlike the `D3D12DescriptorHeap` type, this class allows for both /// allocation and freeing of descriptors, by maintaining a free list. -/// In order to keep the implementation simple, this class only supports -/// allocation of single descriptors and not ranges. /// class D3D12HostVisibleDescriptorAllocator { @@ -86,8 +85,7 @@ class D3D12HostVisibleDescriptorAllocator D3D12_DESCRIPTOR_HEAP_TYPE m_type; D3D12DescriptorHeap m_heap; - Slang::List<D3D12HostVisibleDescriptor> m_freeList; - Slang::List<D3D12DescriptorHeap> m_heaps; + Slang::VirtualObjectPool m_allocator; public: D3D12HostVisibleDescriptorAllocator() @@ -100,36 +98,29 @@ public: m_type = type; SLANG_RETURN_ON_FAIL(m_heap.init(m_device, m_chunkSize, m_type, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - + m_allocator.initPool(m_chunkSize); return SLANG_OK; } - Slang::Result allocate(D3D12HostVisibleDescriptor* outDescriptor) + SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle(int index) const { - // TODO: this allocator would take some work to make thread-safe + return m_heap.getCpuHandle(index); + } - if(m_freeList.getCount() > 0) - { - auto descriptor = m_freeList[0]; - m_freeList.fastRemoveAt(0); + int allocate(int count) + { + return m_allocator.alloc(count); + } - *outDescriptor = descriptor; - return SLANG_OK; - } + Slang::Result allocate(D3D12HostVisibleDescriptor* outDescriptor) + { + // TODO: this allocator would take some work to make thread-safe - int index = m_heap.allocate(); + int index = m_allocator.alloc(1); if(index < 0) { - // Allocate a new heap and try again. - m_heaps.add(m_heap); - SLANG_RETURN_ON_FAIL(m_heap.init(m_device, m_chunkSize, m_type, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - - int index = m_heap.allocate(); - if(index < 0) - { - assert(!"descriptor allocation failed on fresh heap"); - return SLANG_FAIL; - } + assert(!"descriptor allocation failed"); + return SLANG_FAIL; } D3D12HostVisibleDescriptor descriptor; @@ -139,9 +130,16 @@ public: return SLANG_OK; } + void free(int index, int count) + { + m_allocator.free(index, count); + } + void free(D3D12HostVisibleDescriptor descriptor) { - m_freeList.add(descriptor); + auto index = + (int)(descriptor.cpuHandle.ptr - m_heap.getCpuStart().ptr) / m_heap.getDescriptorSize(); + free(index, 1); } }; diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index 2e1959bde..4e80ff47a 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -6,7 +6,7 @@ //WORKING:#include "options.h" #include "../renderer-shared.h" #include "../render-graphics-common.h" - +#include "core/slang-blob.h" #include "core/slang-basic.h" // In order to use the Slang API, we need to include its header @@ -66,11 +66,17 @@ class D3D12Renderer : public GraphicsAPIRenderer { public: // Renderer implementation - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override; virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) override; virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override; - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() override; - virtual SLANG_NO_THROW ITextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() override; + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + const ISwapchain::Desc& desc, + WindowHandle window, + ISwapchain** outSwapchain) override; virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( IResource::Usage initialUsage, @@ -92,6 +98,12 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView( IBufferResource* buffer, IResourceView::Desc const& desc, IResourceView** outView) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebufferLayout(IFramebufferLayout::Desc const& desc, IFramebufferLayout** outLayout) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount, @@ -102,7 +114,9 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createPipelineLayout( const IPipelineLayout::Desc& desc, IPipelineLayout** outLayout) override; virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSet( - IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) override; + IDescriptorSetLayout* layout, + IDescriptorSet::Flag::Enum flag, + IDescriptorSet** outDescriptorSet) override; virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override; @@ -111,8 +125,8 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( const ComputePipelineStateDesc& desc, IPipelineState** outState) override; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* resource, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override; virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) override; @@ -135,12 +149,12 @@ public: const UInt* offsets) override; virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) override; - virtual void SLANG_MCALL setDepthStencilTarget(IResourceView* depthStencilView) override; virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) override; virtual SLANG_NO_THROW void SLANG_MCALL setScissorRects(UInt count, ScissorRect const* rects) override; virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) override; + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override; virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex) override; virtual SLANG_NO_THROW void SLANG_MCALL drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override; @@ -202,6 +216,18 @@ protected: } ComPtr<ID3D12CommandAllocator> m_commandAllocator; ///< The command allocator for this frame UINT64 m_fenceValue; ///< The fence value when rendering this Frame is complete + + // During command submission, we need all the descriptor tables that get + // used to come from a single heap (for each descriptor heap type). + // + // We will thus keep a single heap of each type that we hope will hold + // all the descriptors that actually get needed in a frame. + // + // TODO: we need an allocation policy to reallocate and resize these + // if/when we run out of space during a frame. + // + D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav + D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers }; class ShaderProgramImpl : public GraphicsCommonShaderProgram @@ -315,7 +341,12 @@ protected: return nullptr; } public: - D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle; + D3D12HostVisibleDescriptor m_descriptor; + D3D12Renderer* m_renderer; + ~SamplerStateImpl() + { + m_renderer->m_samplerAllocator.free(m_descriptor); + } }; class ResourceViewImpl : public IResourceView, public RefObject @@ -333,6 +364,189 @@ protected: D3D12HostVisibleDescriptor m_descriptor; }; + class FramebufferLayoutImpl + : public IFramebufferLayout + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebufferLayout* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebufferLayout) + return static_cast<IFramebufferLayout*>(this); + return nullptr; + } + + public: + ShortList<IFramebufferLayout::AttachmentLayout> m_renderTargets; + bool m_hasDepthStencil = false; + IFramebufferLayout::AttachmentLayout m_depthStencil; + }; + + class FramebufferImpl + : public IFramebuffer + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebuffer* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer) + return static_cast<IFramebuffer*>(this); + return nullptr; + } + + public: + ShortList<ComPtr<IResourceView>> renderTargetViews; + ComPtr<IResourceView> depthStencilView; + ShortList<D3D12_CPU_DESCRIPTOR_HANDLE> renderTargetDescriptors; + D3D12_CPU_DESCRIPTOR_HANDLE depthStencilDescriptor; + }; + + class SwapchainImpl + : public ISwapchain + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + ISwapchain* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain) + return static_cast<ISwapchain*>(this); + return nullptr; + } + + public: + Result init(D3D12Renderer* renderer, const ISwapchain::Desc& desc, WindowHandle window) + { + // Return fail on non-supported platforms. + switch (window.type) + { + case WindowHandle::Type::Win32Handle: + break; + default: + return SLANG_FAIL; + } + + m_renderer = renderer; + m_desc = desc; + + // Describe the swap chain. + DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; + swapChainDesc.BufferCount = desc.imageCount; + swapChainDesc.BufferDesc.Width = desc.width; + swapChainDesc.BufferDesc.Height = desc.height; + swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(desc.format); + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.OutputWindow = (HWND)window.handleValues[0]; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.Windowed = TRUE; + + if (!desc.enableVSync) + { + swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + } + + // Swap chain needs the queue so that it can force a flush on it. + ComPtr<IDXGISwapChain> swapChain; + SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->CreateSwapChain( + m_renderer->m_commandQueue, &swapChainDesc, swapChain.writeRef())); + SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef())); + + if (!desc.enableVSync) + { + m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject(); + + int maxLatency = desc.imageCount - 2; + + // Make sure the maximum latency is in the range required by dx12 runtime + maxLatency = (maxLatency < 1) ? 1 : maxLatency; + maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) + ? DXGI_MAX_SWAP_CHAIN_BUFFERS + : maxLatency; + + m_swapChain->SetMaximumFrameLatency(maxLatency); + } + + // This sample does not support fullscreen transitions. + SLANG_RETURN_ON_FAIL(m_renderer->m_deviceInfo.m_dxgiFactory->MakeWindowAssociation( + (HWND)window.handleValues[0], DXGI_MWA_NO_ALT_ENTER)); + + m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); + + for (uint32_t i = 0; i < desc.imageCount; i++) + { + ComPtr<ID3D12Resource> d3dResource; + m_swapChain->GetBuffer(i, IID_PPV_ARGS(d3dResource.writeRef())); + ITextureResource::Desc imageDesc = {}; + imageDesc.init2D( + IResource::Type::Texture2D, desc.format, desc.width, desc.height, 0); + RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc); + image->m_resource.setResource(d3dResource.get(), D3D12_RESOURCE_STATE_COMMON); + m_images.add(image); + } + return SLANG_OK; + } + virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; } + virtual SLANG_NO_THROW Result getImage(uint32_t index, ITextureResource** outResource) override + { + m_images[index]->addRef(); + *outResource = m_images[index].Ptr(); + return SLANG_OK; + } + void makeBackbufferPresentable() + { + D3D12BarrierSubmitter submitter(m_renderer->m_commandList); + m_images[m_renderTargetIndex]->m_resource.transition( + D3D12_RESOURCE_STATE_PRESENT, submitter); + } + virtual SLANG_NO_THROW Result present() override + { + if (m_swapChainWaitableObject) + { + // check if now is good time to present + // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it + // means that no frame is waiting to be be displayed so there is no point doing a + // present. + const bool shouldPresent = + (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT); + if (shouldPresent) + { + m_swapChain->Present(0, 0); + } + } + else + { + if (SLANG_FAILED(m_swapChain->Present(1, 0))) + { + return SLANG_FAIL; + } + } + // Update the render target index. + m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); + return SLANG_OK; + } + + virtual SLANG_NO_THROW uint32_t acquireNextImage() override + { + // `IRenderer::beginFrame()` must be called before `acquireNextImage`. + SLANG_RELEASE_ASSERT(m_renderer->m_commandListOpenCount == 1); + + D3D12BarrierSubmitter submitter(m_renderer->m_commandList); + m_images[m_renderTargetIndex]->m_resource.transition( + D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); + return m_renderTargetIndex; + } + public: + D3D12Renderer* m_renderer = nullptr; + ISwapchain::Desc m_desc; + HANDLE m_swapChainWaitableObject = nullptr; + ComPtr<IDXGISwapChain3> m_swapChain; + uint32_t m_renderTargetIndex; + ShortList<RefPtr<TextureResourceImpl>> m_images; + }; + class InputLayoutImpl: public IInputLayout, public RefObject { public: @@ -495,8 +709,8 @@ protected: D3D12Renderer* m_renderer = nullptr; ///< Weak pointer - must be because if set on Renderer, will have a circular reference RefPtr<DescriptorSetLayoutImpl> m_layout; - D3D12DescriptorHeap* m_resourceHeap = nullptr; - D3D12DescriptorHeap* m_samplerHeap = nullptr; + D3D12HostVisibleDescriptorAllocator* m_resourceHeap = nullptr; + D3D12HostVisibleDescriptorAllocator* m_samplerHeap = nullptr; Int m_resourceTable = 0; Int m_samplerTable = 0; @@ -514,20 +728,15 @@ protected: /// Backing storage for root constant ranges in this descriptor set. List<char> m_rootConstantData; - }; - - // During command submission, we need all the descriptor tables that get - // used to come from a single heap (for each descriptor heap type). - // - // We will thus keep a single heap of each type that we hope will hold - // all the descriptors that actually get needed in a frame. - // - // TODO: we need an allocation policy to reallocate and resize these - // if/when we run out of space during a frame. - // - D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav - D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers + ~DescriptorSetImpl() + { + if (m_resourceObjects.getCount()) + m_resourceHeap->free((int)m_resourceTable, (int)m_resourceObjects.getCount()); + if (m_samplerObjects.getCount()) + m_samplerHeap->free((int)m_samplerTable, (int)m_samplerObjects.getCount()); + } + }; D3D12HostVisibleDescriptorAllocator m_rtvAllocator; D3D12HostVisibleDescriptorAllocator m_dsvAllocator; @@ -539,8 +748,8 @@ protected: // around CPU-visible heaps for storing descriptors in a format // that is ready for copying into the GPU-visible heaps as needed. // - D3D12DescriptorHeap m_cpuViewHeap; ///< Cbv, Srv, Uav - D3D12DescriptorHeap m_cpuSamplerHeap; ///< Heap for samplers + D3D12HostVisibleDescriptorAllocator m_cpuViewHeap; ///< Cbv, Srv, Uav + D3D12HostVisibleDescriptorAllocator m_cpuSamplerHeap; ///< Heap for samplers class PipelineStateImpl : public PipelineStateBase { @@ -639,17 +848,12 @@ protected: Result createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, size_t srcDataSize, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut); - void beginRender(); - - void endRender(); - void submitGpuWorkAndWait(); void _resetCommandList(); Result captureTextureToSurface( D3D12Resource& resource, - void* buffer, - size_t* inOutBufferSize, + ISlangBlob** blob, size_t* outRowPitch, size_t* outPixelSize); @@ -658,21 +862,10 @@ protected: ID3D12GraphicsCommandList* getCommandList() const { return m_commandList; } -// RenderState* calcRenderState(); - - /// From current bindings calculate the root signature and pipeline state -// Result calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& sigOut, ComPtr<ID3D12PipelineState>& pipelineStateOut); -// Result calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut); - Result _bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter); -// Result _calcBindParameters(BindParameters& params); -// RenderState* findRenderState(PipelineType pipelineType); - Result _createDevice(DeviceCheckFlags deviceCheckFlags, const UnownedStringSlice& nameMatch, D3D_FEATURE_LEVEL featureLevel, DeviceInfo& outDeviceInfo); - D3D12CircularResourceHeap m_circularResourceHeap; - int m_commandListOpenCount = 0; ///< If >0 the command list should be open List<BoundVertexBuffer> m_boundVertexBuffers; @@ -683,21 +876,8 @@ protected: RefPtr<PipelineStateImpl> m_currentPipelineState; -// RefPtr<ShaderProgramImpl> m_boundShaderProgram; -// RefPtr<InputLayoutImpl> m_boundInputLayout; - -// RefPtr<BindingStateImpl> m_boundBindingState; RefPtr<DescriptorSetImpl> m_boundDescriptorSets[int(PipelineType::CountOf)][kMaxDescriptorSetCount]; - DXGI_FORMAT m_targetFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - DXGI_FORMAT m_depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; - bool m_hasVsync = true; - bool m_isFullSpeed = false; - bool m_allowFullScreen = false; - bool m_isMultiSampled = false; - int m_numTargetSamples = 1; ///< The number of multi sample samples - int m_targetSampleQuality = 0; ///< The multi sample quality - Desc m_desc; bool m_isInitialized = false; @@ -707,26 +887,20 @@ protected: float m_clearColor[4] = { 0, 0, 0, 0 }; - D3D12_VIEWPORT m_viewport = {}; + D3D12_VIEWPORT m_viewports[kMaxRTVCount] = {}; ComPtr<ID3D12Debug> m_dxDebug; DeviceInfo m_deviceInfo; ID3D12Device* m_device = nullptr; - ComPtr<IDXGISwapChain3> m_swapChain; ComPtr<ID3D12CommandQueue> m_commandQueue; -// ComPtr<ID3D12DescriptorHeap> m_rtvHeap; ComPtr<ID3D12GraphicsCommandList> m_commandList; - D3D12_RECT m_scissorRect = {}; - -// List<RefPtr<RenderState> > m_renderStates; ///< Holds list of all render state combinations -// RenderState* m_currentRenderState = nullptr; ///< The current combination + D3D12_RECT m_scissorRects[kMaxRTVCount] = {}; UINT m_rtvDescriptorSize = 0; -// ComPtr<ID3D12DescriptorHeap> m_dsvHeap; UINT m_dsvDescriptorSize = 0; // Synchronization objects. @@ -740,17 +914,8 @@ protected: FrameInfo m_frameInfos[kMaxNumRenderFrames]; int m_numRenderTargets = 2; - int m_renderTargetIndex = 0; - - D3D12Resource* m_backBuffers[kMaxNumRenderTargets]; - D3D12Resource* m_renderTargets[kMaxNumRenderTargets]; - - D3D12Resource m_backBufferResources[kMaxNumRenderTargets]; - D3D12Resource m_renderTargetResources[kMaxNumRenderTargets]; - - RefPtr<ResourceViewImpl> m_rtvs[kMaxRTVCount]; - RefPtr<ResourceViewImpl> m_dsv; + RefPtr<FramebufferImpl> m_frameBuffer; int32_t m_depthStencilUsageFlags = 0; ///< D3DUtil::UsageFlag combination for depth stencil int32_t m_targetUsageFlags = 0; ///< D3DUtil::UsageFlag combination for target @@ -760,15 +925,13 @@ protected: PFN_D3D12_CREATE_DEVICE m_D3D12CreateDevice = nullptr; PFN_D3D12_SERIALIZE_ROOT_SIGNATURE m_D3D12SerializeRootSignature = nullptr; - HWND m_hwnd = nullptr; - bool m_nvapi = false; }; -SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { RefPtr<D3D12Renderer> result = new D3D12Renderer(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc, windowHandle)); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); *outRenderer = result.detach(); return SLANG_OK; } @@ -786,22 +949,12 @@ SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, void* w void D3D12Renderer::releaseFrameResources() { - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb174577%28v=vs.85%29.aspx - - // Release the resources holding references to the swap chain (requirement of - // IDXGISwapChain::ResizeBuffers) and reset the frame fence values to the - // current fence value. for (int i = 0; i < m_numRenderFrames; i++) { FrameInfo& info = m_frameInfos[i]; info.reset(); info.m_fenceValue = m_fence.getCurrentValue(); } - for (int i = 0; i < m_numRenderTargets; i++) - { - m_backBuffers[i]->setResourceNull(); - m_renderTargets[i]->setResourceNull(); - } } void D3D12Renderer::waitForGpu() @@ -965,75 +1118,21 @@ void D3D12Renderer::_resetCommandList() ID3D12GraphicsCommandList* commandList = getCommandList(); commandList->Reset(frame.m_commandAllocator, nullptr); - - // TIM: when should this get set? -// commandList->OMSetRenderTargets( -// 1, -// &m_rtvs[0]->m_descriptor.cpuHandle, -// FALSE, -// m_dsv ? &m_dsv->m_descriptor.cpuHandle : nullptr); - - // Set necessary state. - commandList->RSSetViewports(1, &m_viewport); - commandList->RSSetScissorRects(1, &m_scissorRect); } -void D3D12Renderer::beginRender() +void D3D12Renderer::beginFrame() { - // Should currently not be open! - assert(m_commandListOpenCount == 0); - - m_circularResourceHeap.updateCompleted(); - - getFrame().m_commandAllocator->Reset(); - - _resetCommandList(); - - // Indicate that the render target needs to be writable - if (m_swapChain) - { - D3D12BarrierSubmitter submitter(m_commandList); - m_renderTargets[m_renderTargetIndex]->transition(D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); - } +} - m_commandListOpenCount = 1; +void D3D12Renderer::makeSwapchainImagePresentable(ISwapchain* swapchain) +{ + static_cast<SwapchainImpl*>(swapchain)->makeBackbufferPresentable(); } -void D3D12Renderer::endRender() +void D3D12Renderer::endFrame() { assert(m_commandListOpenCount == 1); - - { - const UInt64 signalValue = m_fence.nextSignal(m_commandQueue); - m_circularResourceHeap.addSync(signalValue); - } - if (m_swapChain) - { - D3D12Resource& backBuffer = *m_backBuffers[m_renderTargetIndex]; - if (m_isMultiSampled) - { - // MSAA resolve - D3D12Resource& renderTarget = *m_renderTargets[m_renderTargetIndex]; - assert(&renderTarget != &backBuffer); - // Barriers to wait for the render target, and the backbuffer to be in correct state - { - D3D12BarrierSubmitter submitter(m_commandList); - renderTarget.transition(D3D12_RESOURCE_STATE_RESOLVE_SOURCE, submitter); - backBuffer.transition(D3D12_RESOURCE_STATE_RESOLVE_DEST, submitter); - } - - // Do the resolve... - m_commandList->ResolveSubresource(backBuffer, 0, renderTarget, 0, m_targetFormat); - } - - // Make the back buffer presentable - { - D3D12BarrierSubmitter submitter(m_commandList); - backBuffer.transition(D3D12_RESOURCE_STATE_PRESENT, submitter); - } - } SLANG_ASSERT_VOID_ON_FAIL(m_commandList->Close()); - { // Execute the command list. ID3D12CommandList* commandLists[] = { m_commandList }; @@ -1043,6 +1142,30 @@ void D3D12Renderer::endRender() assert(m_commandListOpenCount == 1); // Must be 0 m_commandListOpenCount = 0; + + + // Increment the fence value. Save on the frame - we'll know that frame is done when the fence + // value >= + m_frameInfos[m_frameIndex].m_fenceValue = m_fence.nextSignal(m_commandQueue); + + // increment frame index after signal + m_frameIndex = (m_frameIndex + 1) % m_numRenderFrames; + + // On the current frame wait until it is completed + { + FrameInfo& frame = m_frameInfos[m_frameIndex]; + // If the next frame is not ready to be rendered yet, wait until it is ready. + m_fence.waitUntilCompleted(frame.m_fenceValue); + } + + getFrame().m_commandAllocator->Reset(); + + _resetCommandList(); + + m_commandListOpenCount = 1; + + getFrame().m_viewHeap.deallocateAll(); + getFrame().m_samplerHeap.deallocateAll(); } void D3D12Renderer::submitGpuWork() @@ -1069,8 +1192,7 @@ void D3D12Renderer::submitGpuWorkAndWait() Result D3D12Renderer::captureTextureToSurface( D3D12Resource& resource, - void* buffer, - size_t* inOutBufferSize, + ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) { @@ -1092,13 +1214,7 @@ Result D3D12Renderer::captureTextureToSurface( *outRowPitch = rowPitch; if (outPixelSize) *outPixelSize = bytesPerPixel; - if (!buffer || *inOutBufferSize == 0) - { - *inOutBufferSize = bufferSize; - return SLANG_OK; - } - if (*inOutBufferSize < bufferSize) - return SLANG_ERROR_INSUFFICIENT_BUFFER; + D3D12Resource stagingResource; { D3D12_RESOURCE_DESC stagingDesc; @@ -1155,9 +1271,11 @@ Result D3D12Renderer::captureTextureToSurface( SLANG_RETURN_ON_FAIL(dxResource->Map(0, &readRange, reinterpret_cast<void**>(&data))); - memcpy(buffer, data, bufferSize); - + RefPtr<Slang::ListBlob> resultBlob = new Slang::ListBlob(); + resultBlob->m_data.setCount(bufferSize); + memcpy(resultBlob->m_data.getBuffer(), data, bufferSize); dxResource->Unmap(0, nullptr); + *outBlob = resultBlob.detach(); return SLANG_OK; } } @@ -1174,8 +1292,8 @@ Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3 ID3D12DescriptorHeap* heaps[] = { - m_viewHeap.getHeap(), - m_samplerHeap.getHeap(), + getFrame().m_viewHeap.getHeap(), + getFrame().m_samplerHeap.getHeap(), }; commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps); @@ -1196,7 +1314,7 @@ Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3 { if(auto descriptorCount = descriptorSetLayout->m_resourceCount) { - auto& gpuHeap = m_viewHeap; + auto& gpuHeap = getFrame().m_viewHeap; auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount)); auto& cpuHeap = *descriptorSet->m_resourceHeap; @@ -1214,7 +1332,7 @@ Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3 { if(auto descriptorCount = descriptorSetLayout->m_samplerCount) { - auto& gpuHeap = m_samplerHeap; + auto& gpuHeap = getFrame().m_samplerHeap; auto gpuDescriptorTable = gpuHeap.allocate(int(descriptorCount)); auto& cpuHeap = *descriptorSet->m_samplerHeap; @@ -1352,14 +1470,12 @@ static bool _isSupportedNVAPIOp(ID3D12Device* dev, uint32_t op) #endif } -Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle) +Result D3D12Renderer::initialize(const Desc& desc) { SLANG_RETURN_ON_FAIL(slangContext.initialize(desc.slang, SLANG_DXBC, "sm_5_1")); - SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc, inWindowHandle)); + SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc)); - m_hwnd = (HWND)inWindowHandle; - // Rather than statically link against D3D, we load it dynamically. HMODULE d3dModule = LoadLibraryA("d3d12.dll"); @@ -1505,23 +1621,6 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle) m_desc = desc; - // set viewport - { - m_viewport.Width = float(m_desc.width); - m_viewport.Height = float(m_desc.height); - m_viewport.MinDepth = 0; - m_viewport.MaxDepth = 1; - m_viewport.TopLeftX = 0; - m_viewport.TopLeftY = 0; - } - - { - m_scissorRect.left = 0; - m_scissorRect.top = 0; - m_scissorRect.right = m_desc.width; - m_scissorRect.bottom = m_desc.height; - } - // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; @@ -1529,62 +1628,22 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle) SLANG_RETURN_ON_FAIL(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_commandQueue.writeRef()))); - if (inWindowHandle) + // Create descriptor heaps. + for (int i = 0; i < m_numRenderFrames; i++) { - // Describe the swap chain. - DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; - swapChainDesc.BufferCount = m_numRenderTargets; - swapChainDesc.BufferDesc.Width = m_desc.width; - swapChainDesc.BufferDesc.Height = m_desc.height; - swapChainDesc.BufferDesc.Format = m_targetFormat; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.OutputWindow = m_hwnd; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.Windowed = TRUE; - - if (m_isFullSpeed) - { - m_hasVsync = false; - m_allowFullScreen = false; - } - - if (!m_hasVsync) - { - swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; - } - - // Swap chain needs the queue so that it can force a flush on it. - ComPtr<IDXGISwapChain> swapChain; - SLANG_RETURN_ON_FAIL(m_deviceInfo.m_dxgiFactory->CreateSwapChain(m_commandQueue, &swapChainDesc, swapChain.writeRef())); - SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef())); - - if (!m_hasVsync) - { - m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject(); - - int maxLatency = m_numRenderTargets - 2; - - // Make sure the maximum latency is in the range required by dx12 runtime - maxLatency = (maxLatency < 1) ? 1 : maxLatency; - maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) ? DXGI_MAX_SWAP_CHAIN_BUFFERS : maxLatency; - - m_swapChain->SetMaximumFrameLatency(maxLatency); - } - - // This sample does not support fullscreen transitions. - SLANG_RETURN_ON_FAIL(m_deviceInfo.m_dxgiFactory->MakeWindowAssociation(m_hwnd, DXGI_MWA_NO_ALT_ENTER)); - - m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); + SLANG_RETURN_ON_FAIL(m_frameInfos[i].m_viewHeap.init( + m_device, + 256, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); + SLANG_RETURN_ON_FAIL(m_frameInfos[i].m_samplerHeap.init( + m_device, + 16, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); } - - // Create descriptor heaps. - - SLANG_RETURN_ON_FAIL(m_viewHeap.init (m_device, 256, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - SLANG_RETURN_ON_FAIL(m_samplerHeap.init(m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - - SLANG_RETURN_ON_FAIL(m_cpuViewHeap.init (m_device, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); - SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap.init(m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE)); + SLANG_RETURN_ON_FAIL(m_cpuViewHeap.init (m_device, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)); + SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap.init(m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)); SLANG_RETURN_ON_FAIL(m_rtvAllocator.init (m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_RTV)); SLANG_RETURN_ON_FAIL(m_dsvAllocator.init (m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_DSV)); @@ -1603,17 +1662,9 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle) m_commandList->Close(); } - { - D3D12CircularResourceHeap::Desc desc; - desc.init(); - // Define size - desc.m_blockSize = 65536; - // Set up the heap - m_circularResourceHeap.init(m_device, desc, &m_fence); - } + _resetCommandList(); - // Setup for rendering - beginRender(); + m_commandListOpenCount = 1; m_isInitialized = true; return SLANG_OK; @@ -1628,133 +1679,6 @@ Result D3D12Renderer::createFrameResources() SLANG_RETURN_ON_FAIL(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frame.m_commandAllocator.writeRef()))); } - // Create back buffers - if (m_swapChain) - { -// D3D12_CPU_DESCRIPTOR_HANDLE rtvStart(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); - - // Work out target format - D3D12_RESOURCE_DESC resourceDesc; - { - ComPtr<ID3D12Resource> backBuffer; - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, IID_PPV_ARGS(backBuffer.writeRef()))); - resourceDesc = backBuffer->GetDesc(); - } - const DXGI_FORMAT resourceFormat = D3DUtil::calcResourceFormat(D3DUtil::USAGE_TARGET, m_targetUsageFlags, resourceDesc.Format); - const DXGI_FORMAT targetFormat = D3DUtil::calcFormat(D3DUtil::USAGE_TARGET, resourceFormat); - - // Set the target format - m_targetFormat = targetFormat; - - // Create a RTV, and a command allocator for each frame. - for (int i = 0; i < m_numRenderTargets; i++) - { - // Get the back buffer - ComPtr<ID3D12Resource> backBuffer; - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(UINT(i), IID_PPV_ARGS(backBuffer.writeRef()))); - - // Set up resource for back buffer - m_backBufferResources[i].setResource(backBuffer, D3D12_RESOURCE_STATE_COMMON); - m_backBuffers[i] = &m_backBufferResources[i]; - // Assume they are the same thing for now... - m_renderTargets[i] = &m_backBufferResources[i]; - - // If we are multi-sampling - create a render target separate from the back buffer - if (m_isMultiSampled) - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - D3D12_CLEAR_VALUE clearValue = {}; - clearValue.Format = m_targetFormat; - - // Don't know targets alignment, so just memory copy - ::memcpy(clearValue.Color, m_clearColor, sizeof(m_clearColor)); - - D3D12_RESOURCE_DESC desc(resourceDesc); - - desc.Format = resourceFormat; - desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - desc.SampleDesc.Count = m_numTargetSamples; - desc.SampleDesc.Quality = m_targetSampleQuality; - desc.Alignment = 0; - - SLANG_RETURN_ON_FAIL(m_renderTargetResources[i].initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue)); - m_renderTargets[i] = &m_renderTargetResources[i]; - } - - D3D12HostVisibleDescriptor rtvDescriptor; - SLANG_RETURN_ON_FAIL(m_rtvAllocator.allocate(&rtvDescriptor)); - - m_device->CreateRenderTargetView(*m_renderTargets[i], nullptr, rtvDescriptor.cpuHandle); - } - } - - if (m_swapChain) - { - D3D12_RESOURCE_DESC desc = m_backBuffers[0]->getResource()->GetDesc(); - assert(desc.Width == UINT64(m_desc.width) && desc.Height == UINT64(m_desc.height)); - } - - // Create the depth stencil view. - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - DXGI_FORMAT resourceFormat = D3DUtil::calcResourceFormat(D3DUtil::USAGE_DEPTH_STENCIL, m_depthStencilUsageFlags, m_depthStencilFormat); - DXGI_FORMAT depthStencilFormat = D3DUtil::calcFormat(D3DUtil::USAGE_DEPTH_STENCIL, resourceFormat); - - // Set the depth stencil format - m_depthStencilFormat = depthStencilFormat; - - // Setup default clear - D3D12_CLEAR_VALUE clearValue = {}; - clearValue.Format = depthStencilFormat; - clearValue.DepthStencil.Depth = 1.0f; - clearValue.DepthStencil.Stencil = 0; - - D3D12_RESOURCE_DESC resourceDesc = {}; - resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - resourceDesc.Format = resourceFormat; - resourceDesc.Width = m_desc.width; - resourceDesc.Height = m_desc.height; - resourceDesc.DepthOrArraySize = 1; - resourceDesc.MipLevels = 1; - resourceDesc.SampleDesc.Count = m_numTargetSamples; - resourceDesc.SampleDesc.Quality = m_targetSampleQuality; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - resourceDesc.Alignment = 0; - -#if 0 - SLANG_RETURN_ON_FAIL(m_depthStencil.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue)); - - // Set the depth stencil - D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; - depthStencilDesc.Format = depthStencilFormat; - depthStencilDesc.ViewDimension = m_isMultiSampled ? D3D12_DSV_DIMENSION_TEXTURE2DMS : D3D12_DSV_DIMENSION_TEXTURE2D; - depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; - - // Set up as the depth stencil view - m_device->CreateDepthStencilView(m_depthStencil, &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); - m_depthStencilView = m_dsvHeap->GetCPUDescriptorHandleForHeapStart(); -#endif - } - - m_viewport.Width = static_cast<float>(m_desc.width); - m_viewport.Height = static_cast<float>(m_desc.height); - m_viewport.MaxDepth = 1.0f; - - m_scissorRect.right = static_cast<LONG>(m_desc.width); - m_scissorRect.bottom = static_cast<LONG>(m_desc.height); - return SLANG_OK; } @@ -1766,72 +1690,35 @@ void D3D12Renderer::setClearColor(const float color[4]) void D3D12Renderer::clearFrame() { // Record commands - if(auto rtv = m_rtvs[0]) + if (!m_frameBuffer) + return; + for (auto rtv : m_frameBuffer->renderTargetDescriptors) { - m_commandList->ClearRenderTargetView(rtv->m_descriptor.cpuHandle, m_clearColor, 0, nullptr); + m_commandList->ClearRenderTargetView(rtv, m_clearColor, 0, nullptr); } - if (m_dsv) + if (m_frameBuffer->depthStencilView) { - m_commandList->ClearDepthStencilView(m_dsv->m_descriptor.cpuHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); + m_commandList->ClearDepthStencilView( + m_frameBuffer->depthStencilDescriptor, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); } } -void D3D12Renderer::presentFrame() +SLANG_NO_THROW Result SLANG_MCALL D3D12Renderer::createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) { - endRender(); - - if (m_swapChainWaitableObject) - { - // check if now is good time to present - // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it means that no frame is waiting to be be displayed - // so there is no point doing a present. - const bool shouldPresent = (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT); - if (shouldPresent) - { - m_swapChain->Present(0, 0); - } - } - else - { - if (SLANG_FAILED(m_swapChain->Present(1, 0))) - { - assert(!"Problem presenting"); - beginRender(); - return; - } - } - - // Increment the fence value. Save on the frame - we'll know that frame is done when the fence value >= - m_frameInfos[m_frameIndex].m_fenceValue = m_fence.nextSignal(m_commandQueue); - - // increment frame index after signal - m_frameIndex = (m_frameIndex + 1) % m_numRenderFrames; - // Update the render target index. - m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); - - // On the current frame wait until it is completed - { - FrameInfo& frame = m_frameInfos[m_frameIndex]; - // If the next frame is not ready to be rendered yet, wait until it is ready. - m_fence.waitUntilCompleted(frame.m_fenceValue); - } - - // Setup such that rendering can restart - beginRender(); -} - -TextureResource::Desc D3D12Renderer::getSwapChainTextureDesc() -{ - TextureResource::Desc desc; - desc.init2D(IResource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1); - - return desc; + RefPtr<SwapchainImpl> swapchain = new SwapchainImpl(); + SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window)); + *outSwapchain = swapchain.detach(); + return SLANG_OK; } -SlangResult D3D12Renderer::captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) +SlangResult D3D12Renderer::readTextureResource( + ITextureResource* resource, + ISlangBlob** outBlob, + size_t* outRowPitch, + size_t* outPixelSize) { - return captureTextureToSurface(*m_renderTargets[m_renderTargetIndex], buffer, inOutBufferSize, outRowPitch, outPixelSize); + return captureTextureToSurface(static_cast<TextureResourceImpl*>(resource)->m_resource, outBlob, outRowPitch, outPixelSize); } static D3D12_RESOURCE_STATES _calcResourceState(IResource::Usage usage) @@ -1934,6 +1821,22 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + + switch (initialUsage) + { + case IResource::Usage::RenderTarget: + resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + break; + case IResource::Usage::DepthWrite: + resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + break; + case IResource::Usage::UnorderedAccess: + resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + break; + default: + break; + } + resourceDesc.Alignment = 0; RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc)); @@ -1948,7 +1851,22 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; - SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); + D3D12_CLEAR_VALUE clearValue; + D3D12_CLEAR_VALUE* clearValuePtr = &clearValue; + if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | + D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0) + { + clearValuePtr = nullptr; + } + clearValue.Format = pixelFormat; + memcpy(clearValue.Color, descIn.optimalClearValue, sizeof(clearValue.Color)); + SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted( + m_device, + heapProps, + D3D12_HEAP_FLAG_NONE, + resourceDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + clearValuePtr)); texture->m_resource.setDebugName(L"Texture"); } @@ -1961,17 +1879,13 @@ Result D3D12Renderer::createTextureResource(IResource::Usage initialUsage, const List<UInt32> mipNumRows; mipNumRows.setCount(numMipMaps); - // Since textures are effectively immutable currently initData must be set - assert(initData); - // We should have this many sub resources - assert(initData->numSubResources == numMipMaps * srcDesc.size.depth * arraySize); - // NOTE! This is just the size for one array upload -> not for the whole texture UInt64 requiredSize = 0; m_device->GetCopyableFootprints(&resourceDesc, 0, numMipMaps, 0, layouts.begin(), mipNumRows.begin(), mipRowSizeInBytes.begin(), &requiredSize); // Sub resource indexing // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing + if (initData) { // Create the upload texture D3D12Resource uploadTexture; @@ -2242,27 +2156,17 @@ Result D3D12Renderer::createSamplerState(ISamplerState::Desc const& desc, ISampl auto samplerHeap = &m_cpuSamplerHeap; - int indexInSamplerHeap = samplerHeap->allocate(); - if(indexInSamplerHeap < 0) - { - // We ran out of room in our CPU sampler heap. - // - // TODO: this should not be a catastrophic failure, because - // we should just allocate another CPU sampler heap that - // can service subsequent allocation. - // - return SLANG_FAIL; - } - auto cpuDescriptorHandle = samplerHeap->getCpuHandle(indexInSamplerHeap); - - m_device->CreateSampler(&dxDesc, cpuDescriptorHandle); + D3D12HostVisibleDescriptor cpuDescriptor; + samplerHeap->allocate(&cpuDescriptor); + m_device->CreateSampler(&dxDesc, cpuDescriptor.cpuHandle); // TODO: We really ought to have a free-list of sampler-heap // entries that we check before we go to the heap, and then // when we are done with a sampler we simply add it to the free list. // RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl(); - samplerImpl->m_cpuHandle = cpuDescriptorHandle; + samplerImpl->m_renderer = this; + samplerImpl->m_descriptor = cpuDescriptor; *outSampler = samplerImpl.detach(); return SLANG_OK; } @@ -2282,14 +2186,53 @@ Result D3D12Renderer::createTextureView(ITextureResource* texture, IResourceView case IResourceView::Type::RenderTarget: { SLANG_RETURN_ON_FAIL(m_rtvAllocator.allocate(&viewImpl->m_descriptor)); - m_device->CreateRenderTargetView(resourceImpl->m_resource, nullptr, viewImpl->m_descriptor.cpuHandle); + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = D3DUtil::getMapFormat(desc.format); + switch (desc.renderTarget.shape) + { + case IResource::Type::Texture1D: + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D; + rtvDesc.Texture1D.MipSlice = desc.renderTarget.mipSlice; + break; + case IResource::Type::Texture2D: + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = desc.renderTarget.mipSlice; + rtvDesc.Texture2D.PlaneSlice = desc.renderTarget.planeIndex; + break; + case IResource::Type::Texture3D: + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = desc.renderTarget.mipSlice; + rtvDesc.Texture3D.FirstWSlice = desc.renderTarget.arrayIndex; + rtvDesc.Texture3D.WSize = desc.renderTarget.arraySize; + break; + default: + return SLANG_FAIL; + } + m_device->CreateRenderTargetView( + resourceImpl->m_resource, &rtvDesc, viewImpl->m_descriptor.cpuHandle); } break; case IResourceView::Type::DepthStencil: { SLANG_RETURN_ON_FAIL(m_dsvAllocator.allocate(&viewImpl->m_descriptor)); - m_device->CreateDepthStencilView(resourceImpl->m_resource, nullptr, viewImpl->m_descriptor.cpuHandle); + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.Format = D3DUtil::getMapFormat(desc.format); + switch (desc.renderTarget.shape) + { + case IResource::Type::Texture1D: + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D; + dsvDesc.Texture1D.MipSlice = desc.renderTarget.mipSlice; + break; + case IResource::Type::Texture2D: + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = desc.renderTarget.mipSlice; + break; + default: + return SLANG_FAIL; + } + m_device->CreateDepthStencilView( + resourceImpl->m_resource, &dsvDesc, viewImpl->m_descriptor.cpuHandle); } break; @@ -2403,6 +2346,54 @@ Result D3D12Renderer::createBufferView(IBufferResource* buffer, IResourceView::D return SLANG_OK; } +Result D3D12Renderer::createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFb) +{ + RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl(); + framebuffer->renderTargetViews.setCount(desc.renderTargetCount); + framebuffer->renderTargetDescriptors.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + framebuffer->renderTargetViews[i] = desc.renderTargetViews[i]; + framebuffer->renderTargetDescriptors[i] = + static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_descriptor.cpuHandle; + } + framebuffer->depthStencilView = desc.depthStencilView; + if (desc.depthStencilView) + { + framebuffer->depthStencilDescriptor = + static_cast<ResourceViewImpl*>(desc.depthStencilView)->m_descriptor.cpuHandle; + } + else + { + framebuffer->depthStencilDescriptor.ptr = 0; + } + *outFb = framebuffer.detach(); + return SLANG_OK; +} + +Result D3D12Renderer::createFramebufferLayout( + IFramebufferLayout::Desc const& desc, IFramebufferLayout** outLayout) +{ + RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl(); + layout->m_renderTargets.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + layout->m_renderTargets[i] = desc.renderTargets[i]; + } + + if (desc.depthStencil) + { + layout->m_hasDepthStencil = true; + layout->m_depthStencil = *desc.depthStencil; + } + else + { + layout->m_hasDepthStencil = false; + } + *outLayout = layout.detach(); + return SLANG_OK; +} + Result D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, IInputLayout** outLayout) { RefPtr<InputLayoutImpl> layout(new InputLayoutImpl); @@ -2655,20 +2646,14 @@ void D3D12Renderer::setIndexBuffer(IBufferResource* buffer, Format indexFormat, m_boundIndexOffset = UINT(offset); } -void D3D12Renderer::setDepthStencilTarget(IResourceView* depthStencilView) -{ -} - void D3D12Renderer::setViewports(UInt count, Viewport const* viewports) { static const int kMaxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - assert(count <= kMaxViewports); - - D3D12_VIEWPORT dxViewports[kMaxViewports]; + assert(count <= kMaxViewports && count <= kMaxRTVCount); for(UInt ii = 0; ii < count; ++ii) { auto& inViewport = viewports[ii]; - auto& dxViewport = dxViewports[ii]; + auto& dxViewport = m_viewports[ii]; dxViewport.TopLeftX = inViewport.originX; dxViewport.TopLeftY = inViewport.originY; @@ -2677,20 +2662,18 @@ void D3D12Renderer::setViewports(UInt count, Viewport const* viewports) dxViewport.MinDepth = inViewport.minZ; dxViewport.MaxDepth = inViewport.maxZ; } - - m_commandList->RSSetViewports(UINT(count), dxViewports); + m_commandList->RSSetViewports(UINT(count), m_viewports); } void D3D12Renderer::setScissorRects(UInt count, ScissorRect const* rects) { static const int kMaxScissorRects = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - assert(count <= kMaxScissorRects); + assert(count <= kMaxScissorRects && count <= kMaxRTVCount); - D3D12_RECT dxRects[kMaxScissorRects]; for(UInt ii = 0; ii < count; ++ii) { auto& inRect = rects[ii]; - auto& dxRect = dxRects[ii]; + auto& dxRect = m_scissorRects[ii]; dxRect.left = LONG(inRect.minX); dxRect.top = LONG(inRect.minY); @@ -2698,7 +2681,7 @@ void D3D12Renderer::setScissorRects(UInt count, ScissorRect const* rects) dxRect.bottom = LONG(inRect.maxY); } - m_commandList->RSSetScissorRects(UINT(count), dxRects); + m_commandList->RSSetScissorRects(UINT(count), m_scissorRects); } void D3D12Renderer::setPipelineState(IPipelineState* state) @@ -2706,6 +2689,19 @@ void D3D12Renderer::setPipelineState(IPipelineState* state) m_currentPipelineState = (PipelineStateImpl*)state; } +void D3D12Renderer::setFramebuffer(IFramebuffer* frameBuffer) +{ + ID3D12GraphicsCommandList* commandList = m_commandList; + auto framebufferImpl = static_cast<FramebufferImpl*>(frameBuffer); + commandList->OMSetRenderTargets( + (UINT)framebufferImpl->renderTargetViews.getCount(), + framebufferImpl->renderTargetDescriptors.getArrayView().getBuffer(), + FALSE, + framebufferImpl->depthStencilView ? &framebufferImpl->depthStencilDescriptor : nullptr); + m_frameBuffer = framebufferImpl; +} + + void D3D12Renderer::draw(UInt vertexCount, UInt startVertex) { ID3D12GraphicsCommandList* commandList = m_commandList; @@ -2864,7 +2860,7 @@ void D3D12Renderer::DescriptorSetImpl::setSampler(UInt range, UInt index, ISampl dxDevice->CopyDescriptorsSimple( 1, m_samplerHeap->getCpuHandle(int(descriptorIndex)), - samplerImpl->m_cpuHandle, + samplerImpl->m_descriptor.cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); } @@ -2908,7 +2904,7 @@ void D3D12Renderer::DescriptorSetImpl::setCombinedTextureSampler( dxDevice->CopyDescriptorsSimple( 1, m_samplerHeap->getCpuHandle(int(samplerDescriptorIndex)), - samplerImpl->m_cpuHandle, + samplerImpl->m_descriptor.cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); } @@ -3601,7 +3597,10 @@ Result D3D12Renderer::createPipelineLayout(const IPipelineLayout::Desc& desc, IP return SLANG_OK; } -Result D3D12Renderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) +Result D3D12Renderer::createDescriptorSet( + IDescriptorSetLayout* layout, + IDescriptorSet::Flag::Enum flag, + IDescriptorSet** outDescriptorSet) { auto layoutImpl = (DescriptorSetLayoutImpl*) layout; @@ -3660,13 +3659,22 @@ Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes psoDesc.PrimitiveTopologyType = m_primitiveTopologyType; { - const int numRenderTargets = int(desc.renderTargetCount); + auto framebufferLayout = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout); + const int numRenderTargets = int(framebufferLayout->m_renderTargets.getCount()); - psoDesc.DSVFormat = m_depthStencilFormat; + if (framebufferLayout->m_hasDepthStencil) + { + psoDesc.DSVFormat = D3DUtil::getMapFormat(framebufferLayout->m_depthStencil.format); + } + else + { + psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; + } psoDesc.NumRenderTargets = numRenderTargets; for (Int i = 0; i < numRenderTargets; i++) { - psoDesc.RTVFormats[i] = m_targetFormat; + psoDesc.RTVFormats[i] = + D3DUtil::getMapFormat(framebufferLayout->m_renderTargets[i].format); } psoDesc.SampleDesc.Count = 1; @@ -3735,6 +3743,7 @@ Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDes RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(); pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl; pipelineStateImpl->m_pipelineState = pipelineState; + pipelineStateImpl->m_program = programImpl; pipelineStateImpl->init(desc); *outState = pipelineStateImpl.detach(); return SLANG_OK; diff --git a/tools/gfx/d3d12/render-d3d12.h b/tools/gfx/d3d12/render-d3d12.h index 3304d92dc..4e9dc3f78 100644 --- a/tools/gfx/d3d12/render-d3d12.h +++ b/tools/gfx/d3d12/render-d3d12.h @@ -6,6 +6,6 @@ namespace gfx { -SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); +SlangResult SLANG_MCALL createD3D12Renderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } // gfx diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp index 4251abe98..34ea70eef 100644 --- a/tools/gfx/open-gl/render-gl.cpp +++ b/tools/gfx/open-gl/render-gl.cpp @@ -3,13 +3,11 @@ #include "../nvapi/nvapi-util.h" -//WORKING:#include "options.h" #include "../renderer-shared.h" #include "../render-graphics-common.h" -#include <stdio.h> -#include <stdlib.h> #include "core/slang-basic.h" +#include "core/slang-blob.h" #include "core/slang-secure-crt.h" #include "external/stb/stb_image_write.h" @@ -33,6 +31,7 @@ #include <GL/GL.h> #include "external/glext.h" +#include "external/wglext.h" // We define an "X-macro" for mapping over loadable OpenGL // extension entry point that we will use, so that we can @@ -69,8 +68,21 @@ F(glBindSampler, PFNGLBINDSAMPLERPROC) \ F(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ F(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \ + F(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \ + F(glDeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC) \ + F(glBindFramebuffer, PFNGLBINDFRAMEBUFFERPROC) \ + F(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) \ + F(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC) \ + F(glBlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC) \ + F(glCheckFramebufferStatus, PFNGLCHECKFRAMEBUFFERSTATUSPROC) \ + F(glGenVertexArrays, PFNGLGENVERTEXARRAYSPROC) \ + F(glBindVertexArray, PFNGLBINDVERTEXARRAYPROC) \ + F(glDeleteVertexArrays, PFNGLDELETEVERTEXARRAYSPROC) \ /* end */ +#define MAP_WGL_EXTENSION_FUNCS(F) \ + F(wglCreateContextAttribsARB, PFNWGLCREATECONTEXTATTRIBSARBPROC) \ + /* end */ using namespace Slang; namespace gfx { @@ -78,13 +90,24 @@ namespace gfx { class GLRenderer : public GraphicsAPIRenderer { public: - // Renderer implementation - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override; virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) override; virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override; - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() override; - virtual SLANG_NO_THROW ITextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() override; + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) override + { + SLANG_UNUSED(swapchain); + } + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout( + const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) override; + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override; virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( IResource::Usage initialUsage, @@ -114,7 +137,7 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createPipelineLayout(const IPipelineLayout::Desc& desc, IPipelineLayout** outLayout) override; virtual SLANG_NO_THROW Result SLANG_MCALL - createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) override; + createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) override; virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override; @@ -123,8 +146,8 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( const ComputePipelineStateDesc& desc, IPipelineState** outState) override; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override; virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) override; virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) override; @@ -146,8 +169,6 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) override; virtual SLANG_NO_THROW void SLANG_MCALL - setDepthStencilTarget(IResourceView* depthStencilView) override; - virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) override; virtual SLANG_NO_THROW void SLANG_MCALL setScissorRects(UInt count, ScissorRect const* rects) override; @@ -166,6 +187,7 @@ public: { return m_currentPipelineState.Ptr(); } + HGLRC createGLContext(HDC hdc); GLRenderer(); ~GLRenderer(); @@ -298,6 +320,200 @@ public: GLuint m_bufferID; }; + class FramebufferLayoutImpl + : public IFramebufferLayout + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebufferLayout* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebufferLayout) + return static_cast<IFramebufferLayout*>(this); + return nullptr; + } + + public: + ShortList<IFramebufferLayout::AttachmentLayout> m_renderTargets; + bool m_hasDepthStencil = false; + IFramebufferLayout::AttachmentLayout m_depthStencil; + }; + + class FramebufferImpl + : public IFramebuffer + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebuffer* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer) + return static_cast<IFramebuffer*>(this); + return nullptr; + } + + public: + GLuint m_framebuffer; + WeakSink<GLRenderer>* m_renderer; + ShortList<RefPtr<TextureViewImpl>> renderTargetViews; + RefPtr<TextureViewImpl> depthStencilView; + FramebufferImpl(WeakSink<GLRenderer>* renderer) :m_renderer(renderer) {} + ~FramebufferImpl() + { + if (auto renderer = m_renderer->get()) + { + renderer->glDeleteFramebuffers(1, &m_framebuffer); + } + } + void createGLFramebuffer() + { + auto renderer = m_renderer->get(); + renderer->glGenFramebuffers(1, &m_framebuffer); + renderer->glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + for (Index i = 0; i < renderTargetViews.getCount(); i++) + { + auto rtv = renderTargetViews[i].Ptr(); + renderer->glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + (uint32_t)i, GL_TEXTURE_2D, rtv->m_textureID, 0); + } + if (depthStencilView) + { + renderer->glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + depthStencilView->m_textureID, + 0); + } + auto error = renderer->glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (error != GL_FRAMEBUFFER_COMPLETE) + { + return; + } + } + }; + + class SwapchainImpl + : public ISwapchain + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + ISwapchain* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain) + return static_cast<ISwapchain*>(this); + return nullptr; + } + + public: + ~SwapchainImpl() + { + for (auto image : m_images) + image->m_handle = 0; + if (auto rendererRef = m_renderer->get()) + { + rendererRef->glDeleteFramebuffers(1, &m_framebuffer); + glDeleteTextures(1, &m_backBuffer); + } + wglMakeCurrent(m_hdc, 0); + wglDeleteContext(m_glrc); + ::ReleaseDC(m_hwnd, m_hdc); + } + Result init(GLRenderer* renderer, const ISwapchain::Desc& desc, WindowHandle window) + { + m_renderer = renderer->m_weakRenderer.Ptr(); + + m_hwnd = (HWND)window.handleValues[0]; + m_hdc = ::GetDC(m_hwnd); + m_glrc = renderer->createGLContext(m_hdc); + wglMakeCurrent(renderer->m_hdc, renderer->m_glContext); + + m_desc = desc; + + glGenTextures(1, &m_backBuffer); + glBindTexture(GL_TEXTURE_2D, m_backBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA8, + desc.width, + desc.height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + nullptr); + + wglMakeCurrent(m_hdc, m_glrc); + renderer->glGenFramebuffers(1, &m_framebuffer); + renderer->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer); + renderer->glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_backBuffer, 0); + + for (uint32_t i = 0; i < desc.imageCount; i++) + { + ITextureResource::Desc texDesc = {}; + texDesc.init2D( + IResource::Type::Texture2D, + gfx::Format::RGBA_Unorm_UInt8, + desc.width, + desc.height, + 1); + RefPtr<TextureResourceImpl> tex = + new TextureResourceImpl(IResource::Usage::RenderTarget, texDesc, m_renderer); + tex->m_handle = m_backBuffer; + m_images.add(tex); + } + wglMakeCurrent(renderer->m_hdc, renderer->m_glContext); + return SLANG_OK; + } + virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override { return m_desc; } + virtual SLANG_NO_THROW Result + getImage(uint32_t index, ITextureResource** outResource) override + { + m_images[index]->addRef(); + *outResource = m_images[index].Ptr(); + return SLANG_OK; + } + virtual SLANG_NO_THROW Result present() override + { + glFlush(); + wglMakeCurrent(m_hdc, m_glrc); + auto renderer = m_renderer->get(); + renderer->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + renderer->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer); + renderer->glBlitFramebuffer( + 0, + 0, + m_desc.width, + m_desc.height, + 0, + 0, + m_desc.width, + m_desc.height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); + SwapBuffers(m_hdc); + wglMakeCurrent(renderer->m_hdc, renderer->m_glContext); + return SLANG_OK; + } + + virtual SLANG_NO_THROW uint32_t acquireNextImage() override + { + return 0; + } + + public: + WeakSink<GLRenderer>* m_renderer = nullptr; + GLuint m_framebuffer; + GLuint m_backBuffer; + HGLRC m_glrc; + HWND m_hwnd; + HDC m_hdc; + ISwapchain::Desc m_desc; + ShortList<RefPtr<TextureResourceImpl>> m_images; + }; + enum class GLDescriptorSlotType { ConstantBuffer, @@ -429,6 +645,8 @@ public: { Unknown, RGBA_Unorm_UInt8, + D_Float32, + D_Unorm24_S8, CountOf, }; @@ -455,10 +673,11 @@ public: static void compileTimeAsserts(); HDC m_hdc; - HGLRC m_glContext; + HGLRC m_glContext = 0; float m_clearColor[4] = { 0, 0, 0, 0 }; - + GLuint m_vao; RefPtr<PipelineStateImpl> m_currentPipelineState; + RefPtr<FramebufferImpl> m_currentFramebuffer; RefPtr<WeakSink<GLRenderer> > m_weakRenderer; RefPtr<DescriptorSetImpl> m_boundDescriptorSets[kMaxDescriptorSetCount]; @@ -469,11 +688,12 @@ public: UInt m_boundVertexStreamOffsets[kMaxVertexStreams]; Desc m_desc; - + WindowHandle m_windowHandle; // Declare a function pointer for each OpenGL // extension function we need to load #define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) + MAP_WGL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) #undef DECLARE_GL_EXTENSION_FUNC static const GlPixelFormatInfo s_pixelFormatInfos[]; /// Maps GlPixelFormat to a format info @@ -484,6 +704,9 @@ public: switch (format) { case Format::RGBA_Unorm_UInt8: return GlPixelFormat::RGBA_Unorm_UInt8; + case Format::D_Float32: return GlPixelFormat::D_Float32; + case Format::D_Unorm24_S8: return GlPixelFormat::D_Unorm24_S8; + default: return GlPixelFormat::Unknown; } } @@ -493,6 +716,9 @@ public: // internalType, format, formatType { 0, 0, 0}, // GlPixelFormat::Unknown { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, // GlPixelFormat::RGBA_Unorm_UInt8 + { GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE}, // GlPixelFormat::D_Float32 + { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE}, // GlPixelFormat::D_Unorm24_S8 + }; /* static */void GLRenderer::compileTimeAsserts() @@ -500,10 +726,10 @@ public: SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_pixelFormatInfos) == int(GlPixelFormat::CountOf)); } -SlangResult SLANG_MCALL createGLRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +SlangResult SLANG_MCALL createGLRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { RefPtr<GLRenderer> result = new GLRenderer(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc, windowHandle)); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); *outRenderer = result.detach(); return SLANG_OK; } @@ -523,26 +749,6 @@ void GLRenderer::debugCallback(GLenum source, GLenum type, GLuint id, GLenum sev } } - -GLRenderer::GLRenderer() -{ - m_weakRenderer = new WeakSink<GLRenderer>(this); -} - -GLRenderer::~GLRenderer() -{ - // We can destroy things whilst in this state - m_currentPipelineState.setNull(); - - // By resetting the weak pointer, other objects accessing through WeakSink<GLRenderer> will no longer - // be able to access this object which is entering a 'being destroyed' to 'destroyed' state - if (m_weakRenderer) - { - SLANG_ASSERT(m_weakRenderer->get() == this); - m_weakRenderer->detach(); - } -} - /* static */void APIENTRY GLRenderer::staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { ((GLRenderer*)userParam)->debugCallback(source, type, id, severity, length, message); @@ -582,6 +788,11 @@ void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buff void GLRenderer::flushStateForDraw() { + if (m_currentFramebuffer) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_currentFramebuffer->m_framebuffer); + } + glBindVertexArray(m_vao); auto inputLayout = m_currentPipelineState->m_inputLayout.Ptr(); auto attrCount = Index(inputLayout->m_attributeCount); for (Index ii = 0; ii < attrCount; ++ii) @@ -606,7 +817,6 @@ void GLRenderer::flushStateForDraw() { glDisableVertexAttribArray((GLuint)ii); } - // Next bind the descriptor sets as required by the layout auto pipelineLayout = m_currentPipelineState->m_pipelineLayout; auto descriptorSetCount = pipelineLayout->m_sets.getCount(); @@ -770,36 +980,126 @@ GLuint GLRenderer::loadShader(GLenum stage, const char* source) return shaderID; } -#if 0 -void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details) +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifdef _WIN32 +LRESULT CALLBACK WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam) { - const auto& bindings = desc.m_bindings; - const int numBindings = int(bindings.Count()); - for (int i = 0; i < numBindings; ++i) - { - const auto& binding = bindings[i]; - const auto& detail = details[i]; + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} +#endif - if (binding.bindingType == BindingType::Sampler && detail.m_samplerHandle != 0) - { - glDeleteSamplers(1, &detail.m_samplerHandle); - } - } +WindowHandle createWindow() +{ + WindowHandle window = {}; +#ifdef _WIN32 + const wchar_t className[] = L"OpenGLContextWindow"; + static bool windowClassRegistered = false; + HINSTANCE hInstance = GetModuleHandle(NULL); + if (!windowClassRegistered) + { + windowClassRegistered = true; + WNDCLASS wc = {}; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = className; + RegisterClass(&wc); + } + + HWND hwnd = CreateWindowEx( + 0, // Optional window styles. + className, // Window class + L"GLWindow", // Window text + WS_OVERLAPPEDWINDOW, // Window style + // Size and position + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, // Parent window + NULL, // Menu + hInstance, // Instance handle + NULL // Additional application data + ); + + if (hwnd == NULL) + { + return window; + } + window = WindowHandle::FromHwnd(hwnd); +#endif + return window; } + +void destroyWindow(WindowHandle window) +{ +#ifdef _WIN32 + DestroyWindow((HWND)window.handleValues[0]); #endif +} -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! +GLRenderer::GLRenderer() { m_weakRenderer = new WeakSink<GLRenderer>(this); } -SLANG_NO_THROW Result SLANG_MCALL GLRenderer::initialize(const Desc& desc, void* inWindowHandle) +GLRenderer::~GLRenderer() +{ + // We can destroy things whilst in this state + m_currentPipelineState.setNull(); + m_currentFramebuffer.setNull(); + if (glDeleteVertexArrays) + { + glDeleteVertexArrays(1, &m_vao); + } + if (m_glContext) + { + wglDeleteContext(m_glContext); + } + destroyWindow(m_windowHandle); + + // By resetting the weak pointer, other objects accessing through WeakSink<GLRenderer> will no + // longer be able to access this object which is entering a 'being destroyed' to 'destroyed' + // state + if (m_weakRenderer) + { + SLANG_ASSERT(m_weakRenderer->get() == this); + m_weakRenderer->detach(); + } +} + +HGLRC GLRenderer::createGLContext(HDC hdc) +{ + PIXELFORMATDESCRIPTOR pixelFormatDesc = {sizeof(PIXELFORMATDESCRIPTOR)}; + pixelFormatDesc.nVersion = 1; + pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; + pixelFormatDesc.cColorBits = 32; + pixelFormatDesc.cDepthBits = 24; + pixelFormatDesc.cStencilBits = 8; + pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; + int pixelFormatIndex = ChoosePixelFormat(hdc, &pixelFormatDesc); + SetPixelFormat(hdc, pixelFormatIndex, &pixelFormatDesc); + + int attributeList[5]; + + attributeList[0] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attributeList[1] = 4; + attributeList[2] = WGL_CONTEXT_MINOR_VERSION_ARB; + attributeList[3] = 3; + attributeList[4] = 0; + + HGLRC newGLContext = wglCreateContextAttribsARB(hdc, m_glContext, attributeList); + return newGLContext; +} + +SLANG_NO_THROW Result SLANG_MCALL GLRenderer::initialize(const Desc& desc) { SLANG_RETURN_ON_FAIL(slangContext.initialize(desc.slang, SLANG_GLSL, "glsl_440")); - SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc, inWindowHandle)); + SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc)); - auto windowHandle = (HWND)inWindowHandle; + m_windowHandle = createWindow(); m_desc = desc; - m_hdc = ::GetDC(windowHandle); + m_hdc = ::GetDC((HWND)m_windowHandle.handleValues[0]); PIXELFORMATDESCRIPTOR pixelFormatDesc = { sizeof(PIXELFORMATDESCRIPTOR) }; pixelFormatDesc.nVersion = 1; @@ -812,7 +1112,6 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::initialize(const Desc& desc, void* int pixelFormatIndex = ChoosePixelFormat(m_hdc, &pixelFormatDesc); SetPixelFormat(m_hdc, pixelFormatIndex, &pixelFormatDesc); - m_glContext = wglCreateContext(m_hdc); wglMakeCurrent(m_hdc, m_glContext); @@ -844,19 +1143,39 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::initialize(const Desc& desc, void* #define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME); MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) + MAP_WGL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) #undef LOAD_GL_EXTENSION_FUNC + wglMakeCurrent(m_hdc, 0); + wglDeleteContext(m_glContext); + m_glContext = 0; + + if (!wglCreateContextAttribsARB) + { + return SLANG_FAIL; + } + + m_glContext = createGLContext(m_hdc); + + if (m_glContext == NULL) + { + return SLANG_FAIL; + } + wglMakeCurrent(m_hdc, m_glContext); + glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); - glViewport(0, 0, desc.width, desc.height); + if (!glGenVertexArrays) + return SLANG_FAIL; + + glGenVertexArrays(1, &m_vao); if (glDebugMessageCallback) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(staticDebugCallback, this); } - return SLANG_OK; } @@ -870,49 +1189,97 @@ SLANG_NO_THROW void SLANG_MCALL GLRenderer::clearFrame() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } -SLANG_NO_THROW void SLANG_MCALL GLRenderer::presentFrame() +SLANG_NO_THROW void SLANG_MCALL GLRenderer::beginFrame() { } + +SLANG_NO_THROW void SLANG_MCALL GLRenderer::endFrame() { glFlush(); - ::SwapBuffers(m_hdc); } -SLANG_NO_THROW TextureResource::Desc SLANG_MCALL GLRenderer::getSwapChainTextureDesc() +SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) { - TextureResource::Desc desc; - desc.init2D(IResource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1); - return desc; + RefPtr<SwapchainImpl> swapchain = new SwapchainImpl(); + SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window)); + *outSwapchain = swapchain.detach(); + wglMakeCurrent(m_hdc, m_glContext); + return SLANG_OK; } -SLANG_NO_THROW Result SLANG_MCALL GLRenderer::captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) +SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createFramebufferLayout( + const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) { - size_t requiredSize = m_desc.width * m_desc.height * sizeof(uint32_t); - if (outRowPitch) - *outRowPitch = m_desc.width * sizeof(uint32_t); - if (outPixelSize) - *outPixelSize = sizeof(uint32_t); + RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl(); + layout->m_renderTargets.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + layout->m_renderTargets[i] = desc.renderTargets[i]; + } - if (!buffer || *inOutBufferSize == 0) + if (desc.depthStencil) { - *inOutBufferSize = requiredSize; - return SLANG_OK; + layout->m_hasDepthStencil = true; + layout->m_depthStencil = *desc.depthStencil; + } + else + { + layout->m_hasDepthStencil = false; + } + *outLayout = layout.detach(); + return SLANG_OK; +} + +SLANG_NO_THROW Result SLANG_MCALL + GLRenderer::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) +{ + RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl(m_weakRenderer); + framebuffer->renderTargetViews.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; i++) + { + framebuffer->renderTargetViews[i] = + static_cast<TextureViewImpl*>(desc.renderTargetViews[i]); } - if (*inOutBufferSize < requiredSize) - return SLANG_ERROR_INSUFFICIENT_BUFFER; + framebuffer->depthStencilView = static_cast<TextureViewImpl*>(desc.depthStencilView); + framebuffer->createGLFramebuffer(); + *outFramebuffer = framebuffer.detach(); + return SLANG_OK; +} - glReadPixels(0, 0, m_desc.width, m_desc.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); +SLANG_NO_THROW void SLANG_MCALL GLRenderer::setFramebuffer(IFramebuffer* frameBuffer) +{ + m_currentFramebuffer = static_cast<FramebufferImpl*>(frameBuffer); +} + +SLANG_NO_THROW Result SLANG_MCALL GLRenderer::readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) +{ + auto resource = static_cast<TextureResourceImpl*>(texture); + auto size = resource->getDesc()->size; + size_t requiredSize = size.width * size.height * sizeof(uint32_t); + if (outRowPitch) + *outRowPitch = size.width * sizeof(uint32_t); + if (outPixelSize) + *outPixelSize = sizeof(uint32_t); + + RefPtr<ListBlob> blob = new ListBlob(); + blob->m_data.setCount(requiredSize); + auto buffer = blob->m_data.begin(); + glBindTexture(resource->m_target, resource->m_handle); + glGetTexImage(resource->m_target, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); // Flip pixels vertically in-place. - for (int y = 0; y < m_desc.height / 2; y++) + for (int y = 0; y < size.height / 2; y++) { - for (int x = 0; x < m_desc.width; x++) + for (int x = 0; x < size.width; x++) { std::swap( - *((uint32_t*)buffer + y * m_desc.width + x), - *((uint32_t*)buffer + (m_desc.height - y - 1) * m_desc.width + x)); + *((uint32_t*)buffer + y * size.width + x), + *((uint32_t*)buffer + (size.height - y - 1) * size.width + x)); } } + *outBlob = blob.detach(); + return SLANG_OK; } @@ -945,12 +1312,8 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( const int effectiveArraySize = srcDesc.calcEffectiveArraySize(); - assert(initData); - assert(initData->numSubResources == srcDesc.numMipLevels * srcDesc.size.depth * effectiveArraySize); - // Set on texture so will be freed if failure texture->m_handle = handle; - const void*const*const data = initData->subResources; switch (srcDesc.type) { @@ -966,7 +1329,16 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( { for (int j = 0; j < srcDesc.numMipLevels; j++) { - glTexImage2D(target, j, internalFormat, srcDesc.size.width, i, 0, format, formatType, data[slice++]); + glTexImage2D( + target, + j, + internalFormat, + Math::Max(1, srcDesc.size.width >> j), + i, + 0, + format, + formatType, + initData ? initData->subResources[slice++] : nullptr); } } } @@ -976,7 +1348,15 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( glBindTexture(target, handle); for (int i = 0; i < srcDesc.numMipLevels; i++) { - glTexImage1D(target, i, internalFormat, srcDesc.size.width, 0, format, formatType, data[i]); + glTexImage1D( + target, + i, + internalFormat, + Math::Max(1, srcDesc.size.width >> i), + 0, + format, + formatType, + initData ? initData->subResources[i] : nullptr); } } break; @@ -1002,7 +1382,17 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( { for (int j = 0; j < srcDesc.numMipLevels; j++) { - glTexImage3D(target, j, internalFormat, srcDesc.size.width, srcDesc.size.height, slice, 0, format, formatType, data[slice++]); + glTexImage3D( + target, + j, + internalFormat, + Math::Max(1, srcDesc.size.width >> j), + Math::Max(1, srcDesc.size.height >> j), + slice, + 0, + format, + formatType, + initData ? initData->subResources[slice++] : nullptr); } } } @@ -1018,7 +1408,16 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( { for (int i = 0; i < srcDesc.numMipLevels; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[slice++]); + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, + i, + internalFormat, + Math::Max(1, srcDesc.size.width >> i), + Math::Max(1, srcDesc.size.height >> i), + 0, + format, + formatType, + initData ? initData->subResources[slice++] : nullptr); } } } @@ -1028,7 +1427,16 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( glBindTexture(target, handle); for (int i = 0; i < srcDesc.numMipLevels; i++) { - glTexImage2D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[i]); + glTexImage2D( + target, + i, + internalFormat, + Math::Max(1, srcDesc.size.width >> i), + Math::Max(1, srcDesc.size.height >> i), + 0, + format, + formatType, + initData ? initData->subResources[i] : nullptr); } } } @@ -1040,7 +1448,17 @@ SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureResource( glBindTexture(target, handle); for (int i = 0; i < srcDesc.numMipLevels; i++) { - glTexImage3D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, srcDesc.size.depth, 0, format, formatType, data[i]); + glTexImage3D( + target, + i, + internalFormat, + Math::Max(1, srcDesc.size.width >> i), + Math::Max(1, srcDesc.size.height >> i), + Math::Max(1, srcDesc.size.depth >> i), + 0, + format, + formatType, + initData ? initData->subResources[i] : nullptr); } break; } @@ -1122,14 +1540,14 @@ SLANG_NO_THROW Result SLANG_MCALL SLANG_NO_THROW Result SLANG_MCALL GLRenderer::createTextureView( ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) { - auto resourceImpl = (TextureResourceImpl*) texture; + auto resourceImpl = static_cast<TextureResourceImpl*>(texture); // TODO: actually do something? RefPtr<TextureViewImpl> viewImpl = new TextureViewImpl(); viewImpl->m_resource = resourceImpl; viewImpl->m_textureID = resourceImpl->m_handle; - *outView = viewImpl; + *outView = viewImpl.detach(); return SLANG_OK; } @@ -1235,10 +1653,6 @@ SLANG_NO_THROW void SLANG_MCALL { } -SLANG_NO_THROW void SLANG_MCALL GLRenderer::setDepthStencilTarget(IResourceView* depthStencilView) -{ -} - SLANG_NO_THROW void SLANG_MCALL GLRenderer::setViewports(UInt count, Viewport const* viewports) { assert(count == 1); @@ -1455,8 +1869,10 @@ SLANG_NO_THROW Result SLANG_MCALL } SLANG_NO_THROW Result SLANG_MCALL - GLRenderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) + GLRenderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) { + SLANG_UNUSED(flag); + auto layoutImpl = (DescriptorSetLayoutImpl*) layout; RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl(); diff --git a/tools/gfx/open-gl/render-gl.h b/tools/gfx/open-gl/render-gl.h index ef8bb318c..7d0d0f3dd 100644 --- a/tools/gfx/open-gl/render-gl.h +++ b/tools/gfx/open-gl/render-gl.h @@ -5,6 +5,6 @@ namespace gfx { -SlangResult SLANG_MCALL createGLRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); +SlangResult SLANG_MCALL createGLRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } // gfx diff --git a/tools/gfx/render-graphics-common.cpp b/tools/gfx/render-graphics-common.cpp index 3e38b8b5a..068669136 100644 --- a/tools/gfx/render-graphics-common.cpp +++ b/tools/gfx/render-graphics-common.cpp @@ -962,7 +962,7 @@ protected: { ComPtr<IDescriptorSet> descriptorSet; SLANG_RETURN_ON_FAIL( - renderer->createDescriptorSet(descriptorSetInfo->layout, descriptorSet.writeRef())); + renderer->createDescriptorSet(descriptorSetInfo->layout, IDescriptorSet::Flag::Transient, descriptorSet.writeRef())); descriptorSets.add(descriptorSet); } @@ -1474,7 +1474,6 @@ void GraphicsAPIRenderer::preparePipelineDesc(GraphicsPipelineStateDesc& desc) { auto program = dynamic_cast<GraphicsCommonShaderProgram*>(desc.program); auto rootLayout = program->getLayout(); - desc.renderTargetCount = rootLayout->getRenderTargetCount(); desc.pipelineLayout = rootLayout->getPipelineLayout(); } } diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp index dc3928454..3a886aaa4 100644 --- a/tools/gfx/render.cpp +++ b/tools/gfx/render.cpp @@ -25,6 +25,7 @@ static const uint8_t s_formatSize[] = { uint8_t(sizeof(float) * 1), // R_Float32, uint8_t(sizeof(uint32_t)), // RGBA_Unorm_UInt8, + uint8_t(sizeof(uint32_t)), // BGRA_Unorm_UInt8, uint8_t(sizeof(uint16_t)), // R_UInt16, uint8_t(sizeof(uint32_t)), // R_UInt32, @@ -85,30 +86,30 @@ extern "C" } } - SLANG_GFX_API SlangResult SLANG_MCALL gfxCreateRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) + SLANG_GFX_API SlangResult SLANG_MCALL gfxCreateRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { switch (desc->rendererType) { #if SLANG_WINDOWS_FAMILY case RendererType::DirectX11: { - return createD3D11Renderer(desc, windowHandle, outRenderer); + return createD3D11Renderer(desc, outRenderer); } case RendererType::DirectX12: { - return createD3D12Renderer(desc, windowHandle, outRenderer); + return createD3D12Renderer(desc, outRenderer); } case RendererType::OpenGl: { - return createGLRenderer(desc, windowHandle, outRenderer); + return createGLRenderer(desc, outRenderer); } case RendererType::Vulkan: { - return createVKRenderer(desc, windowHandle, outRenderer); + return createVKRenderer(desc, outRenderer); } case RendererType::CUDA: { - return createCUDARenderer(desc, windowHandle, outRenderer); + return createCUDARenderer(desc, outRenderer); } #endif diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index fdee8b776..78c0439fd 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -16,6 +16,10 @@ const Slang::Guid GfxGUID::IID_IPipelineLayout = SLANG_UUID_IPipelineLayout; const Slang::Guid GfxGUID::IID_IInputLayout = SLANG_UUID_IInputLayout; const Slang::Guid GfxGUID::IID_IPipelineState = SLANG_UUID_IPipelineState; const Slang::Guid GfxGUID::IID_IResourceView = SLANG_UUID_IResourceView; +const Slang::Guid GfxGUID::IID_IFramebuffer = SLANG_UUID_IFrameBuffer; +const Slang::Guid GfxGUID::IID_IFramebufferLayout = SLANG_UUID_IFramebufferLayout; + +const Slang::Guid GfxGUID::IID_ISwapchain = SLANG_UUID_ISwapchain; const Slang::Guid GfxGUID::IID_ISamplerState = SLANG_UUID_ISamplerState; const Slang::Guid GfxGUID::IID_IResource = SLANG_UUID_IResource; const Slang::Guid GfxGUID::IID_IBufferResource = SLANG_UUID_IBufferResource; @@ -170,6 +174,7 @@ void PipelineStateBase::initializeBase(const PipelineStateDesc& inDesc) desc = inDesc; auto program = desc.getProgram(); + m_program = program; isSpecializable = (program->slangProgram && program->slangProgram->getSpecializationParamCount() != 0); } @@ -180,10 +185,8 @@ IRenderer* gfx::RendererBase::getInterface(const Guid& guid) : nullptr; } -SLANG_NO_THROW Result SLANG_MCALL RendererBase::initialize(const Desc& desc, void* inWindowHandle) +SLANG_NO_THROW Result SLANG_MCALL RendererBase::initialize(const Desc& desc) { - SLANG_UNUSED(inWindowHandle); - shaderCache.init(desc.shaderCacheFileSystem); return SLANG_OK; } diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h index c9f2b3340..b543e709b 100644 --- a/tools/gfx/renderer-shared.h +++ b/tools/gfx/renderer-shared.h @@ -16,6 +16,9 @@ struct GfxGUID static const Slang::Guid IID_IPipelineLayout; static const Slang::Guid IID_IPipelineState; static const Slang::Guid IID_IResourceView; + static const Slang::Guid IID_IFramebuffer; + static const Slang::Guid IID_IFramebufferLayout; + static const Slang::Guid IID_ISwapchain; static const Slang::Guid IID_ISamplerState; static const Slang::Guid IID_IResource; static const Slang::Guid IID_IBufferResource; @@ -234,7 +237,7 @@ public: // Indicates whether this is a specializable pipeline. A specializable // pipeline cannot be used directly and must be specialized first. bool isSpecializable = false; - + ComPtr<IShaderProgram> m_program; protected: void initializeBase(const PipelineStateDesc& inDesc); }; @@ -388,7 +391,7 @@ protected: protected: - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle); + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc); protected: Slang::List<Slang::String> m_features; public: diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 6bfd58dda..e89b6a765 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -14,8 +14,13 @@ // Vulkan has a different coordinate system to ogl // http://anki3d.org/vulkan-coordinate-system/ - +#ifndef ENABLE_VALIDATION_LAYER +#if _DEBUG #define ENABLE_VALIDATION_LAYER 1 +#else +#define ENABLE_VALIDATION_LAYER 0 +#endif +#endif #ifdef _MSC_VER # include <stddef.h> @@ -36,16 +41,23 @@ public: kMaxRenderTargets = 8, kMaxAttachments = kMaxRenderTargets + 1, - kMaxDescriptorSets = 4, + kMaxDescriptorSets = 8, }; - // Renderer implementation - virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc, void* inWindowHandle) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize(const Desc& desc) override; virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) override; virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() override; - virtual SLANG_NO_THROW void SLANG_MCALL presentFrame() override; - virtual SLANG_NO_THROW TextureResource::Desc SLANG_MCALL getSwapChainTextureDesc() override; - + virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL endFrame() override; + virtual SLANG_NO_THROW void SLANG_MCALL + makeSwapchainImagePresentable(ISwapchain* swapchain) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebufferLayout(const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) override; + virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* frameBuffer) override; virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( IResource::Usage initialUsage, const ITextureResource::Desc& desc, @@ -75,7 +87,7 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createPipelineLayout(const IPipelineLayout::Desc& desc, IPipelineLayout** outLayout) override; virtual SLANG_NO_THROW Result SLANG_MCALL - createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) override; + createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) override; virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override; @@ -86,8 +98,8 @@ public: const ComputePipelineStateDesc& desc, IPipelineState** outState) override; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) override; virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) override; virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) override; @@ -109,8 +121,6 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset) override; virtual SLANG_NO_THROW void SLANG_MCALL - setDepthStencilTarget(IResourceView* depthStencilView) override; - virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) override; virtual SLANG_NO_THROW void SLANG_MCALL setScissorRects(UInt count, ScissorRect const* rects) override; @@ -222,7 +232,7 @@ public: { m_api->vkFreeMemory(m_api->m_device, m_imageMemory, nullptr); } - if (m_image != VK_NULL_HANDLE) + if (m_image != VK_NULL_HANDLE && !m_isWeakImageReference) { m_api->vkDestroyImage(m_api->m_device, m_image, nullptr); } @@ -232,8 +242,9 @@ public: Usage m_initialUsage; VkImage m_image = VK_NULL_HANDLE; + VkFormat m_vkformat = VK_FORMAT_R8G8B8A8_UNORM; VkDeviceMemory m_imageMemory = VK_NULL_HANDLE; - + bool m_isWeakImageReference = false; const VulkanApi* m_api; }; @@ -328,6 +339,297 @@ public: VkDeviceSize size; }; + class SwapchainImpl + : public ISwapchain + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + ISwapchain* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ISwapchain) + return static_cast<ISwapchain*>(this); + return nullptr; + } + + public: + VulkanSwapChain m_swapChain; + ISwapchain::Desc m_desc; + ShortList<RefPtr<TextureResourceImpl>> m_images; + VKRenderer* m_renderer; + uint32_t m_currentImageIndex = 0; + public: + Result init(VKRenderer* renderer, const ISwapchain::Desc& desc, WindowHandle window) + { + m_desc = desc; + m_renderer = renderer; + + VulkanSwapChain::Desc swapchainDesc; + VulkanSwapChain::PlatformDesc* platformDesc = nullptr; + swapchainDesc.m_imageCount = desc.imageCount; + swapchainDesc.init(); + swapchainDesc.m_format = desc.format; + swapchainDesc.m_vsync = desc.enableVSync; +#if SLANG_WINDOWS_FAMILY + VulkanSwapChain::WinPlatformDesc winPlatformDesc; + winPlatformDesc.m_hinstance = ::GetModuleHandle(nullptr); + winPlatformDesc.m_hwnd = (HWND)window.handleValues[0]; + platformDesc = &winPlatformDesc; +#endif + + SLANG_RETURN_ON_FAIL(m_swapChain.init(&renderer->m_deviceQueue, swapchainDesc, platformDesc)); + m_desc.format = m_swapChain.getDesc().m_format; + m_desc.width = m_swapChain.getWidth(); + m_desc.height = m_swapChain.getHeight(); + m_desc.imageCount = m_swapChain.getDesc().m_imageCount; + auto& images = m_swapChain.getImages(); + for (uint32_t i = 0; i < desc.imageCount; i++) + { + ITextureResource::Desc imageDesc = {}; + + imageDesc.init2D( + IResource::Type::Texture2D, + m_swapChain.getDesc().m_format, + m_swapChain.getWidth(), + m_swapChain.getHeight(), + 1); + RefPtr<TextureResourceImpl> image = new TextureResourceImpl(imageDesc, gfx::IResource::Usage::RenderTarget, &renderer->m_api); + image->m_image = images[i]; + image->m_imageMemory = 0; + image->m_vkformat = m_swapChain.getVkFormat(); + image->m_isWeakImageReference = true; + m_images.add(image); + } + return SLANG_OK; + } + + virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() + { + return m_desc; + } + virtual SLANG_NO_THROW Result getImage(uint32_t index, ITextureResource** outResource) + { + *outResource = m_images[index]; + m_images[index]->addRef(); + return SLANG_OK; + } + virtual SLANG_NO_THROW Result present() + { + m_swapChain.present(m_desc.enableVSync); + return SLANG_OK; + } + virtual SLANG_NO_THROW uint32_t acquireNextImage() + { + m_currentImageIndex = (uint32_t)m_swapChain.nextFrontImageIndex(); + auto image = m_images[m_currentImageIndex]; + m_renderer->_transitionImageLayout( + image->m_image, + image->m_vkformat, + *image->getDesc(), + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + return m_currentImageIndex; + } + }; + + class FramebufferLayoutImpl + : public IFramebufferLayout + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebufferLayout* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebufferLayout) + return static_cast<IFramebufferLayout*>(this); + return nullptr; + } + + public: + VkRenderPass m_renderPass; + VKRenderer* m_renderer; + + public: + ~FramebufferLayoutImpl() + { + m_renderer->m_api.vkDestroyRenderPass(m_renderer->m_api.m_device, m_renderPass, nullptr); + } + Result init(VKRenderer* renderer, const IFramebufferLayout::Desc& desc) + { + m_renderer = renderer; + // Create render pass. + int numAttachments = desc.renderTargetCount; + if (desc.depthStencil) + { + numAttachments++; + } + bool shouldClear = false; + bool shouldClearDepth = false; + bool shouldClearStencil = false; + + // We need extra space if we have depth buffer + Array<VkAttachmentDescription, kMaxAttachments> attachmentDesc; + attachmentDesc.setCount(numAttachments); + for (uint32_t i = 0; i < desc.renderTargetCount; ++i) + { + auto& renderTarget = desc.renderTargets[i]; + VkAttachmentDescription& dst = attachmentDesc[i]; + + dst.flags = 0; + dst.format = VulkanUtil::getVkFormat(renderTarget.format); + dst.samples = (VkSampleCountFlagBits)renderTarget.sampleCount; + dst.loadOp = + shouldClear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + dst.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + dst.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + dst.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + + if (desc.depthStencil) + { + VkAttachmentDescription& dst = attachmentDesc[desc.renderTargetCount]; + dst.flags = 0; + dst.format = VulkanUtil::getVkFormat(desc.depthStencil->format); + dst.samples = (VkSampleCountFlagBits)desc.depthStencil->sampleCount; + dst.loadOp = + shouldClearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + dst.stencilLoadOp = shouldClearStencil ? VK_ATTACHMENT_LOAD_OP_CLEAR + : VK_ATTACHMENT_LOAD_OP_LOAD; + dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + dst.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + dst.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + + Array<VkAttachmentReference, kMaxRenderTargets> colorAttachments; + colorAttachments.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; ++i) + { + VkAttachmentReference& dst = colorAttachments[i]; + dst.attachment = i; + dst.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + + VkAttachmentReference depthAttachment = {}; + depthAttachment.attachment = desc.renderTargetCount; + depthAttachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpassDesc = {}; + subpassDesc.flags = 0; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.inputAttachmentCount = 0u; + subpassDesc.pInputAttachments = nullptr; + subpassDesc.colorAttachmentCount = desc.renderTargetCount; + subpassDesc.pColorAttachments = colorAttachments.getBuffer(); + subpassDesc.pResolveAttachments = nullptr; + subpassDesc.pDepthStencilAttachment = desc.depthStencil ? &depthAttachment : nullptr; + subpassDesc.preserveAttachmentCount = 0u; + subpassDesc.pPreserveAttachments = nullptr; + + VkRenderPassCreateInfo renderPassCreateInfo = {}; + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCreateInfo.attachmentCount = numAttachments; + renderPassCreateInfo.pAttachments = attachmentDesc.getBuffer(); + renderPassCreateInfo.subpassCount = 1; + renderPassCreateInfo.pSubpasses = &subpassDesc; + SLANG_VK_RETURN_ON_FAIL(m_renderer->m_api.vkCreateRenderPass( + m_renderer->m_api.m_device, &renderPassCreateInfo, nullptr, &m_renderPass)); + return SLANG_OK; + } + }; + + class FramebufferImpl + : public IFramebuffer + , public RefObject + { + public: + SLANG_REF_OBJECT_IUNKNOWN_ALL + IFramebuffer* getInterface(const Guid& guid) + { + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFramebuffer) + return static_cast<IFramebuffer*>(this); + return nullptr; + } + + public: + VkFramebuffer m_handle; + ShortList<ComPtr<IResourceView>> renderTargetViews; + ComPtr<IResourceView> depthStencilView; + uint32_t m_width; + uint32_t m_height; + VKRenderer* m_renderer; + RefPtr<FramebufferLayoutImpl> m_layout; + public: + ~FramebufferImpl() + { + m_renderer->m_api.vkDestroyFramebuffer(m_renderer->m_api.m_device, m_handle, nullptr); + } + Result init(VKRenderer* renderer, const IFramebuffer::Desc& desc) + { + m_renderer = renderer; + auto dsv = desc.depthStencilView + ? static_cast<TextureResourceViewImpl*>(desc.depthStencilView) + : nullptr; + // Get frame dimensions from attachments. + if (dsv) + { + // If we have a depth attachment, get frame size from there. + auto size = dsv->m_texture->getDesc()->size; + m_width = size.width; + m_height = size.height; + } + else + { + // If we don't have a depth attachment, then we must have at least + // one color attachment. Get frame dimension from there. + auto size = static_cast<TextureResourceViewImpl*>(desc.renderTargetViews[0]) + ->m_texture->getDesc() + ->size; + m_width = size.width; + m_height = size.height; + } + + // Create render pass. + int numAttachments = desc.renderTargetCount; + if (desc.depthStencilView) + numAttachments++; + Array<VkImageView, kMaxAttachments> imageViews; + imageViews.setCount(numAttachments); + renderTargetViews.setCount(desc.renderTargetCount); + for (uint32_t i = 0; i < desc.renderTargetCount; ++i) + { + auto resourceView = + static_cast<TextureResourceViewImpl*>(desc.renderTargetViews[i]); + renderTargetViews[i] = resourceView; + imageViews[i] = resourceView->m_view; + } + + if (dsv) + { + imageViews[desc.renderTargetCount] = dsv->m_view; + depthStencilView = dsv; + } + + + // Create framebuffer. + m_layout = static_cast<FramebufferLayoutImpl*>(desc.layout); + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = m_layout->m_renderPass; + framebufferInfo.attachmentCount = numAttachments; + framebufferInfo.pAttachments = imageViews.getBuffer(); + framebufferInfo.width = m_width; + framebufferInfo.height = m_height; + framebufferInfo.layers = 1; + + SLANG_VK_RETURN_ON_FAIL(m_renderer->m_api.vkCreateFramebuffer( + m_renderer->m_api.m_device, &framebufferInfo, nullptr, &m_handle)); + return SLANG_OK; + } + }; + class ShaderProgramImpl: public GraphicsCommonShaderProgram { public: @@ -384,15 +686,10 @@ public: { m_api->vkDestroyDescriptorSetLayout(m_api->m_device, m_descriptorSetLayout, nullptr); } - if (m_descriptorPool != VK_NULL_HANDLE) - { - m_api->vkDestroyDescriptorPool(m_api->m_device, m_descriptorPool, nullptr); - } } VulkanApi const* m_api; VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; - VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE; // Vulkan descriptor sets are the closest in design to what // the `Renderer` abstraction exposes as a `DescriptorSet`. @@ -445,6 +742,10 @@ public: /// to descriptor sets described by this layout. /// Index m_totalBoundObjectCount = 0; + + /// Vulkan Descriptor set bindings + Slang::List<VkDescriptorSetLayoutBinding> m_vkBindings; + }; class PipelineLayoutImpl : public IPipelineLayout, public RefObject @@ -499,6 +800,7 @@ public: ~DescriptorSetImpl() { + m_renderer->descriptorSetAllocator.free(m_descriptorSet); } virtual SLANG_NO_THROW void SLANG_MCALL setConstantBuffer(UInt range, UInt index, IBufferResource* buffer) override; @@ -520,13 +822,15 @@ public: VKRenderer* m_renderer = nullptr; ///< Weak pointer, can't be strong, because if set will become circular reference RefPtr<DescriptorSetLayoutImpl> m_layout; - VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE; + VulkanDescriptorSet m_descriptorSet = {}; /// Records entities that are bound to this descriptor set, and keeps the associated resources/views/state in scope List<RefPtr<RefObject>> m_boundObjects; /// Backing storage for root constant ranges belonging to this descriptor set List<char> m_rootConstantData; + + bool m_isTransient = false; }; struct BoundVertexBuffer @@ -570,6 +874,8 @@ public: RefPtr<PipelineLayoutImpl> m_pipelineLayout; + RefPtr<FramebufferLayoutImpl> m_framebufferLayout; + RefPtr<ShaderProgramImpl> m_shaderProgram; VkPipeline m_pipeline = VK_NULL_HANDLE; @@ -589,11 +895,6 @@ public: static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData); - /// Returns true if m_currentPipeline matches the current configuration -// Pipeline* _getPipeline(); -// bool _isEqual(const Pipeline& pipeline) const; -// Slang::Result _createPipeline(RefPtr<Pipeline>& pipelineOut); - void _beginRender(); void _endRender(); Slang::Result _beginPass(); @@ -602,19 +903,15 @@ public: VkDebugReportCallbackEXT m_debugReportCallback; -// RefPtr<InputLayoutImpl> m_currentInputLayout; - -// RefPtr<BindingStateImpl> m_currentBindingState; RefPtr<PipelineLayoutImpl> m_currentPipelineLayout; RefPtr<DescriptorSetImpl> m_currentDescriptorSetImpls [kMaxDescriptorSets]; VkDescriptorSet m_currentDescriptorSets [kMaxDescriptorSets]; -// RefPtr<ShaderProgramImpl> m_currentProgram; - -// List<RefPtr<Pipeline> > m_pipelineCache; RefPtr<PipelineStateImpl> m_currentPipeline; + RefPtr<FramebufferImpl> m_currentFramebuffer; + List<BoundVertexBuffer> m_boundVertexBuffers; VkPrimitiveTopology m_primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; @@ -625,15 +922,17 @@ public: VulkanApi m_api; VulkanDeviceQueue m_deviceQueue; - VulkanSwapChain m_swapChain; - - VkRenderPass m_renderPass = VK_NULL_HANDLE; - - int m_swapChainImageIndex = -1; float m_clearColor[4] = { 0, 0, 0, 0 }; + List<VkViewport> m_viewports; + List<VkRect2D> m_scissorRects; Desc m_desc; + + DescriptorSetAllocator descriptorSetAllocator; + + // Temporary list used by flushBindingState to avoid per-frame allocation. + List<VkCopyDescriptorSet> m_descSetCopies; }; /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer::Buffer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -672,196 +971,10 @@ Result VKRenderer::Buffer::init(const VulkanApi& api, size_t bufferSize, VkBuffe /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -#if 0 -bool VKRenderer::_isEqual(const Pipeline& pipeline) const -{ - return - pipeline.m_pipelineLayout == m_currentPipelineLayout && - pipeline.m_primitiveTopology == m_primitiveTopology && - pipeline.m_inputLayout == m_currentInputLayout && - pipeline.m_shaderProgram == m_currentProgram; -} - -VKRenderer::Pipeline* VKRenderer::_getPipeline() -{ - if (m_currentPipeline && _isEqual(*m_currentPipeline)) - { - return m_currentPipeline; - } - - // Look for a match in the cache - for (int i = 0; i < int(m_pipelineCache.Count()); ++i) - { - Pipeline* pipeline = m_pipelineCache[i]; - if (_isEqual(*pipeline)) - { - m_currentPipeline = pipeline; - return pipeline; - } - } - - RefPtr<Pipeline> pipeline; - SLANG_RETURN_NULL_ON_FAIL(_createPipeline(pipeline)); - m_pipelineCache.Add(pipeline); - m_currentPipeline = pipeline; - return pipeline; -} - -Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut) -{ - RefPtr<Pipeline> pipeline(new Pipeline(m_api)); - - // Initialize the state - pipeline->m_primitiveTopology = m_primitiveTopology; - pipeline->m_pipelineLayout = m_currentPipelineLayout; - pipeline->m_shaderProgram = m_currentProgram; - pipeline->m_inputLayout = m_currentInputLayout; - - // Must be equal at this point if all the items are correctly set in pipeline - assert(_isEqual(*pipeline)); - - VkPipelineCache pipelineCache = VK_NULL_HANDLE; - - if (m_currentProgram->m_pipelineType == PipelineType::Compute) - { - // Then create a pipeline to use that layout - - VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - computePipelineInfo.stage = m_currentProgram->m_compute; - computePipelineInfo.layout = pipeline->m_pipelineLayout->m_pipelineLayout; - - SLANG_VK_CHECK(m_api.vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline->m_pipeline)); - } - else if (m_currentProgram->m_pipelineType == PipelineType::Graphics) - { - // Create the graphics pipeline - - const int width = m_swapChain.getWidth(); - const int height = m_swapChain.getHeight(); - - VkPipelineShaderStageCreateInfo shaderStages[] = { m_currentProgram->m_vertex, m_currentProgram->m_fragment }; - - // VertexBuffer/s - // Currently only handles one - - VkPipelineVertexInputStateCreateInfo vertexInputInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.vertexAttributeDescriptionCount = 0; - - VkVertexInputBindingDescription vertexInputBindingDescription; - - if (m_currentInputLayout) - { - vertexInputBindingDescription.binding = 0; - vertexInputBindingDescription.stride = m_currentInputLayout->m_vertexSize; - vertexInputBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - const auto& srcAttributeDescs = m_currentInputLayout->m_vertexDescs; - - vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription; - - vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(srcAttributeDescs.Count()); - vertexInputInfo.pVertexAttributeDescriptions = srcAttributeDescs.getBuffer(); - } - - // - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float)width; - viewport.height = (float)height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = { 0, 0 }; - scissor.extent = { uint32_t(width), uint32_t(height) }; - - VkPipelineViewportStateCreateInfo viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlending = {}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; - pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pColorBlendState = &colorBlending; - pipelineInfo.layout = pipeline->m_pipelineLayout->m_pipelineLayout; - pipelineInfo.renderPass = m_renderPass; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - - SLANG_VK_CHECK(m_api.vkCreateGraphicsPipelines(m_device, pipelineCache, 1, &pipelineInfo, nullptr, &pipeline->m_pipeline)); - } - else - { - assert(!"Unhandled program type"); - return SLANG_FAIL; - } - - pipelineOut = pipeline; - return SLANG_OK; -} -#endif - Result VKRenderer::_beginPass() { - if (m_swapChainImageIndex < 0) - { - return SLANG_FAIL; - } - const int numRenderTargets = 1; - const VulkanSwapChain::Image& image = m_swapChain.getImages()[m_swapChainImageIndex]; - int numAttachments = 0; // Start render pass @@ -877,15 +990,15 @@ Result VKRenderer::_beginPass() clearValue.depthStencil.stencil = 0; } - const int width = m_swapChain.getWidth(); - const int height = m_swapChain.getHeight(); + const int width = m_currentFramebuffer->m_width; + const int height = m_currentFramebuffer->m_height; VkCommandBuffer cmdBuffer = m_deviceQueue.getCommandBuffer(); VkRenderPassBeginInfo renderPassBegin = {}; renderPassBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBegin.renderPass = m_renderPass; - renderPassBegin.framebuffer = image.m_frameBuffer; + renderPassBegin.renderPass = m_currentFramebuffer->m_layout->m_renderPass; + renderPassBegin.framebuffer = m_currentFramebuffer->m_handle; renderPassBegin.renderArea.offset.x = 0; renderPassBegin.renderArea.offset.y = 0; renderPassBegin.renderArea.extent.width = width; @@ -896,25 +1009,15 @@ Result VKRenderer::_beginPass() m_api.vkCmdBeginRenderPass(cmdBuffer, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE); // Set up scissor and viewport + if (m_scissorRects.getCount()) { - VkRect2D rects[kMaxRenderTargets] = {}; - VkViewport viewports[kMaxRenderTargets] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - rects[i] = VkRect2D{ 0, 0, uint32_t(width), uint32_t(height) }; - - VkViewport& dstViewport = viewports[i]; - - dstViewport.x = 0.0f; - dstViewport.y = 0.0f; - dstViewport.width = float(width); - dstViewport.height = float(height); - dstViewport.minDepth = 0.0f; - dstViewport.maxDepth = 1.0f; - } - - m_api.vkCmdSetScissor(cmdBuffer, 0, numRenderTargets, rects); - m_api.vkCmdSetViewport(cmdBuffer, 0, numRenderTargets, viewports); + m_api.vkCmdSetScissor( + cmdBuffer, 0, (uint32_t)m_scissorRects.getCount(), m_scissorRects.getBuffer()); + } + if (m_viewports.getCount()) + { + m_api.vkCmdSetViewport( + cmdBuffer, 0, (uint32_t)m_viewports.getCount(), m_viewports.getBuffer()); } return SLANG_OK; @@ -926,25 +1029,23 @@ void VKRenderer::_endPass() m_api.vkCmdEndRenderPass(cmdBuffer); } -void VKRenderer::_beginRender() +void VKRenderer::_endRender() { - m_swapChainImageIndex = m_swapChain.nextFrontImageIndex(); + m_deviceQueue.flush(); - if (m_swapChainImageIndex < 0) + // Make m_currentDescriptorSets consistent with m_currentDescriptorSetImpls + // so that we don't mistakenly treat any transient descriptor sets as "copied" in the next frame. + for (uint32_t i = 0; i < kMaxDescriptorSets; i++) { - return; + if (m_currentDescriptorSetImpls[i]) + m_currentDescriptorSets[i] = m_currentDescriptorSetImpls[i]->m_descriptorSet.handle; } } -void VKRenderer::_endRender() -{ - m_deviceQueue.flush(); -} - -Result SLANG_MCALL createVKRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer) +Result SLANG_MCALL createVKRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer) { RefPtr<VKRenderer> result = new VKRenderer(); - SLANG_RETURN_ON_FAIL(result->initialize(*desc, windowHandle)); + SLANG_RETURN_ON_FAIL(result->initialize(*desc)); *outRenderer = result.detach(); return SLANG_OK; } @@ -957,6 +1058,8 @@ VKRenderer::~VKRenderer() waitForGpu(); } + m_currentFramebuffer.setNull(); + m_currentPipeline.setNull(); // Same as clear but, also dtors all elements, which clear does not @@ -968,16 +1071,10 @@ VKRenderer::~VKRenderer() impl.setNull(); } - if (m_renderPass != VK_NULL_HANDLE) - { - m_api.vkDestroyRenderPass(m_device, m_renderPass, nullptr); - m_renderPass = VK_NULL_HANDLE; - } - - m_swapChain.destroy(); - m_deviceQueue.destroy(); + descriptorSetAllocator.close(); + if (m_device != VK_NULL_HANDLE) { m_api.vkDestroyDevice(m_device, nullptr); @@ -1060,15 +1157,15 @@ VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint( // !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! -SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle) +SlangResult VKRenderer::initialize(const Desc& desc) { SLANG_RETURN_ON_FAIL(slangContext.initialize(desc.slang, SLANG_SPIRV, "sm_5_1")); - SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc, inWindowHandle)); + SLANG_RETURN_ON_FAIL(GraphicsAPIRenderer::initialize(desc)); SLANG_RETURN_ON_FAIL(m_module.init()); SLANG_RETURN_ON_FAIL(m_api.initGlobalProcs(m_module)); - + descriptorSetAllocator.m_api = &m_api; m_desc = desc; VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; @@ -1150,7 +1247,8 @@ SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle) } #endif - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); + if (m_api.vkCreateInstance(&instanceCreateInfo, nullptr, &instance) != VK_SUCCESS) + return SLANG_FAIL; SLANG_RETURN_ON_FAIL(m_api.initInstanceProcs(instance)); #if ENABLE_VALIDATION_LAYER @@ -1319,110 +1417,6 @@ SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle) m_api.vkGetDeviceQueue(m_device, queueFamilyIndex, 0, &queue); SLANG_RETURN_ON_FAIL(m_deviceQueue.init(m_api, queue, queueFamilyIndex)); } - - // set up swap chain - - { - VulkanSwapChain::Desc desc; - VulkanSwapChain::PlatformDesc* platformDesc = nullptr; - - desc.init(); - desc.m_format = Format::RGBA_Unorm_UInt8; - -#if SLANG_WINDOWS_FAMILY - VulkanSwapChain::WinPlatformDesc winPlatformDesc; - winPlatformDesc.m_hinstance = ::GetModuleHandle(nullptr); - winPlatformDesc.m_hwnd = (HWND)inWindowHandle; - platformDesc = &winPlatformDesc; -#endif - - SLANG_RETURN_ON_FAIL(m_swapChain.init(&m_deviceQueue, desc, platformDesc)); - } - - // depth/stencil? - - // render pass? - - { - const int numRenderTargets = 1; - bool shouldClear = true; - bool shouldClearDepth = false; - bool shouldClearStencil = false; - bool hasDepthBuffer = false; - - Format depthFormat = Format::Unknown; - VkFormat colorFormat = m_swapChain.getVkFormat(); - - int numAttachments = 0; - // We need extra space if we have depth buffer - VkAttachmentDescription attachmentDesc[kMaxRenderTargets + 1] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - VkAttachmentDescription& dst = attachmentDesc[numAttachments ++]; - - dst.flags = 0; - dst.format = colorFormat; - dst.samples = VK_SAMPLE_COUNT_1_BIT; - dst.loadOp = shouldClear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - dst.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - dst.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - } - if (hasDepthBuffer) - { - VkAttachmentDescription& dst = attachmentDesc[numAttachments++]; - - dst.flags = 0; - dst.format = VulkanUtil::getVkFormat(depthFormat); - dst.samples = VK_SAMPLE_COUNT_1_BIT; - dst.loadOp = shouldClearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.stencilLoadOp = shouldClearStencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - dst.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - - VkAttachmentReference colorAttachments[kMaxRenderTargets] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - VkAttachmentReference& dst = colorAttachments[i]; - dst.attachment = i; - dst.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - - VkAttachmentReference depthAttachment = {}; - depthAttachment.attachment = numRenderTargets; - depthAttachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpassDesc = {}; - subpassDesc.flags = 0; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.inputAttachmentCount = 0u; - subpassDesc.pInputAttachments = nullptr; - subpassDesc.colorAttachmentCount = numRenderTargets; - subpassDesc.pColorAttachments = colorAttachments; - subpassDesc.pResolveAttachments = nullptr; - subpassDesc.pDepthStencilAttachment = hasDepthBuffer ? &depthAttachment : nullptr; - subpassDesc.preserveAttachmentCount = 0u; - subpassDesc.pPreserveAttachments = nullptr; - - VkRenderPassCreateInfo renderPassCreateInfo = {}; - renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassCreateInfo.attachmentCount = numAttachments; - renderPassCreateInfo.pAttachments = attachmentDesc; - renderPassCreateInfo.subpassCount = 1; - renderPassCreateInfo.pSubpasses = &subpassDesc; - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &m_renderPass)); - } - - // frame buffer - SLANG_RETURN_ON_FAIL(m_swapChain.createFrameBuffers(m_renderPass)); - - _beginRender(); - return SLANG_OK; } @@ -1444,30 +1438,98 @@ void VKRenderer::setClearColor(const float color[4]) void VKRenderer::clearFrame() { + _beginPass(); + ShortList<VkClearAttachment> clears; + for (Index i = 0; i < m_currentFramebuffer->renderTargetViews.getCount(); i++) + { + VkClearAttachment attachment; + attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + memcpy(attachment.clearValue.color.float32, m_clearColor, sizeof(float) * 4); + attachment.colorAttachment = (int)i; + clears.add(attachment); + } + if (m_currentFramebuffer->depthStencilView) + { + VkClearAttachment attachment; + attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + attachment.clearValue.depthStencil.depth = 1.0f; + attachment.clearValue.depthStencil.stencil = 0; + clears.add(attachment); + } + VkClearRect rect = {}; + rect.baseArrayLayer = 0; + rect.layerCount = 1; + rect.rect.extent.width = m_currentFramebuffer->m_width; + rect.rect.extent.height = m_currentFramebuffer->m_height; + m_api.vkCmdClearAttachments( + m_deviceQueue.getCommandBuffer(), + (uint32_t)clears.getCount(), + clears.getArrayView().getBuffer(), + 1, + &rect); + _endPass(); +} + +void VKRenderer::beginFrame() +{ + if (m_deviceQueue.isCurrent(VulkanDeviceQueue::EventType::EndFrame)) + m_deviceQueue.makeCompleted(VulkanDeviceQueue::EventType::EndFrame); } -void VKRenderer::presentFrame() +void VKRenderer::endFrame() { _endRender(); +} + +void VKRenderer::makeSwapchainImagePresentable(ISwapchain* swapchain) +{ + auto swapchainImpl = static_cast<SwapchainImpl*>(swapchain); + auto image = swapchainImpl->m_images[swapchainImpl->m_currentImageIndex]; + _transitionImageLayout( + image->m_image, + image->m_vkformat, + *image->getDesc(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + if (!m_deviceQueue.isCurrent(VulkanDeviceQueue::EventType::EndFrame)) + m_deviceQueue.makeCurrent(VulkanDeviceQueue::EventType::EndFrame); +} - const bool vsync = true; - m_swapChain.present(vsync); +Result VKRenderer::createSwapchain( + const ISwapchain::Desc& desc, WindowHandle window, ISwapchain** outSwapchain) +{ + RefPtr<SwapchainImpl> sc = new SwapchainImpl(); + SLANG_RETURN_ON_FAIL(sc->init(this, desc, window)); + *outSwapchain = sc.detach(); + return SLANG_OK; +} + +Result VKRenderer::createFramebufferLayout(const IFramebufferLayout::Desc& desc, IFramebufferLayout** outLayout) +{ + RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl(); + SLANG_RETURN_ON_FAIL(layout->init(this, desc)); + *outLayout = layout.detach(); + return SLANG_OK; +} - _beginRender(); +Result VKRenderer::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer) +{ + RefPtr<FramebufferImpl> fb = new FramebufferImpl(); + SLANG_RETURN_ON_FAIL(fb->init(this, desc)); + *outFramebuffer = fb.detach(); + return SLANG_OK; } -TextureResource::Desc VKRenderer::getSwapChainTextureDesc() +void VKRenderer::setFramebuffer(IFramebuffer* framebuffer) { - TextureResource::Desc desc; - desc.init2D(IResource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1); - return desc; + m_currentFramebuffer = static_cast<FramebufferImpl*>(framebuffer); } -SlangResult VKRenderer::captureScreenSurface( - void* buffer, size_t* inOutBufferSize, size_t* outRowPitch, size_t* outPixelSize) +SlangResult VKRenderer::readTextureResource( + ITextureResource* texture, ISlangBlob** outBlob, size_t* outRowPitch, size_t* outPixelSize) { - SLANG_UNUSED(buffer); - SLANG_UNUSED(inOutBufferSize); + SLANG_UNUSED(texture); + SLANG_UNUSED(outBlob); SLANG_UNUSED(outRowPitch); SLANG_UNUSED(outPixelSize); return SLANG_FAIL; @@ -1578,6 +1640,32 @@ static VkImageUsageFlags _calcImageUsageFlags(int bindFlags, int cpuAccessFlags, return usage; } +bool isDepthFormat(VkFormat format) +{ + switch (format) + { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + } + return false; +} + +bool isStencilFormat(VkFormat format) +{ + switch (format) + { + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + } + return false; +} + void VKRenderer::_transitionImageLayout(VkImage image, VkFormat format, const TextureResource::Desc& desc, VkImageLayout oldLayout, VkImageLayout newLayout) { VkImageMemoryBarrier barrier = {}; @@ -1587,7 +1675,14 @@ void VKRenderer::_transitionImageLayout(VkImage image, VkFormat format, const Te barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + if (isDepthFormat(format)) + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (isStencilFormat(format)) + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + if (barrier.subresourceRange.aspectMask == 0) + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = desc.numMipLevels; barrier.subresourceRange.baseArrayLayer = 0; @@ -1612,6 +1707,47 @@ void VKRenderer::_transitionImageLayout(VkImage image, VkFormat format, const Te sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } + else if ( + oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && + newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + else if ( + oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && + (newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)) + { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + } + else if ( + oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && + newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) + { + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = 0; + + sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + else if ( + oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && + newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + } else { assert(!"unsupported layout transition!"); @@ -1653,7 +1789,7 @@ Result VKRenderer::createTextureResource(IResource::Usage initialUsage, const IT const int arraySize = desc.calcEffectiveArraySize(); RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(desc, initialUsage, &m_api)); - + texture->m_vkformat = format; // Create the image { VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; @@ -1786,7 +1922,7 @@ Result VKRenderer::createTextureResource(IResource::Usage initialUsage, const IT { const uint8_t* srcData = (const uint8_t*)(initData->subResources[subResourceIndex]); - for (int l = 0; l < numRows; l++) + for (uint32_t l = 0; l < numRows; l++) { ::memcpy(dstData, srcData, dstRowSizeInBytes); @@ -1846,7 +1982,30 @@ Result VKRenderer::createTextureResource(IResource::Usage initialUsage, const IT m_deviceQueue.flushAndWait(); } - + else + { + switch (initialUsage) + { + case IResource::Usage::RenderTarget: + _transitionImageLayout( + texture->m_image, + format, + *texture->getDesc(), + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + break; + case IResource::Usage::DepthWrite: + _transitionImageLayout( + texture->m_image, + format, + *texture->getDesc(), + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + break; + default: + break; + } + } *outResource = texture.detach(); return SLANG_OK; } @@ -1983,6 +2142,44 @@ static VkCompareOp translateComparisonFunc(ComparisonFunc func) } } +static VkStencilOp translateStencilOp(StencilOp op) +{ + switch (op) + { + case StencilOp::DecrementSaturate: + return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + case StencilOp::DecrementWrap: + return VK_STENCIL_OP_DECREMENT_AND_WRAP; + case StencilOp::IncrementSaturate: + return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + case StencilOp::IncrementWrap: + return VK_STENCIL_OP_INCREMENT_AND_WRAP; + case StencilOp::Invert: + return VK_STENCIL_OP_INVERT; + case StencilOp::Keep: + return VK_STENCIL_OP_KEEP; + case StencilOp::Replace: + return VK_STENCIL_OP_REPLACE; + case StencilOp::Zero: + return VK_STENCIL_OP_ZERO; + default: + return VK_STENCIL_OP_KEEP; + } +} + +static VkStencilOpState translateStencilState(DepthStencilOpDesc desc) +{ + VkStencilOpState rs; + rs.compareMask = desc.stencilCompareMask; + rs.compareOp = translateComparisonFunc(desc.stencilFunc); + rs.depthFailOp = translateStencilOp(desc.stencilDepthFailOp); + rs.failOp = translateStencilOp(desc.stencilFailOp); + rs.passOp = translateStencilOp(desc.stencilPassOp); + rs.reference = desc.stencilReference; + rs.writeMask = desc.stencilWriteMask; + return rs; +} + Result VKRenderer::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) { VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; @@ -2022,7 +2219,7 @@ Result VKRenderer::createTextureView(ITextureResource* texture, IResourceView::D VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.flags = 0; - createInfo.format = VulkanUtil::getVkFormat(desc.format); + createInfo.format = resourceImpl->m_vkformat; createInfo.image = resourceImpl->m_image; createInfo.components = VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,VK_COMPONENT_SWIZZLE_B,VK_COMPONENT_SWIZZLE_A }; switch (resourceImpl->getType()) @@ -2052,10 +2249,29 @@ Result VKRenderer::createTextureView(ITextureResource* texture, IResourceView::D { case IResourceView::Type::DepthStencil: view->m_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + switch (resourceImpl->m_vkformat) + { + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_X8_D24_UNORM_PACK32: + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + case VK_FORMAT_S8_UINT: + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + break; + default: + break; + } + createInfo.subresourceRange.levelCount = 1; break; case IResourceView::Type::RenderTarget: view->m_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + createInfo.subresourceRange.levelCount = 1; break; case IResourceView::Type::ShaderResource: view->m_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -2309,20 +2525,16 @@ void VKRenderer::setIndexBuffer(IBufferResource* buffer, Format indexFormat, UIn { } -void VKRenderer::setDepthStencilTarget(IResourceView* depthStencilView) -{ -} - void VKRenderer::setViewports(UInt count, Viewport const* viewports) { static const int kMaxViewports = 8; // TODO: base on device caps assert(count <= kMaxViewports); - VkViewport vkViewports[kMaxViewports]; + m_viewports.setCount(count); for(UInt ii = 0; ii < count; ++ii) { auto& inViewport = viewports[ii]; - auto& vkViewport = vkViewports[ii]; + auto& vkViewport = m_viewports[ii]; vkViewport.x = inViewport.originX; vkViewport.y = inViewport.originY; @@ -2333,7 +2545,7 @@ void VKRenderer::setViewports(UInt count, Viewport const* viewports) } VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - m_api.vkCmdSetViewport(commandBuffer, 0, uint32_t(count), vkViewports); + m_api.vkCmdSetViewport(commandBuffer, 0, uint32_t(count), m_viewports.getBuffer()); } void VKRenderer::setScissorRects(UInt count, ScissorRect const* rects) @@ -2341,20 +2553,21 @@ void VKRenderer::setScissorRects(UInt count, ScissorRect const* rects) static const int kMaxScissorRects = 8; // TODO: base on device caps assert(count <= kMaxScissorRects); - VkRect2D vkRects[kMaxScissorRects]; + m_scissorRects.setCount(count); for(UInt ii = 0; ii < count; ++ii) { auto& inRect = rects[ii]; - auto& vkRect = vkRects[ii]; + auto& vkRect = m_scissorRects[ii]; vkRect.offset.x = int32_t(inRect.minX); vkRect.offset.y = int32_t(inRect.minY); vkRect.extent.width = uint32_t(inRect.maxX - inRect.minX); vkRect.extent.height = uint32_t(inRect.maxY - inRect.minY); + } VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - m_api.vkCmdSetScissor(commandBuffer, 0, uint32_t(count), vkRects); + m_api.vkCmdSetScissor(commandBuffer, 0, uint32_t(count), m_scissorRects.getBuffer()); } void VKRenderer::setPipelineState(IPipelineState* state) @@ -2365,7 +2578,8 @@ void VKRenderer::setPipelineState(IPipelineState* state) void VKRenderer::_flushBindingState(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint) { auto pipeline = m_currentPipeline; - + auto& descSetCopies = m_descSetCopies; + descSetCopies.clear(); // We start by binding the pipeline state. // m_api.vkCmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline->m_pipeline); @@ -2375,6 +2589,41 @@ void VKRenderer::_flushBindingState(VkCommandBuffer commandBuffer, VkPipelineBin auto pipelineLayoutImpl = pipeline->m_pipelineLayout.Ptr(); auto vkPipelineLayout = pipelineLayoutImpl->m_pipelineLayout; auto descriptorSetCount = pipelineLayoutImpl->m_descriptorSetCount; + for (uint32_t i = 0; i < (uint32_t)descriptorSetCount; i++) + { + if (m_currentDescriptorSetImpls[i]->m_isTransient) + { + // A transient descriptor set may go out of life cycle after command list recording, + // therefore we must make a copy of it in the per-frame descriptor pool. + + // If we have already created a transient copy for this descriptor set, skip the copy. + if (m_currentDescriptorSetImpls[i]->m_descriptorSet.handle != + m_currentDescriptorSets[i]) + continue; + + auto descSet = m_deviceQueue.allocTransientDescriptorSet( + m_currentDescriptorSetImpls[i]->m_layout->m_descriptorSetLayout); + uint32_t bindingIndex = 0; + for (auto binding : m_currentDescriptorSetImpls[i]->m_layout->m_vkBindings) + { + VkCopyDescriptorSet copy = {}; + copy.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; + copy.srcSet = m_currentDescriptorSetImpls[i]->m_descriptorSet.handle; + copy.dstSet = descSet.handle; + copy.srcBinding = copy.dstBinding = bindingIndex; + copy.srcArrayElement = copy.dstArrayElement = 0; + copy.descriptorCount = binding.descriptorCount; + descSetCopies.add(copy); + bindingIndex++; + } + m_currentDescriptorSets[i] = descSet.handle; + } + } + if (descSetCopies.getCount()) + { + m_api.vkUpdateDescriptorSets( + m_api.m_device, 0, nullptr, (uint32_t)descSetCopies.getCount(), descSetCopies.getBuffer()); + } m_api.vkCmdBindDescriptorSets(commandBuffer, pipelineBindPoint, vkPipelineLayout, 0, uint32_t(descriptorSetCount), &m_currentDescriptorSets[0], @@ -2509,7 +2758,8 @@ Result VKRenderer::createDescriptorSetLayout(const IDescriptorSetLayout::Desc& d { RefPtr<DescriptorSetLayoutImpl> descriptorSetLayoutImpl = new DescriptorSetLayoutImpl(m_api); - Slang::List<VkDescriptorSetLayoutBinding> dstBindings; + auto& dstBindings = descriptorSetLayoutImpl->m_vkBindings; + Slang::List<uint32_t> descriptorCountForTypes; UInt rangeCount = desc.slotRangeCount; @@ -2610,31 +2860,7 @@ Result VKRenderer::createDescriptorSetLayout(const IDescriptorSetLayout::Desc& d VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; SLANG_VK_CHECK(m_api.vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout)); - // Create a pool while we are at it, to allocate descriptor sets of this type. - - List<VkDescriptorPoolSize> poolSizes; - for (Index ii = 0; ii < descriptorCountForTypes.getCount(); ++ii) - { - auto descriptorCount = descriptorCountForTypes[ii]; - if (descriptorCount > 0) - { - VkDescriptorPoolSize poolSize; - poolSize.type = VkDescriptorType(ii); - poolSize.descriptorCount = descriptorCount; - poolSizes.add(poolSize); - } - } - - VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size. - descriptorPoolInfo.poolSizeCount = uint32_t(poolSizes.getCount()); - descriptorPoolInfo.pPoolSizes = poolSizes.getBuffer(); - - VkDescriptorPool descriptorPool = VK_NULL_HANDLE; - SLANG_VK_CHECK(m_api.vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &descriptorPool)); - descriptorSetLayoutImpl->m_descriptorSetLayout = descriptorSetLayout; - descriptorSetLayoutImpl->m_descriptorPool = descriptorPool; *outLayout = descriptorSetLayoutImpl.detach(); return SLANG_OK; @@ -2703,22 +2929,18 @@ Result VKRenderer::createPipelineLayout(const IPipelineLayout::Desc& desc, IPipe return SLANG_OK; } -Result VKRenderer::createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet** outDescriptorSet) +Result VKRenderer::createDescriptorSet( + IDescriptorSetLayout* layout, + IDescriptorSet::Flag::Enum flag, + IDescriptorSet** outDescriptorSet) { auto layoutImpl = (DescriptorSetLayoutImpl*)layout; - VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - descriptorSetAllocInfo.descriptorPool = layoutImpl->m_descriptorPool; - descriptorSetAllocInfo.descriptorSetCount = 1; - descriptorSetAllocInfo.pSetLayouts = &layoutImpl->m_descriptorSetLayout; - - VkDescriptorSet descriptorSet; - SLANG_VK_CHECK(m_api.vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &descriptorSet)); - RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl(this); descriptorSetImpl->m_layout = layoutImpl; - descriptorSetImpl->m_descriptorSet = descriptorSet; - + descriptorSetImpl->m_descriptorSet = + descriptorSetAllocator.allocate(layoutImpl->m_descriptorSetLayout); + descriptorSetImpl->m_isTransient = (flag == IDescriptorSet::Flag::Enum::Transient); descriptorSetImpl->m_rootConstantData.setCount(layoutImpl->m_rootConstantDataSize); descriptorSetImpl->m_boundObjects.setCount(layoutImpl->m_totalBoundObjectCount); @@ -2741,7 +2963,7 @@ void VKRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, IB bufferInfo.range = bufferImpl->getDesc()->sizeInBytes; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.dstSet = m_descriptorSet; + writeInfo.dstSet = m_descriptorSet.handle; writeInfo.dstBinding = uint32_t(bindingIndex); writeInfo.dstArrayElement = uint32_t(index); writeInfo.descriptorCount = 1; @@ -2771,7 +2993,7 @@ void VKRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, IResourc imageInfo.imageLayout = textureViewImpl->m_layout; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.dstSet = m_descriptorSet; + writeInfo.dstSet = m_descriptorSet.handle; writeInfo.dstBinding = uint32_t(bindingIndex); writeInfo.dstArrayElement = uint32_t(index); writeInfo.descriptorCount = 1; @@ -2787,7 +3009,7 @@ void VKRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, IResourc auto bufferViewImpl = (TexelBufferResourceViewImpl*)viewImpl; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.dstSet = m_descriptorSet; + writeInfo.dstSet = m_descriptorSet.handle; writeInfo.dstBinding = uint32_t(bindingIndex); writeInfo.dstArrayElement = uint32_t(index); writeInfo.descriptorCount = 1; @@ -2808,7 +3030,7 @@ void VKRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, IResourc bufferInfo.range = bufferViewImpl->size; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.dstSet = m_descriptorSet; + writeInfo.dstSet = m_descriptorSet.handle; writeInfo.dstBinding = uint32_t(bindingIndex); writeInfo.dstArrayElement = uint32_t(index); writeInfo.descriptorCount = 1; @@ -2833,7 +3055,7 @@ void VKRenderer::DescriptorSetImpl::setSampler(UInt range, UInt index, ISamplerS auto descriptorType = rangeInfo.vkDescriptorType; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.dstSet = m_descriptorSet; + writeInfo.dstSet = m_descriptorSet.handle; writeInfo.dstBinding = uint32_t(bindingIndex); writeInfo.dstArrayElement = uint32_t(index); writeInfo.descriptorCount = 1; @@ -2915,7 +3137,7 @@ void VKRenderer::setDescriptorSet(PipelineType pipelineType, IPipelineLayout* la auto descriptorSetImpl = (DescriptorSetImpl*)descriptorSet; m_currentDescriptorSetImpls[index] = descriptorSetImpl; - m_currentDescriptorSets[index] = descriptorSetImpl->m_descriptorSet; + m_currentDescriptorSets[index] = descriptorSetImpl->m_descriptorSet.handle; } Result VKRenderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) @@ -3062,6 +3284,16 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR}; dynamicStateInfo.pDynamicStates = dynamicStates; + VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = {}; + depthStencilStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateInfo.depthTestEnable = inDesc.depthStencil.depthTestEnable ? 1 : 0; + depthStencilStateInfo.back = translateStencilState(inDesc.depthStencil.backFace); + depthStencilStateInfo.front = translateStencilState(inDesc.depthStencil.frontFace); + depthStencilStateInfo.depthBoundsTestEnable = 0; + depthStencilStateInfo.depthCompareOp = translateComparisonFunc(inDesc.depthStencil.depthFunc); + depthStencilStateInfo.depthWriteEnable = inDesc.depthStencil.depthWriteEnable ? 1 : 0; + depthStencilStateInfo.stencilTestEnable = inDesc.depthStencil.stencilEnable ? 1 : 0; + VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -3073,8 +3305,9 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDepthStencilState = &depthStencilStateInfo; pipelineInfo.layout = pipelineLayoutImpl->m_pipelineLayout; - pipelineInfo.renderPass = m_renderPass; + pipelineInfo.renderPass = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout)->m_renderPass; pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.pDynamicState = &dynamicStateInfo; @@ -3085,6 +3318,8 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(m_api); pipelineStateImpl->m_pipeline = pipeline; pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl; + pipelineStateImpl->m_framebufferLayout = + static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout); pipelineStateImpl->m_shaderProgram = programImpl; pipelineStateImpl->init(desc); *outState = pipelineStateImpl.detach(); diff --git a/tools/gfx/vulkan/render-vk.h b/tools/gfx/vulkan/render-vk.h index f259ab44c..b2bceb31c 100644 --- a/tools/gfx/vulkan/render-vk.h +++ b/tools/gfx/vulkan/render-vk.h @@ -6,6 +6,6 @@ namespace gfx { -SlangResult SLANG_MCALL createVKRenderer(const IRenderer::Desc* desc, void* windowHandle, IRenderer** outRenderer); +SlangResult SLANG_MCALL createVKRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer); } // gfx diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 3fb4b3909..77e6a9a09 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -14,14 +14,14 @@ namespace gfx { #define VK_API_INSTANCE_PROCS_OPT(x) \ x(vkGetPhysicalDeviceFeatures2) \ x(vkGetPhysicalDeviceProperties2) \ + x(vkCreateDebugReportCallbackEXT) \ + x(vkDestroyDebugReportCallbackEXT) \ + x(vkDebugReportMessageEXT) \ /* */ #define VK_API_INSTANCE_PROCS(x) \ x(vkCreateDevice) \ x(vkDestroyDevice) \ - x(vkCreateDebugReportCallbackEXT) \ - x(vkDestroyDebugReportCallbackEXT) \ - x(vkDebugReportMessageEXT) \ x(vkEnumeratePhysicalDevices) \ x(vkGetPhysicalDeviceProperties) \ x(vkGetPhysicalDeviceFeatures) \ @@ -34,6 +34,7 @@ namespace gfx { #define VK_API_DEVICE_PROCS(x) \ x(vkCreateDescriptorPool) \ x(vkDestroyDescriptorPool) \ + x(vkResetDescriptorPool) \ x(vkGetDeviceQueue) \ x(vkQueueSubmit) \ x(vkQueueWaitIdle) \ @@ -47,6 +48,7 @@ namespace gfx { x(vkCreateDescriptorSetLayout) \ x(vkDestroyDescriptorSetLayout) \ x(vkAllocateDescriptorSets) \ + x(vkFreeDescriptorSets) \ x(vkUpdateDescriptorSets) \ x(vkCreatePipelineLayout) \ x(vkDestroyPipelineLayout) \ @@ -74,6 +76,7 @@ namespace gfx { x(vkGetImageMemoryRequirements) \ \ x(vkCmdBindPipeline) \ + x(vkCmdClearAttachments) \ x(vkCmdBindDescriptorSets) \ x(vkCmdDispatch) \ x(vkCmdDraw) \ @@ -107,6 +110,7 @@ namespace gfx { x(vkBeginCommandBuffer) \ x(vkEndCommandBuffer) \ x(vkResetCommandBuffer) \ + x(vkResetCommandPool) \ \ x(vkBindImageMemory) \ x(vkBindBufferMemory) \ diff --git a/tools/gfx/vulkan/vk-descriptor-allocator.cpp b/tools/gfx/vulkan/vk-descriptor-allocator.cpp new file mode 100644 index 000000000..c01e37642 --- /dev/null +++ b/tools/gfx/vulkan/vk-descriptor-allocator.cpp @@ -0,0 +1,70 @@ +#include "vk-descriptor-allocator.h" +#include "vk-util.h" + +namespace gfx +{ +VkDescriptorPool DescriptorSetAllocator::newPool() +{ + VkDescriptorPoolCreateInfo descriptorPoolInfo = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + VkDescriptorPoolSize poolSizes[] = { + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_SAMPLER, 1024}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 4096}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1024}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 256}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 256}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4096}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4096}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 4096}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 4096}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 16}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, 16}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 256}}; + descriptorPoolInfo.maxSets = 4096; + descriptorPoolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(VkDescriptorPoolSize); + descriptorPoolInfo.pPoolSizes = poolSizes; + descriptorPoolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + SLANG_VK_CHECK(m_api->vkCreateDescriptorPool( + m_api->m_device, &descriptorPoolInfo, nullptr, &descriptorPool)); + pools.add(descriptorPool); + return descriptorPool; +} + +VulkanDescriptorSet DescriptorSetAllocator::allocate(VkDescriptorSetLayout layout) +{ + VulkanDescriptorSet rs = {}; + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = getPool(); + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &layout; + if (m_api->vkAllocateDescriptorSets(m_api->m_device, &allocInfo, &rs.handle) == VK_SUCCESS) + { + rs.pool = allocInfo.descriptorPool; + return rs; + } + // If allocation from last pool fails, try all existing pools. + for (Slang::Index i = 0; i < pools.getCount() - 1; i++) + { + allocInfo.descriptorPool = pools[i]; + if (m_api->vkAllocateDescriptorSets(m_api->m_device, &allocInfo, &rs.handle) == VK_SUCCESS) + { + rs.pool = allocInfo.descriptorPool; + return rs; + } + } + // If we still cannot allocate the descriptor set, add a new pool. + auto pool = newPool(); + allocInfo.descriptorPool = pool; + if (m_api->vkAllocateDescriptorSets(m_api->m_device, &allocInfo, &rs.handle) == VK_SUCCESS) + { + rs.pool = allocInfo.descriptorPool; + return rs; + } + // Failed to allocate from a new pool, we are in trouble. + assert(!"descriptor set allocation failed."); + return rs; +} +} diff --git a/tools/gfx/vulkan/vk-descriptor-allocator.h b/tools/gfx/vulkan/vk-descriptor-allocator.h new file mode 100644 index 000000000..3d5c441ad --- /dev/null +++ b/tools/gfx/vulkan/vk-descriptor-allocator.h @@ -0,0 +1,43 @@ +// vk-descriptor-allocator.h + +#pragma once + +#include "vk-api.h" +#include "core/slang-list.h" + +namespace gfx +{ +struct VulkanDescriptorSet +{ + VkDescriptorSet handle; + VkDescriptorPool pool; +}; +class DescriptorSetAllocator +{ +public: + Slang::List<VkDescriptorPool> pools; + const VulkanApi* m_api; + VkDescriptorPool newPool(); + VkDescriptorPool getPool() + { + if (pools.getCount()) + return pools.getLast(); + return newPool(); + } + VulkanDescriptorSet allocate(VkDescriptorSetLayout layout); + void free(VulkanDescriptorSet set) + { + m_api->vkFreeDescriptorSets(m_api->m_device, set.pool, 1, &set.handle); + } + void reset() + { + for (auto pool : pools) + m_api->vkResetDescriptorPool(m_api->m_device, pool, 0); + } + void close() + { + for (auto pool : pools) + m_api->vkDestroyDescriptorPool(m_api->m_device, pool, nullptr); + } +}; +} // namespace gfx diff --git a/tools/gfx/vulkan/vk-device-queue.cpp b/tools/gfx/vulkan/vk-device-queue.cpp index 0cc9a0a0d..149e5dec2 100644 --- a/tools/gfx/vulkan/vk-device-queue.cpp +++ b/tools/gfx/vulkan/vk-device-queue.cpp @@ -24,10 +24,11 @@ void VulkanDeviceQueue::destroy() for (int i = 0; i < m_numCommandBuffers; i++) { - m_api->vkFreeCommandBuffers(m_api->m_device, m_commandPool, 1, &m_commandBuffers[i]); + m_api->vkFreeCommandBuffers(m_api->m_device, m_commandPools[i], 1, &m_commandBuffers[i]); m_api->vkDestroyFence(m_api->m_device, m_fences[i].fence, nullptr); + m_api->vkDestroyCommandPool(m_api->m_device, m_commandPools[i], nullptr); + m_descSetAllocator[i].close(); } - m_api->vkDestroyCommandPool(m_api->m_device, m_commandPool, nullptr); m_api = nullptr; } } @@ -47,26 +48,25 @@ SlangResult VulkanDeviceQueue::init(const VulkanApi& api, VkQueue queue, int que m_queue = queue; - VkCommandPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - poolCreateInfo.queueFamilyIndex = queueIndex; + for (int i = 0; i < m_numCommandBuffers; i++) + { + VkCommandPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - api.vkCreateCommandPool(api.m_device, &poolCreateInfo, nullptr, &m_commandPool); + poolCreateInfo.queueFamilyIndex = queueIndex; - VkCommandBufferAllocateInfo commandInfo = {}; - commandInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - commandInfo.commandPool = m_commandPool; - commandInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - commandInfo.commandBufferCount = 1; + api.vkCreateCommandPool(api.m_device, &poolCreateInfo, nullptr, &m_commandPools[i]); - VkFenceCreateInfo fenceCreateInfo = {}; - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.flags = 0; // VK_FENCE_CREATE_SIGNALED_BIT; + VkCommandBufferAllocateInfo commandInfo = {}; + commandInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandInfo.commandPool = m_commandPools[i]; + commandInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + commandInfo.commandBufferCount = 1; - for (int i = 0; i < m_numCommandBuffers; i++) - { + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = 0; // VK_FENCE_CREATE_SIGNALED_BIT; Fence& fence = m_fences[i]; api.vkAllocateCommandBuffers(api.m_device, &commandInfo, &m_commandBuffers[i]); @@ -74,6 +74,8 @@ SlangResult VulkanDeviceQueue::init(const VulkanApi& api, VkQueue queue, int que api.vkCreateFence(api.m_device, &fenceCreateInfo, nullptr, &fence.fence); fence.active = false; fence.value = 0; + + m_descSetAllocator[i].m_api = &api; } VkSemaphoreCreateInfo semaphoreCreateInfo = {}; @@ -133,6 +135,7 @@ void VulkanDeviceQueue::flushStepA() // No longer waiting on this semaphore makeCompleted(EventType::BeginFrame); + makeCompleted(EventType::EndFrame); } void VulkanDeviceQueue::_updateFenceAtIndex( int fenceIndex, bool blocking) @@ -161,6 +164,7 @@ void VulkanDeviceQueue::flushStepB() { m_commandBufferIndex = (m_commandBufferIndex + 1) % m_numCommandBuffers; m_commandBuffer = m_commandBuffers[m_commandBufferIndex]; + m_commandPool = m_commandPools[m_commandBufferIndex]; // non-blocking update of fence values for (int i = 0; i < m_numCommandBuffers; ++i) @@ -171,9 +175,8 @@ void VulkanDeviceQueue::flushStepB() // blocking update of fence values _updateFenceAtIndex(m_commandBufferIndex, true); - m_api->vkResetCommandBuffer(m_commandBuffer, 0); - - //m_api.vkResetCommandPool(m_api->m_device, m_commandPool, 0); + m_descSetAllocator[m_commandBufferIndex].reset(); + m_api->vkResetCommandPool(m_api->m_device, m_commandPool, 0); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -194,6 +197,11 @@ void VulkanDeviceQueue::flushAndWait() waitForIdle(); } +VkSemaphore VulkanDeviceQueue::getSemaphore(EventType eventType) +{ + return m_semaphores[int(eventType)]; +} + VkSemaphore VulkanDeviceQueue::makeCurrent(EventType eventType) { assert(!isCurrent(eventType)); diff --git a/tools/gfx/vulkan/vk-device-queue.h b/tools/gfx/vulkan/vk-device-queue.h index cd53b6b9d..9869a3caf 100644 --- a/tools/gfx/vulkan/vk-device-queue.h +++ b/tools/gfx/vulkan/vk-device-queue.h @@ -2,6 +2,7 @@ #pragma once #include "vk-api.h" +#include "vk-descriptor-allocator.h" namespace gfx { @@ -35,6 +36,7 @@ struct VulkanDeviceQueue /// Make the specified event 'current' - meaning it's semaphore must be waited on VkSemaphore makeCurrent(EventType eventType); + VkSemaphore getSemaphore(EventType eventType); /// Makes the event no longer required to be waited on void makeCompleted(EventType eventType); /// Returns true if the event is already current @@ -43,6 +45,11 @@ struct VulkanDeviceQueue /// Get the command buffer VkCommandBuffer getCommandBuffer() const { return m_commandBuffer; } + VulkanDescriptorSet allocTransientDescriptorSet(VkDescriptorSetLayout layout) + { + return m_descSetAllocator[m_commandBufferIndex].allocate(layout); + } + /// Get the queue VkQueue getQueue() const { return m_queue; } @@ -76,19 +83,21 @@ struct VulkanDeviceQueue VkQueue m_queue = VK_NULL_HANDLE; - VkCommandPool m_commandPool = VK_NULL_HANDLE; int m_numCommandBuffers = 0; int m_commandBufferIndex = 0; // There are the same amount of command buffers as fences + VkCommandPool m_commandPools[kMaxCommandBuffers] = {VK_NULL_HANDLE}; VkCommandBuffer m_commandBuffers[kMaxCommandBuffers] = { VK_NULL_HANDLE }; Fence m_fences[kMaxCommandBuffers] = { {VK_NULL_HANDLE, 0, 0u} }; VkCommandBuffer m_commandBuffer = VK_NULL_HANDLE; - + VkCommandPool m_commandPool = VK_NULL_HANDLE; VkSemaphore m_semaphores[int(EventType::CountOf)]; VkSemaphore m_currentSemaphores[int(EventType::CountOf)]; + DescriptorSetAllocator m_descSetAllocator[kMaxCommandBuffers]; + uint64_t m_lastFenceCompleted = 1; uint64_t m_nextFenceValue = 2; diff --git a/tools/gfx/vulkan/vk-swap-chain.cpp b/tools/gfx/vulkan/vk-swap-chain.cpp index 21460ce61..bc6160a02 100644 --- a/tools/gfx/vulkan/vk-swap-chain.cpp +++ b/tools/gfx/vulkan/vk-swap-chain.cpp @@ -83,7 +83,7 @@ SlangResult VulkanSwapChain::init(VulkanDeviceQueue* deviceQueue, const Desc& de VkFormat format = formats[i]; if (_indexOfFormat(surfaceFormats, format) >= 0) { - m_format = format; + m_format = format; } } @@ -94,10 +94,12 @@ SlangResult VulkanSwapChain::init(VulkanDeviceQueue* deviceQueue, const Desc& de // Save the desc m_desc = desc; - SLANG_RETURN_ON_FAIL(_createSwapChain()); - m_desc = desc; + if (descIn.m_format == Format::RGBA_Unorm_UInt8 && m_format == VK_FORMAT_B8G8R8A8_UNORM) + { + m_desc.m_format = Format::BGRA_Unorm_UInt8; + } return SLANG_OK; } @@ -121,61 +123,6 @@ void VulkanSwapChain::getWindowSize(int* widthOut, int* heightOut) const #endif } -SlangResult VulkanSwapChain::_createFrameBuffers(VkRenderPass renderPass) -{ - assert(renderPass != VK_NULL_HANDLE); - - for (Index i = 0; i < m_images.getCount(); ++i) - { - Image& image = m_images[i]; - VkImageView attachments[] = - { - image.m_imageView - }; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachments; - framebufferInfo.width = m_width; - framebufferInfo.height = m_height; - framebufferInfo.layers = 1; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateFramebuffer(m_api->m_device, &framebufferInfo, nullptr, &image.m_frameBuffer)); - } - - return SLANG_OK; -} - -void VulkanSwapChain::_destroyFrameBuffers() -{ - for (Index i = 0; i < m_images.getCount(); ++i) - { - Image& image = m_images[i]; - if (image.m_frameBuffer != VK_NULL_HANDLE) - { - m_api->vkDestroyFramebuffer(m_api->m_device, image.m_frameBuffer, nullptr); - image.m_frameBuffer = VK_NULL_HANDLE; - } - } -} - -SlangResult VulkanSwapChain::createFrameBuffers(VkRenderPass renderPass) -{ - if (m_renderPass != VK_NULL_HANDLE) - { - _destroyFrameBuffers(); - m_renderPass = VK_NULL_HANDLE; - } - if (renderPass != VK_NULL_HANDLE) - { - SLANG_RETURN_ON_FAIL(_createFrameBuffers(renderPass)); - } - m_renderPass = renderPass; - return SLANG_OK; -} - SlangResult VulkanSwapChain::_createSwapChain() { if (hasValidSwapChain()) @@ -215,7 +162,7 @@ SlangResult VulkanSwapChain::_createSwapChain() { int numCheckPresentOptions = 3; VkPresentModeKHR presentOptions[] = { VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR }; - if (m_vsync) + if (m_desc.m_vsync) { presentOptions[0] = VK_PRESENT_MODE_FIFO_KHR; presentOptions[1] = VK_PRESENT_MODE_IMMEDIATE_KHR; @@ -245,7 +192,7 @@ SlangResult VulkanSwapChain::_createSwapChain() VkSwapchainCreateInfoKHR swapchainDesc = {}; swapchainDesc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainDesc.surface = m_surface; - swapchainDesc.minImageCount = 3; + swapchainDesc.minImageCount = m_desc.m_imageCount; swapchainDesc.imageFormat = m_format; swapchainDesc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; swapchainDesc.imageExtent = imageExtent; @@ -262,7 +209,7 @@ SlangResult VulkanSwapChain::_createSwapChain() uint32_t numSwapChainImages = 0; m_api->vkGetSwapchainImagesKHR(m_api->m_device, m_swapChain, &numSwapChainImages, nullptr); - + m_desc.m_imageCount = numSwapChainImages; { List<VkImage> images; images.setCount(numSwapChainImages); @@ -272,45 +219,9 @@ SlangResult VulkanSwapChain::_createSwapChain() m_images.setCount(numSwapChainImages); for (int i = 0; i < int(numSwapChainImages); ++i) { - Image& dstImage = m_images[i]; - dstImage.m_image = images[i]; - + m_images[i] = images[i]; } } - - { - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = m_format; - - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - for (int i = 0; i < int(numSwapChainImages); ++i) - { - Image& image = m_images[i]; - - createInfo.image = image.m_image; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateImageView(m_api->m_device, &createInfo, nullptr, &image.m_imageView)); - } - } - - if (m_renderPass != VK_NULL_HANDLE) - { - _createFrameBuffers(m_renderPass); - } - return SLANG_OK; } @@ -323,21 +234,6 @@ void VulkanSwapChain::_destroySwapChain() m_deviceQueue->waitForIdle(); - if (m_renderPass != VK_NULL_HANDLE) - { - _destroyFrameBuffers(); - } - - for (Index i = 0; i < m_images.getCount(); ++i) - { - Image& image = m_images[i]; - - if (image.m_imageView != VK_NULL_HANDLE) - { - m_api->vkDestroyImageView(m_api->m_device, image.m_imageView, nullptr); - } - } - if (m_swapChain != VK_NULL_HANDLE) { m_api->vkDestroySwapchainKHR(m_api->m_device, m_swapChain, nullptr); @@ -397,7 +293,7 @@ void VulkanSwapChain::present(bool vsync) return; } - VkSemaphore endFrameSemaphore = m_deviceQueue->makeCurrent(VulkanDeviceQueue::EventType::EndFrame); + VkSemaphore endFrameSemaphore = m_deviceQueue->getSemaphore(VulkanDeviceQueue::EventType::EndFrame); m_deviceQueue->flushStepA(); @@ -408,18 +304,19 @@ void VulkanSwapChain::present(bool vsync) presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &m_swapChain; presentInfo.pImageIndices = swapChainIndices; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &endFrameSemaphore; - + if (endFrameSemaphore != VK_NULL_HANDLE) + { + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &endFrameSemaphore; + } VkResult result = m_api->vkQueuePresentKHR(m_deviceQueue->getQueue(), &presentInfo); m_deviceQueue->makeCompleted(VulkanDeviceQueue::EventType::EndFrame); m_deviceQueue->flushStepB(); - if (result != VK_SUCCESS || m_vsync != vsync) + if (result != VK_SUCCESS) { - m_vsync = vsync; _destroySwapChain(); } } diff --git a/tools/gfx/vulkan/vk-swap-chain.h b/tools/gfx/vulkan/vk-swap-chain.h index e5162d63b..0a2a40b4f 100644 --- a/tools/gfx/vulkan/vk-swap-chain.h +++ b/tools/gfx/vulkan/vk-swap-chain.h @@ -44,29 +44,21 @@ struct VulkanSwapChain m_depthFormatTypeless = Format::Unknown; m_depthFormat = Format::Unknown; m_textureDepthFormat = Format::Unknown; + m_imageCount = 2; + m_vsync = false; } Format m_format; - //bool m_enableFormat; Format m_depthFormatTypeless; Format m_depthFormat; Format m_textureDepthFormat; + uint32_t m_imageCount; + bool m_vsync; }; - struct Image - { - VkImage m_image = VK_NULL_HANDLE; - VkImageView m_imageView = VK_NULL_HANDLE; - VkFramebuffer m_frameBuffer = VK_NULL_HANDLE; - }; - - /// Must be called before the swap chain can be used SlangResult init(VulkanDeviceQueue* deviceQueue, const Desc& desc, const PlatformDesc* platformDesc); - /// Create the frame buffers (they must be compatible with the supplied renderPass) - SlangResult createFrameBuffers(VkRenderPass renderPass); - /// Returned the desc used to construct the swap chain. /// Is invalid if init hasn't returned with successful result. const Desc& getDesc() const { return m_desc; } @@ -89,7 +81,7 @@ struct VulkanSwapChain int getHeight() const { return m_height; } /// Get the detail about the images - const Slang::List<Image>& getImages() const { return m_images; } + const Slang::List<VkImage>& getImages() const { return m_images; } /// Get the next front render image index. Returns -1, if image couldn't be found int nextFrontImageIndex(); @@ -114,10 +106,7 @@ struct VulkanSwapChain const T* _getPlatformDesc() const { return static_cast<const T*>((const PlatformDesc*)m_platformDescBuffer.getBuffer()); } SlangResult _createSwapChain(); void _destroySwapChain(); - SlangResult _createFrameBuffers(VkRenderPass renderPass); - void _destroyFrameBuffers(); - bool m_vsync = true; int m_width = 0; int m_height = 0; @@ -127,11 +116,9 @@ struct VulkanSwapChain VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSwapchainKHR m_swapChain = VK_NULL_HANDLE; - VkRenderPass m_renderPass = VK_NULL_HANDLE; //< Not owned - int m_currentSwapChainIndex = 0; - Slang::List<Image> m_images; + Slang::List<VkImage> m_images; VulkanDeviceQueue* m_deviceQueue = nullptr; const VulkanApi* m_api = nullptr; diff --git a/tools/gfx/vulkan/vk-util.cpp b/tools/gfx/vulkan/vk-util.cpp index e8940d1b2..561b97a53 100644 --- a/tools/gfx/vulkan/vk-util.cpp +++ b/tools/gfx/vulkan/vk-util.cpp @@ -15,6 +15,7 @@ namespace gfx { case Format::RG_Float32: return VK_FORMAT_R32G32_SFLOAT; case Format::R_Float32: return VK_FORMAT_R32_SFLOAT; case Format::RGBA_Unorm_UInt8: return VK_FORMAT_R8G8B8A8_UNORM; + case Format::BGRA_Unorm_UInt8: return VK_FORMAT_B8G8R8A8_UNORM; case Format::R_UInt32: return VK_FORMAT_R32_UINT; case Format::D_Float32: return VK_FORMAT_D32_SFLOAT; diff --git a/tools/graphics-app-framework/gui.cpp b/tools/graphics-app-framework/gui.cpp index 3bc365701..0d416ec85 100644 --- a/tools/graphics-app-framework/gui.cpp +++ b/tools/graphics-app-framework/gui.cpp @@ -36,7 +36,7 @@ void setNativeWindowHook(Window* window, WNDPROC proc); #endif -GUI::GUI(Window* window, IRenderer* inRenderer) +GUI::GUI(Window* window, IRenderer* inRenderer, IFramebufferLayout* framebufferLayout) : renderer(inRenderer) { ImGui::CreateContext(); @@ -188,7 +188,7 @@ GUI::GUI(Window* window, IRenderer* inRenderer) targetBlendDesc.alpha.dstFactor = BlendFactor::Zero; GraphicsPipelineStateDesc pipelineDesc; - pipelineDesc.renderTargetCount = 1; + pipelineDesc.framebufferLayout = framebufferLayout; pipelineDesc.program = program; pipelineDesc.pipelineLayout = pipelineLayout; pipelineDesc.inputLayout = inputLayout; @@ -367,7 +367,7 @@ void GUI::endFrame() renderer->setScissorRect(rect); // TODO: This should be a dynamic/transient descriptor set... - auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout); + auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout, gfx::IDescriptorSet::Flag::Transient); descriptorSet->setConstantBuffer(0, 0, constantBuffer); descriptorSet->setResource(1, 0, (gfx::IResourceView*) command->TextureId); diff --git a/tools/graphics-app-framework/gui.h b/tools/graphics-app-framework/gui.h index 3ef2b0ba5..22b4bf2f5 100644 --- a/tools/graphics-app-framework/gui.h +++ b/tools/graphics-app-framework/gui.h @@ -12,7 +12,7 @@ namespace gfx { struct GUI : Slang::RefObject { - GUI(Window* window, IRenderer* renderer); + GUI(Window* window, IRenderer* renderer, IFramebufferLayout* framebufferLayout); ~GUI(); void beginFrame(); diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 7bf7dd369..42c14a557 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -80,11 +80,10 @@ struct ShaderOutputPlan List<Item> items; }; -class RenderTestApp : public WindowListener +class RenderTestApp : public RefObject { public: - // WindowListener - virtual Result update(Window* window) SLANG_OVERRIDE; + Result update(); // At initialization time, we are going to load and compile our Slang shader // code, and then create the API objects we need for rendering. @@ -110,7 +109,7 @@ protected: IRenderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input); - + void _initializeFramebuffer(); virtual void finalizeImpl(); uint64_t m_startTicks; @@ -124,6 +123,9 @@ protected: ComPtr<IBufferResource> m_vertexBuffer; ComPtr<IShaderProgram> m_shaderProgram; ComPtr<IPipelineState> m_pipelineState; + ComPtr<IFramebufferLayout> m_framebufferLayout; + ComPtr<IFramebuffer> m_framebuffer; + ComPtr<ITextureResource> m_colorBuffer; ShaderCompilerUtil::OutputAndLayout m_compilationOutput; @@ -472,10 +474,13 @@ SlangResult LegacyRenderTestApp::initialize( { m_options = options; + m_renderer = renderer; + SLANG_RETURN_ON_FAIL(_initializeShaders(session, renderer, options.shaderType, input)); + _initializeFramebuffer(); + m_numAddedConstantBuffers = 0; - m_renderer = renderer; // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed m_constantBufferSize = 16 * sizeof(float); @@ -557,14 +562,12 @@ SlangResult LegacyRenderTestApp::initialize( desc.pipelineLayout = m_bindingState->pipelineLayout; desc.program = m_shaderProgram; desc.inputLayout = m_inputLayout; - desc.renderTargetCount = m_bindingState->m_numRenderTargets; - + desc.framebufferLayout = m_framebufferLayout; m_pipelineState = renderer->createGraphicsPipelineState(desc); } break; } } - // If success must have a pipeline state return m_pipelineState ? SLANG_OK : SLANG_FAIL; } @@ -604,6 +607,8 @@ SlangResult ShaderObjectRenderTestApp::initialize( m_renderer = renderer; + _initializeFramebuffer(); + { switch(m_options.shaderType) { @@ -649,13 +654,12 @@ SlangResult ShaderObjectRenderTestApp::initialize( GraphicsPipelineStateDesc desc; desc.program = m_shaderProgram; desc.inputLayout = inputLayout; - + desc.framebufferLayout = m_framebufferLayout; m_pipelineState = renderer->createGraphicsPipelineState(desc); } break; } } - // If success must have a pipeline state return m_pipelineState ? SLANG_OK : SLANG_FAIL; } @@ -678,6 +682,61 @@ Result RenderTestApp::_initializeShaders( return m_shaderProgram ? SLANG_OK : SLANG_FAIL; } +void RenderTestApp::_initializeFramebuffer() +{ + gfx::ITextureResource::Desc depthBufferDesc; + depthBufferDesc.setDefaults(gfx::IResource::Usage::DepthWrite); + depthBufferDesc.init2D( + gfx::IResource::Type::Texture2D, + gfx::Format::D_Float32, + gWindowWidth, + gWindowHeight, + 0); + + ComPtr<gfx::ITextureResource> depthBufferResource = m_renderer->createTextureResource( + gfx::IResource::Usage::DepthWrite, depthBufferDesc, nullptr); + + gfx::ITextureResource::Desc colorBufferDesc; + colorBufferDesc.setDefaults(gfx::IResource::Usage::RenderTarget); + colorBufferDesc.init2D( + gfx::IResource::Type::Texture2D, + gfx::Format::RGBA_Unorm_UInt8, + gWindowWidth, + gWindowHeight, + 0); + m_colorBuffer = m_renderer->createTextureResource( + gfx::IResource::Usage::RenderTarget, colorBufferDesc, nullptr); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = gfx::Format::RGBA_Unorm_UInt8; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + ComPtr<gfx::IResourceView> rtv = + m_renderer->createTextureView(m_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 = + m_renderer->createTextureView(depthBufferResource.get(), depthBufferViewDesc); + + IFramebufferLayout::AttachmentLayout colorAttachment = {gfx::Format::RGBA_Unorm_UInt8, 1}; + IFramebufferLayout::AttachmentLayout depthAttachment = {gfx::Format::D_Float32, 1}; + gfx::IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &colorAttachment; + framebufferLayoutDesc.depthStencil = &depthAttachment; + m_renderer->createFramebufferLayout(framebufferLayoutDesc, m_framebufferLayout.writeRef()); + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = dsv.get(); + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = m_framebufferLayout; + m_renderer->createFramebuffer(framebufferDesc, m_framebuffer.writeRef()); +} void LegacyRenderTestApp::setProjectionMatrix() { @@ -843,14 +902,10 @@ Result ShaderObjectRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const c Result RenderTestApp::writeScreen(const char* filename) { - size_t rowPitch, bufferSize, pixelSize; - List<uint8_t> buffer; - - SLANG_RETURN_ON_FAIL(m_renderer->captureScreenSurface(nullptr, &bufferSize, &rowPitch, &pixelSize)); - buffer.setCount(bufferSize); - SLANG_RETURN_ON_FAIL( - m_renderer->captureScreenSurface(buffer.getBuffer(), &bufferSize, &rowPitch, &pixelSize)); - + size_t rowPitch, pixelSize; + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(m_renderer->readTextureResource(m_colorBuffer, blob.writeRef(), &rowPitch, &pixelSize)); + auto bufferSize = blob->getBufferSize(); Surface surface; size_t width = rowPitch / pixelSize; size_t height = bufferSize / rowPitch; @@ -859,12 +914,14 @@ Result RenderTestApp::writeScreen(const char* filename) (int)height, gfx::Format::RGBA_Unorm_UInt8, (int)rowPitch, - buffer.getBuffer()); + (void*)blob->getBufferPointer()); return PngSerializeUtil::write(filename, surface); } -Result RenderTestApp::update(Window* window) +Result RenderTestApp::update() { + m_renderer->beginFrame(); + // Whenever we don't have Windows events to process, we render a frame. if (m_options.shaderType == Options::ShaderProgramType::Compute) { @@ -873,9 +930,16 @@ Result RenderTestApp::update(Window* window) else { static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 }; + m_renderer->setFramebuffer(m_framebuffer); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)gWindowWidth; + viewport.extentY = (float)gWindowHeight; + m_renderer->setViewportAndScissor(viewport); + m_renderer->setClearColor(kClearColor); m_renderer->clearFrame(); - renderFrame(); } @@ -947,12 +1011,10 @@ Result RenderTestApp::update(Window* window) } } } - // We are done - window->postQuit(); return SLANG_OK; } - m_renderer->presentFrame(); + m_renderer->endFrame(); return SLANG_OK; } @@ -999,9 +1061,6 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi // Parse command-line options SLANG_RETURN_ON_FAIL(Options::parse(argcIn, argvIn, StdWriters::getError(), options)); - // Declare window pointer before renderer, such that window is released after renderer - RefPtr<renderer_test::Window> window; - ShaderCompilerUtil::Input input; input.profile = ""; @@ -1281,8 +1340,6 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi { IRenderer::Desc desc = {}; desc.rendererType = options.rendererType; - desc.width = gWindowWidth; - desc.height = gWindowHeight; desc.adapter = options.adapter.getBuffer(); List<const char*> requiredFeatureList; @@ -1294,16 +1351,9 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi desc.nvapiExtnSlot = int(nvapiExtnSlot); desc.slang.slangGlobalSession = session; - window = renderer_test::Window::create(); - void* windowHandle = nullptr; - if (window) - { - SLANG_RETURN_ON_FAIL(window->initialize(gWindowWidth, gWindowHeight)); - windowHandle = window->getHandle(); - } { - SlangResult res = gfxCreateRenderer(&desc, windowHandle, renderer.writeRef()); + SlangResult res = gfxCreateRenderer(&desc, renderer.writeRef()); if (SLANG_FAILED(res)) { // We need to be careful here about SLANG_E_NOT_AVAILABLE. This return value means that the renderer couldn't @@ -1351,8 +1401,7 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi else app = new LegacyRenderTestApp(); SLANG_RETURN_ON_FAIL(app->initialize(session, renderer, options, input)); - window->show(); - SLANG_RETURN_ON_FAIL(window->runLoop(app)); + app->update(); app->finalize(); return SLANG_OK; } diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp index ad3812ae3..5b3867848 100644 --- a/tools/render-test/shader-renderer-util.cpp +++ b/tools/render-test/shader-renderer-util.cpp @@ -283,7 +283,7 @@ ComPtr<ISamplerState> _createSamplerState(IRenderer* renderer, auto pipelineLayout = renderer->createPipelineLayout(pipelineLayoutDesc); if(!pipelineLayout) return SLANG_FAIL; - auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout); + auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout, IDescriptorSet::Flag::Transient); if(!descriptorSet) return SLANG_FAIL; List<BindingStateImpl::OutputBinding> outputBindings; diff --git a/tools/slang-test/test-reporter.cpp b/tools/slang-test/test-reporter.cpp index fd9748b28..4a7c76c4c 100644 --- a/tools/slang-test/test-reporter.cpp +++ b/tools/slang-test/test-reporter.cpp @@ -314,28 +314,38 @@ void TestReporter::_addResult(const TestInfo& info) m_testInfos.add(info); - // printf("OUTPUT_MODE: %d\n", options.outputMode); - switch (m_outputMode) + auto defaultOutputFunc = [](const TestInfo& info) { + char const* resultString = "UNEXPECTED"; + switch (info.testResult) + { + case TestResult::Fail: + resultString = "FAILED"; + break; + case TestResult::Pass: + resultString = "passed"; + break; + case TestResult::Ignored: + resultString = "ignored"; + break; default: + assert(!"unexpected"); + break; + } + + StringBuilder buffer; + if (info.executionTime > 0.0f) { - char const* resultString = "UNEXPECTED"; - switch (info.testResult) - { - case TestResult::Fail: resultString = "FAILED"; break; - case TestResult::Pass: resultString = "passed"; break; - case TestResult::Ignored: resultString = "ignored"; break; - default: - assert(!"unexpected"); - break; - } + _appendTime(info.executionTime, buffer); + } + printf("%s test: '%S' %s\n", resultString, info.name.toWString().begin(), buffer.getBuffer()); + }; - StringBuilder buffer; - if (info.executionTime > 0.0f) - { - _appendTime(info.executionTime, buffer); - } - printf("%s test: '%S' %s\n", resultString, info.name.toWString().begin(), buffer.getBuffer()); + switch (m_outputMode) + { + default: + { + defaultOutputFunc(info); break; } case TestOutputMode::TeamCity: @@ -464,7 +474,7 @@ void TestReporter::_addResult(const TestInfo& info) exeRes.standardError.begin()); #endif } - + defaultOutputFunc(info); break; } } |
