Skip to content

Commit 70ce4e5

Browse files
committed
GPU Vulkan Display: Make viewport / scissor dynamic, images are by default read/writeable to allow FSAA and screenshots without swapchain recreation
1 parent 0ad7e39 commit 70ce4e5

2 files changed

Lines changed: 37 additions & 53 deletions

File tree

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx‎

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ static void cmdImageMemoryBarrier(vk::CommandBuffer cmdbuffer, vk::Image image,
142142
static void cmdBeginRendering(vk::CommandBuffer cmdbuffer, uint32_t width, uint32_t height, const vk::RenderingAttachmentInfo& color, const vk::RenderingAttachmentInfo* depth = nullptr)
143143
{
144144
cmdbuffer.beginRendering(vk::RenderingInfo{{}, vk::Rect2D{{0, 0}, {width, height}}, 1, 0, 1, &color, depth});
145+
vk::Viewport viewport{0.f, 0.f, (float)width, (float)height, 0.f, 1.f};
146+
vk::Rect2D scissor{{0, 0}, {width, height}};
147+
cmdbuffer.setViewport(0, 1, &viewport);
148+
cmdbuffer.setScissor(0, 1, &scissor);
145149
}
146150

147151
static void cmdBeginRenderingLoad(vk::CommandBuffer cmdbuffer, vk::Image image, vk::ImageView view, uint32_t width, uint32_t height) // Render on top of the content of a color attachment written by a previous pass
@@ -713,12 +717,8 @@ void GPUDisplayBackendVulkan::clearTextureSampler()
713717

714718
// ---------------------------- VULKAN SWAPCHAIN MANAGEMENT ----------------------------
715719

716-
void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing, vk::SwapchainKHR oldSwapChain)
720+
void GPUDisplayBackendVulkan::createSwapChain(vk::SwapchainKHR oldSwapChain)
717721
{
718-
mDownsampleFactor = getDownsampleFactor(forScreenshot);
719-
mDownsampleFSAA = mDownsampleFactor != 1;
720-
mSwapchainImageReadable = forScreenshot;
721-
722722
updateSwapChainDetails(mPhysicalDevice);
723723
mSurfaceFormat = chooseSwapSurfaceFormat(mSwapChainDetails.formats);
724724
mPresentMode = chooseSwapPresentMode(mSwapChainDetails.presentModes, mDisplay->cfgR().drawQualityVSync ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eImmediate);
@@ -731,8 +731,6 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing
731731

732732
mScreenWidth = extent.width;
733733
mScreenHeight = extent.height;
734-
mRenderWidth = mScreenWidth * mDownsampleFactor;
735-
mRenderHeight = mScreenHeight * mDownsampleFactor;
736734

737735
vk::SwapchainCreateInfoKHR swapCreateInfo{};
738736
swapCreateInfo.surface = mSurface;
@@ -741,7 +739,7 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing
741739
swapCreateInfo.imageColorSpace = mSurfaceFormat.colorSpace;
742740
swapCreateInfo.imageExtent = extent;
743741
swapCreateInfo.imageArrayLayers = 1;
744-
swapCreateInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
742+
swapCreateInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; // Transfer for screenshots / FSAA downsampling, so that they need no swapchain recreation
745743
swapCreateInfo.imageSharingMode = vk::SharingMode::eExclusive;
746744
swapCreateInfo.queueFamilyIndexCount = 0; // Optional
747745
swapCreateInfo.pQueueFamilyIndices = nullptr; // Optional
@@ -750,12 +748,6 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing
750748
swapCreateInfo.presentMode = mPresentMode;
751749
swapCreateInfo.clipped = true;
752750
swapCreateInfo.oldSwapchain = oldSwapChain;
753-
if (mSwapchainImageReadable) {
754-
swapCreateInfo.imageUsage |= vk::ImageUsageFlagBits::eTransferSrc;
755-
}
756-
if (mDownsampleFSAA) {
757-
swapCreateInfo.imageUsage |= vk::ImageUsageFlagBits::eTransferDst;
758-
}
759751
mSwapChain = mDevice.createSwapchainKHR(swapCreateInfo, nullptr);
760752
if (oldSwapChain) {
761753
mDevice.destroySwapchainKHR(oldSwapChain, nullptr);
@@ -801,20 +793,26 @@ void GPUDisplayBackendVulkan::clearSwapChain(bool keepSwapChain)
801793

802794
void GPUDisplayBackendVulkan::recreateRendering(bool forScreenshot, bool forMixing)
803795
{
796+
needRecordCommandBuffers();
797+
const bool needUpdateSwapChain = mMustUpdateSwapChain;
798+
const bool needUpdateOffscreenBuffers = needUpdateSwapChain || mDownsampleFactor != getDownsampleFactor(forScreenshot) || mMSAASampleCount != getMSAASamplesFlag(std::min<uint32_t>(mMaxMSAAsupported, mDisplay->cfgR().drawQualityMSAA)) || mZActive != (mZSupported && mDisplay->cfgL().depthBuffer) || mMixingSupported != forMixing;
799+
if (!needUpdateOffscreenBuffers) {
800+
return;
801+
}
804802
mDevice.waitIdle();
805-
bool needUpdateSwapChain = mMustUpdateSwapChain || mDownsampleFactor != getDownsampleFactor(forScreenshot) || mSwapchainImageReadable != forScreenshot;
806-
bool needUpdateOffscreenBuffers = needUpdateSwapChain || mMSAASampleCount != getMSAASamplesFlag(std::min<uint32_t>(mMaxMSAAsupported, mDisplay->cfgR().drawQualityMSAA)) || mZActive != (mZSupported && mDisplay->cfgL().depthBuffer) || mMixingSupported != forMixing;
807-
clearPipeline();
808-
if (needUpdateOffscreenBuffers) {
809-
clearOffscreenBuffers();
810-
if (needUpdateSwapChain) {
811-
clearSwapChain(true);
812-
createSwapChain(forScreenshot, forMixing, mSwapChain);
813-
}
814-
createOffscreenBuffers(forScreenshot, forMixing);
803+
const vk::Format oldFormat = mSurfaceFormat.format;
804+
const vk::SampleCountFlagBits oldMSAASampleCount = mMSAASampleCount;
805+
const bool oldZActive = mZActive;
806+
clearOffscreenBuffers();
807+
if (needUpdateSwapChain) {
808+
clearSwapChain(true);
809+
createSwapChain(mSwapChain);
810+
}
811+
createOffscreenBuffers(forScreenshot, forMixing);
812+
if (mSurfaceFormat.format != oldFormat || mMSAASampleCount != oldMSAASampleCount || mZActive != oldZActive) { // Viewport / scissor are dynamic
813+
clearPipeline();
814+
createPipeline();
815815
}
816-
createPipeline();
817-
needRecordCommandBuffers();
818816
mUpdateUBOtextMatrix = mUpdateUBOmixMatrix = -1; // Screen / render size may have changed
819817
}
820818

@@ -825,6 +823,10 @@ void GPUDisplayBackendVulkan::createOffscreenBuffers(bool forScreenshot, bool fo
825823
mMSAASampleCount = getMSAASamplesFlag(std::min<uint32_t>(mMaxMSAAsupported, mDisplay->cfgR().drawQualityMSAA));
826824
mZActive = mZSupported && mDisplay->cfgL().depthBuffer;
827825
mMixingSupported = forMixing;
826+
mDownsampleFactor = getDownsampleFactor(forScreenshot);
827+
mDownsampleFSAA = mDownsampleFactor != 1;
828+
mRenderWidth = mScreenWidth * mDownsampleFactor;
829+
mRenderHeight = mScreenHeight * mDownsampleFactor;
828830

829831
const uint32_t imageCountWithMixImages = mImageCount * (mMixingSupported ? 2 : 1);
830832
mRenderTargetView.resize(imageCountWithMixImages);
@@ -929,23 +931,9 @@ void GPUDisplayBackendVulkan::createPipeline()
929931
// inputAssembly.topology // below
930932
inputAssembly.primitiveRestartEnable = false;
931933

932-
vk::Viewport viewport{};
933-
viewport.x = 0.0f;
934-
viewport.y = 0.0f;
935-
// viewport.width // below
936-
// viewport.height // below
937-
viewport.minDepth = 0.0f;
938-
viewport.maxDepth = 1.0f;
939-
940-
vk::Rect2D scissor{};
941-
scissor.offset = vk::Offset2D{0, 0};
942-
// scissor.extent // below
943-
944-
vk::PipelineViewportStateCreateInfo viewportState{};
934+
vk::PipelineViewportStateCreateInfo viewportState{}; // Viewport and scissor are dynamic
945935
viewportState.viewportCount = 1;
946-
viewportState.pViewports = &viewport;
947936
viewportState.scissorCount = 1;
948-
viewportState.pScissors = &scissor;
949937

950938
vk::PipelineRasterizationStateCreateInfo rasterizer{};
951939
rasterizer.depthClampEnable = false;
@@ -995,9 +983,9 @@ void GPUDisplayBackendVulkan::createPipeline()
995983
depthStencil.depthBoundsTestEnable = false;
996984
depthStencil.stencilTestEnable = false;
997985

998-
vk::DynamicState dynamicStates[] = {vk::DynamicState::eLineWidth};
986+
vk::DynamicState dynamicStates[] = {vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eLineWidth};
999987
vk::PipelineDynamicStateCreateInfo dynamicState{};
1000-
dynamicState.dynamicStateCount = 1;
988+
// dynamicState.dynamicStateCount // below: viewport + scissor for text / texture, + line width for the main pipelines
1001989
dynamicState.pDynamicStates = dynamicStates;
1002990

1003991
vk::PushConstantRange pushConstantRanges[2] = {vk::PushConstantRange{}, vk::PushConstantRange{}};
@@ -1034,7 +1022,7 @@ void GPUDisplayBackendVulkan::createPipeline()
10341022
pipelineInfo.basePipelineHandle = VkPipeline(VK_NULL_HANDLE); // Optional
10351023
pipelineInfo.basePipelineIndex = -1; // Optional
10361024

1037-
mPipelines.resize(mMixingSupported ? 5 : 4);
1025+
mPipelines.resize(5);
10381026
static constexpr vk::PrimitiveTopology types[3] = {vk::PrimitiveTopology::ePointList, vk::PrimitiveTopology::eLineList, vk::PrimitiveTopology::eLineStrip};
10391027
for (uint32_t i = 0; i < mPipelines.size(); i++) {
10401028
if (i == 4) { // Texture rendering
@@ -1043,26 +1031,24 @@ void GPUDisplayBackendVulkan::createPipeline()
10431031
inputAssembly.topology = vk::PrimitiveTopology::eTriangleList;
10441032
vertShaderStageInfo.module = mShaders["vertexTexture"];
10451033
fragShaderStageInfo.module = mShaders["fragmentTexture"];
1034+
dynamicState.dynamicStateCount = 2;
10461035
pipelineInfo.layout = mPipelineLayoutTexture;
10471036
renderingInfo.depthAttachmentFormat = vk::Format::eUndefined;
10481037
pipelineInfo.pDepthStencilState = nullptr;
10491038
colorBlendAttachment.blendEnable = true;
10501039
multisampling.rasterizationSamples = vk::SampleCountFlagBits::e1;
1051-
viewport.width = scissor.extent.width = mRenderWidth;
1052-
viewport.height = scissor.extent.height = mRenderHeight;
10531040
} else if (i == 3) { // Text rendering
10541041
bindingDescription.stride = 4 * sizeof(float);
10551042
attributeDescriptions.format = vk::Format::eR32G32B32A32Sfloat;
10561043
inputAssembly.topology = vk::PrimitiveTopology::eTriangleList;
10571044
vertShaderStageInfo.module = mShaders["vertexTexture"];
10581045
fragShaderStageInfo.module = mShaders["fragmentText"];
1046+
dynamicState.dynamicStateCount = 2;
10591047
pipelineInfo.layout = mPipelineLayoutTexture;
10601048
renderingInfo.depthAttachmentFormat = vk::Format::eUndefined;
10611049
pipelineInfo.pDepthStencilState = nullptr;
10621050
colorBlendAttachment.blendEnable = true;
10631051
multisampling.rasterizationSamples = vk::SampleCountFlagBits::e1;
1064-
viewport.width = scissor.extent.width = mScreenWidth;
1065-
viewport.height = scissor.extent.height = mScreenHeight;
10661052
} else { // Point / line / line-strip rendering
10671053
bindingDescription.stride = 3 * sizeof(float);
10681054
attributeDescriptions.format = vk::Format::eR32G32B32Sfloat;
@@ -1072,10 +1058,9 @@ void GPUDisplayBackendVulkan::createPipeline()
10721058
pipelineInfo.layout = mPipelineLayout;
10731059
renderingInfo.depthAttachmentFormat = mZActive ? vk::Format::eD32Sfloat : vk::Format::eUndefined;
10741060
pipelineInfo.pDepthStencilState = mZActive ? &depthStencil : nullptr;
1061+
dynamicState.dynamicStateCount = 3;
10751062
colorBlendAttachment.blendEnable = true;
10761063
multisampling.rasterizationSamples = mMSAASampleCount;
1077-
viewport.width = scissor.extent.width = mRenderWidth;
1078-
viewport.height = scissor.extent.height = mRenderHeight;
10791064
}
10801065

10811066
CHKERR(mDevice.createGraphicsPipelines(VkPipelineCache(VK_NULL_HANDLE), 1, &pipelineInfo, nullptr, &mPipelines[i])); // TODO: multiple at once + cache?
@@ -1389,7 +1374,7 @@ void GPUDisplayBackendVulkan::prepareDraw(const hmm_mat4& proj, const hmm_mat4&
13891374
};
13901375

13911376
vk::Result retVal = vk::Result::eSuccess;
1392-
bool mustUpdateSwapChain = mMustUpdateSwapChain || mDisplay->updateRenderPipeline() || (requestScreenshot && !mSwapchainImageReadable) || (toMixBuffer && !mMixingSupported) || mDownsampleFactor != getDownsampleFactor(requestScreenshot);
1377+
bool mustUpdateSwapChain = mMustUpdateSwapChain || mDisplay->updateRenderPipeline() || (toMixBuffer && !mMixingSupported) || mDownsampleFactor != getDownsampleFactor(requestScreenshot);
13931378
if (!mustUpdateSwapChain) {
13941379
retVal = getImage();
13951380
if (retVal == vk::Result::eErrorOutOfDateKHR) {

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend
114114
void createCommandBuffers();
115115
void createSemaphores();
116116
void createUniformLayoutsAndBuffers();
117-
void createSwapChain(bool forScreenshot = false, bool forMixing = false, vk::SwapchainKHR oldSwapChain = {});
117+
void createSwapChain(vk::SwapchainKHR oldSwapChain = {});
118118
void createOffscreenBuffers(bool forScreenshot = false, bool forMixing = false);
119119
void createPipeline();
120120
void clearDevice();
@@ -204,7 +204,6 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend
204204
vecpod<float> mFontVertexBufferHost;
205205
bool mHasDrawnText = false;
206206

207-
bool mSwapchainImageReadable = false;
208207
vk::SampleCountFlagBits mMSAASampleCount = vk::SampleCountFlagBits::e16;
209208
uint32_t mMaxMSAAsupported = 0;
210209
bool mZActive = false;

0 commit comments

Comments
 (0)