diff --git a/include/vsg/app/WindowResizeHandler.h b/include/vsg/app/WindowResizeHandler.h index fe99165c21..236245dcc7 100644 --- a/include/vsg/app/WindowResizeHandler.h +++ b/include/vsg/app/WindowResizeHandler.h @@ -23,6 +23,7 @@ namespace vsg /// Utility class for updating a scene graph when a View's camera ViewportState has been updated so that associated GraphicsPipelines in the /// scene graph can be recompiled and correctly reflect the new ViewportState. + /// As viewport size and scissor is dynamic by default, this is only necessary when opting out of that or when the viewport count has changed. class VSG_DECLSPEC UpdateGraphicsPipelines : public Inherit { public: @@ -43,7 +44,6 @@ namespace vsg class VSG_DECLSPEC WindowResizeHandler : public Inherit { public: - ref_ptr context; VkRect2D renderArea; VkExtent2D previous_extent; VkExtent2D new_extent; @@ -63,7 +63,6 @@ namespace vsg /// return true if the object was visited bool visit(const Object* object, uint32_t index = 0); - void apply(BindGraphicsPipeline& bindPipeline) override; void apply(Object& object) override; void apply(ClearAttachments& clearAttachments) override; void apply(View& view) override; diff --git a/include/vsg/state/DynamicState.h b/include/vsg/state/DynamicState.h index 06397f2250..420025129b 100644 --- a/include/vsg/state/DynamicState.h +++ b/include/vsg/state/DynamicState.h @@ -18,6 +18,7 @@ namespace vsg { /// DynamicState encapsulates VkPipelineDynamicStateCreateInfo settings passed when setting up GraphicsPipeline + /// By default, viewport and scissor are set to dynamic class VSG_DECLSPEC DynamicState : public Inherit { public: diff --git a/include/vsg/vk/State.h b/include/vsg/vk/State.h index 49b7549a6f..e52da8e3a0 100644 --- a/include/vsg/vk/State.h +++ b/include/vsg/vk/State.h @@ -255,6 +255,9 @@ namespace vsg MatrixStack projectionMatrixStack{0}; MatrixStack modelviewMatrixStack{64}; + StateStack scissorStack{}; + StateStack viewportStack{}; + void setInhertiedViewProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix) { inheritedProjectionMatrix = projMatrix; @@ -292,6 +295,9 @@ namespace vsg stateStack.record(*_commandBuffer); } + scissorStack.record(*_commandBuffer); + viewportStack.record(*_commandBuffer); + projectionMatrixStack.record(*_commandBuffer); modelviewMatrixStack.record(*_commandBuffer); diff --git a/src/vsg/app/CommandGraph.cpp b/src/vsg/app/CommandGraph.cpp index e8ac3d4991..a7ea02f3ff 100644 --- a/src/vsg/app/CommandGraph.cpp +++ b/src/vsg/app/CommandGraph.cpp @@ -13,6 +13,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include +#include #include #include #include @@ -120,6 +122,13 @@ void CommandGraph::record(ref_ptr recordedCommandBuffers recordTraversal->getState()->_commandBuffer = commandBuffer; + if (framebuffer || window) + { + const VkExtent2D& extent = framebuffer ? framebuffer->extent2D() : window->extent2D(); + recordTraversal->getState()->scissorStack.push(SetScissor::create(0, Scissors{{{0, 0}, extent}})); + recordTraversal->getState()->viewportStack.push(SetViewport::create(0, Viewports{{0.0f, 0.0f, static_cast(extent.width), static_cast(extent.height), 0.0f, 1.0f}})); + } + // or select index when maps to a dormant CommandBuffer VkCommandBuffer vk_commandBuffer = *commandBuffer; @@ -139,6 +148,12 @@ void CommandGraph::record(ref_ptr recordedCommandBuffers vkEndCommandBuffer(vk_commandBuffer); + if (framebuffer || window) + { + recordTraversal->getState()->scissorStack.pop(); + recordTraversal->getState()->viewportStack.pop(); + } + recordedCommandBuffers->add(submitOrder, commandBuffer); } diff --git a/src/vsg/app/RecordTraversal.cpp b/src/vsg/app/RecordTraversal.cpp index ed47544ad9..8b75fd91db 100644 --- a/src/vsg/app/RecordTraversal.cpp +++ b/src/vsg/app/RecordTraversal.cpp @@ -16,6 +16,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include +#include #include #include #include @@ -575,27 +577,39 @@ void RecordTraversal::apply(const View& view) _state->inheritViewForLODScaling = (view.features & INHERIT_VIEWPOINT) != 0; _state->setProjectionAndViewMatrix(view.camera->projectionMatrix->transform(), view.camera->viewMatrix->transform()); - if (_viewDependentState && _viewDependentState->viewportData && view.camera->viewportState) + if (_viewDependentState && view.camera->viewportState) { auto& viewportData = _viewDependentState->viewportData; auto& viewports = view.camera->viewportState->viewports; - auto dest_itr = viewportData->begin(); - for (auto src_itr = viewports.begin(); - dest_itr != viewportData->end() && src_itr != viewports.end(); - ++dest_itr, ++src_itr) + _state->scissorStack.push(vsg::SetScissor::create(0, view.camera->viewportState->scissors)); + _state->viewportStack.push(vsg::SetViewport::create(0, viewports)); + + if (viewportData) { - auto& dest_viewport = *dest_itr; - vec4 src_viewport(src_itr->x, src_itr->y, src_itr->width, src_itr->height); - if (dest_viewport != src_viewport) + auto dest_itr = viewportData->begin(); + for (auto src_itr = viewports.begin(); + dest_itr != viewportData->end() && src_itr != viewports.end(); + ++dest_itr, ++src_itr) { - dest_viewport = src_viewport; - viewportData->dirty(); + auto& dest_viewport = *dest_itr; + vec4 src_viewport(src_itr->x, src_itr->y, src_itr->width, src_itr->height); + if (dest_viewport != src_viewport) + { + dest_viewport = src_viewport; + viewportData->dirty(); + } } } } view.traverse(*this); + + if (_viewDependentState && view.camera->viewportState) + { + _state->scissorStack.pop(); + _state->viewportStack.pop(); + } } else { diff --git a/src/vsg/app/RenderGraph.cpp b/src/vsg/app/RenderGraph.cpp index 6fbdcec0cc..c962e67213 100644 --- a/src/vsg/app/RenderGraph.cpp +++ b/src/vsg/app/RenderGraph.cpp @@ -12,6 +12,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include +#include #include #include #include @@ -141,6 +143,12 @@ void RenderGraph::accept(RecordTraversal& recordTraversal) const renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); + if (extent.width != invalid_dimension && extent.height != invalid_dimension) + { + recordTraversal.getState()->scissorStack.push(SetScissor::create(0, Scissors{{{0, 0}, extent}})); + recordTraversal.getState()->viewportStack.push(SetViewport::create(0, Viewports{{0.0f, 0.0f, static_cast(extent.width), static_cast(extent.height), 0.0f, 1.0f}})); + } + VkCommandBuffer vk_commandBuffer = *(recordTraversal.getState()->_commandBuffer); vkCmdBeginRenderPass(vk_commandBuffer, &renderPassInfo, contents); @@ -148,6 +156,12 @@ void RenderGraph::accept(RecordTraversal& recordTraversal) const traverse(recordTraversal); vkCmdEndRenderPass(vk_commandBuffer); + + if (extent.width != invalid_dimension && extent.height != invalid_dimension) + { + recordTraversal.getState()->scissorStack.pop(); + recordTraversal.getState()->viewportStack.pop(); + } } void RenderGraph::resized() @@ -158,27 +172,13 @@ void RenderGraph::resized() auto activeRenderPass = getRenderPass(); if (!activeRenderPass) return; - auto device = activeRenderPass->device; - - if (!windowResizeHandler->context) windowResizeHandler->context = vsg::Context::create(device); - auto extent = getExtent(); - windowResizeHandler->context->commandPool = nullptr; - windowResizeHandler->context->renderPass = activeRenderPass; windowResizeHandler->renderArea = renderArea; windowResizeHandler->previous_extent = previous_extent; windowResizeHandler->new_extent = extent; windowResizeHandler->visited.clear(); - if (activeRenderPass->maxSamples != VK_SAMPLE_COUNT_1_BIT) - { - windowResizeHandler->context->overridePipelineStates.emplace_back(vsg::MultisampleState::create(activeRenderPass->maxSamples)); - } - - // make sure the device is idle before we recreate any Vulkan objects - vkDeviceWaitIdle(*(device)); - traverse(*windowResizeHandler); windowResizeHandler->scale_rect(renderArea); diff --git a/src/vsg/app/SecondaryCommandGraph.cpp b/src/vsg/app/SecondaryCommandGraph.cpp index 3d24d72b6f..620b04b828 100644 --- a/src/vsg/app/SecondaryCommandGraph.cpp +++ b/src/vsg/app/SecondaryCommandGraph.cpp @@ -14,6 +14,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include +#include #include #include #include @@ -155,12 +157,25 @@ void SecondaryCommandGraph::record(ref_ptr recordedComma inheritanceInfo.framebuffer = VK_NULL_HANDLE; } + if (framebuffer || window) + { + const VkExtent2D& extent = framebuffer ? framebuffer->extent2D() : window->extent2D(); + recordTraversal->getState()->scissorStack.push(SetScissor::create(0, Scissors{{{0, 0}, extent}})); + recordTraversal->getState()->viewportStack.push(SetViewport::create(0, Viewports{{0.0f, 0.0f, static_cast(extent.width), static_cast(extent.height), 0.0f, 1.0f}})); + } + vkBeginCommandBuffer(vk_commandBuffer, &beginInfo); traverse(*recordTraversal); vkEndCommandBuffer(vk_commandBuffer); + if (framebuffer || window) + { + recordTraversal->getState()->scissorStack.pop(); + recordTraversal->getState()->viewportStack.pop(); + } + // pass on this command buffer to connected ExecuteCommands nodes for (auto& ec : _executeCommands) { diff --git a/src/vsg/app/WindowResizeHandler.cpp b/src/vsg/app/WindowResizeHandler.cpp index da831f4a1d..a7ed833786 100644 --- a/src/vsg/app/WindowResizeHandler.cpp +++ b/src/vsg/app/WindowResizeHandler.cpp @@ -89,40 +89,6 @@ bool WindowResizeHandler::visit(const Object* object, uint32_t index) return true; } -void WindowResizeHandler::apply(vsg::BindGraphicsPipeline& bindPipeline) -{ - GraphicsPipeline* graphicsPipeline = bindPipeline.pipeline; - - if (!visit(graphicsPipeline, context->viewID)) - { - return; - } - - if (graphicsPipeline) - { - struct ContainsViewport : public ConstVisitor - { - bool foundViewport = false; - void apply(const ViewportState&) override { foundViewport = true; } - bool operator()(const GraphicsPipeline& gp) - { - for (auto& pipelineState : gp.pipelineStates) - { - pipelineState->accept(*this); - } - return foundViewport; - } - } containsViewport; - - bool needToRegenerateGraphicsPipeline = !containsViewport(*graphicsPipeline); - if (needToRegenerateGraphicsPipeline) - { - graphicsPipeline->release(context->viewID); - graphicsPipeline->compile(*context); - } - } -} - void WindowResizeHandler::apply(vsg::Object& object) { object.traverse(*this); @@ -143,8 +109,6 @@ void WindowResizeHandler::apply(vsg::View& view) { if (!visit(&view)) return; - context->viewID = view.viewID; - if (!view.camera) { view.traverse(*this); @@ -177,9 +141,5 @@ void WindowResizeHandler::apply(vsg::View& view) } } - context->defaultPipelineStates.emplace_back(viewportState); - view.traverse(*this); - - context->defaultPipelineStates.pop_back(); } diff --git a/src/vsg/state/DynamicState.cpp b/src/vsg/state/DynamicState.cpp index 475c87907f..3932258934 100644 --- a/src/vsg/state/DynamicState.cpp +++ b/src/vsg/state/DynamicState.cpp @@ -16,7 +16,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace vsg; -DynamicState::DynamicState() +DynamicState::DynamicState() : + dynamicStates({VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}) { } diff --git a/src/vsg/vk/Context.cpp b/src/vsg/vk/Context.cpp index 2b42ffe29b..68c3c078d2 100644 --- a/src/vsg/vk/Context.cpp +++ b/src/vsg/vk/Context.cpp @@ -22,6 +22,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include #include @@ -129,6 +130,8 @@ Context::Context(Device* in_device, const ResourceRequirements& in_resourceRequi { vsg::debug("Context::Context() reusing descriptorPools = ", descriptorPools); } + + defaultPipelineStates.push_back(DynamicState::create()); } Context::Context(const Context& context) :