@@ -639,16 +639,14 @@ void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers()
639639{
640640 for (int32_t j = 0 ; j < 3 ; j++) {
641641 mUniformBuffersMat [j].resize (mImageCount );
642- mUniformBuffersCol [j].resize (mImageCount );
643642 for (uint32_t i = 0 ; i < mImageCount ; i++) {
644643 mUniformBuffersMat [j][i] = createBuffer (sizeof (hmm_mat4), nullptr , vk::BufferUsageFlagBits::eUniformBuffer, mDisplay ->cfg ().vulkan .uniformBuffersInDeviceMemory ? 2 : 0 );
645- mUniformBuffersCol [j][i] = createBuffer (sizeof (float ) * 4 , nullptr , vk::BufferUsageFlagBits::eUniformBuffer, mDisplay ->cfg ().vulkan .uniformBuffersInDeviceMemory ? 2 : 0 );
646644 }
647645 }
648646
649647 std::array<vk::DescriptorPoolSize, 2 > poolSizes{};
650648 poolSizes[0 ].type = vk::DescriptorType::eUniformBuffer;
651- poolSizes[0 ].descriptorCount = (uint32_t )mImageCount * ( 2 * 3 ) ;
649+ poolSizes[0 ].descriptorCount = (uint32_t )mImageCount * 3 ;
652650 poolSizes[1 ].type = vk::DescriptorType::eCombinedImageSampler;
653651 poolSizes[1 ].descriptorCount = (uint32_t )mImageCount * 2 ;
654652 vk::DescriptorPoolCreateInfo poolInfo{};
@@ -662,21 +660,18 @@ void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers()
662660 uboLayoutBindingMat.descriptorType = vk::DescriptorType::eUniformBuffer;
663661 uboLayoutBindingMat.descriptorCount = 1 ;
664662 uboLayoutBindingMat.stageFlags = vk::ShaderStageFlagBits::eVertex;
665- vk::DescriptorSetLayoutBinding uboLayoutBindingCol = uboLayoutBindingMat;
666- uboLayoutBindingCol.binding = 1 ;
667- uboLayoutBindingCol.stageFlags = vk::ShaderStageFlagBits::eFragment;
668663 vk::DescriptorSetLayoutBinding samplerLayoutBinding{};
669664 samplerLayoutBinding.binding = 2 ;
670665 samplerLayoutBinding.descriptorCount = 1 ;
671666 samplerLayoutBinding.descriptorType = vk::DescriptorType::eCombinedImageSampler;
672667 samplerLayoutBinding.stageFlags = vk::ShaderStageFlagBits::eFragment;
673- vk::DescriptorSetLayoutBinding bindings[3 ] = {uboLayoutBindingMat, uboLayoutBindingCol , samplerLayoutBinding};
668+ vk::DescriptorSetLayoutBinding bindings[2 ] = {uboLayoutBindingMat, samplerLayoutBinding};
674669
675670 vk::DescriptorSetLayoutCreateInfo layoutInfo{};
676- layoutInfo.bindingCount = 2 ;
671+ layoutInfo.bindingCount = 1 ;
677672 layoutInfo.pBindings = bindings;
678673 mUniformDescriptor = mDevice .createDescriptorSetLayout (layoutInfo, nullptr );
679- layoutInfo.bindingCount = 3 ;
674+ layoutInfo.bindingCount = 2 ;
680675 mUniformDescriptorTexture = mDevice .createDescriptorSetLayout (layoutInfo, nullptr );
681676
682677 vk::DescriptorSetAllocateInfo allocInfo{};
@@ -687,27 +682,25 @@ void GPUDisplayBackendVulkan::createUniformLayoutsAndBuffers()
687682 allocInfo.pSetLayouts = layouts.data ();
688683 mDescriptorSets [j] = mDevice .allocateDescriptorSets (allocInfo);
689684
690- for (int32_t k = 0 ; k < 2 ; k++) {
691- auto & mUniformBuffers = k ? mUniformBuffersCol [j] : mUniformBuffersMat [j];
692- for (uint32_t i = 0 ; i < mImageCount ; i++) {
693- vk::DescriptorBufferInfo bufferInfo{};
694- bufferInfo.buffer = mUniformBuffers [i].buffer ;
695- bufferInfo.offset = 0 ;
696- bufferInfo.range = mUniformBuffers [i].size ;
697-
698- vk::WriteDescriptorSet descriptorWrite{};
699- descriptorWrite.dstSet = mDescriptorSets [j][i];
700- descriptorWrite.dstBinding = k;
701- descriptorWrite.dstArrayElement = 0 ;
702- descriptorWrite.descriptorType = vk::DescriptorType::eUniformBuffer;
703- descriptorWrite.descriptorCount = 1 ;
704- descriptorWrite.pBufferInfo = &bufferInfo;
705- descriptorWrite.pImageInfo = nullptr ;
706- descriptorWrite.pTexelBufferView = nullptr ;
707- mDevice .updateDescriptorSets (1 , &descriptorWrite, 0 , nullptr );
708- }
685+ for (uint32_t i = 0 ; i < mImageCount ; i++) {
686+ vk::DescriptorBufferInfo bufferInfo{};
687+ bufferInfo.buffer = mUniformBuffersMat [j][i].buffer ;
688+ bufferInfo.offset = 0 ;
689+ bufferInfo.range = mUniformBuffersMat [j][i].size ;
690+
691+ vk::WriteDescriptorSet descriptorWrite{};
692+ descriptorWrite.dstSet = mDescriptorSets [j][i];
693+ descriptorWrite.dstBinding = 0 ;
694+ descriptorWrite.dstArrayElement = 0 ;
695+ descriptorWrite.descriptorType = vk::DescriptorType::eUniformBuffer;
696+ descriptorWrite.descriptorCount = 1 ;
697+ descriptorWrite.pBufferInfo = &bufferInfo;
698+ descriptorWrite.pImageInfo = nullptr ;
699+ descriptorWrite.pTexelBufferView = nullptr ;
700+ mDevice .updateDescriptorSets (1 , &descriptorWrite, 0 , nullptr );
709701 }
710702 }
703+ mUpdateUBOdrawMatrix = mUpdateUBOtextMatrix = mUpdateUBOmixMatrix = -1 ;
711704
712705 if (mFontImage .sizex && mFontImage .sizey ) {
713706 updateFontTextureDescriptor ();
@@ -721,7 +714,6 @@ void GPUDisplayBackendVulkan::clearUniformLayoutsAndBuffers()
721714 mDevice .destroyDescriptorPool (mDescriptorPool , nullptr );
722715 for (int32_t j = 0 ; j < 3 ; j++) {
723716 clearVector (mUniformBuffersMat [j], [&](auto & x) { clearBuffer (x); });
724- clearVector (mUniformBuffersCol [j], [&](auto & x) { clearBuffer (x); });
725717 }
726718}
727719
@@ -821,6 +813,9 @@ void GPUDisplayBackendVulkan::createSwapChain(bool forScreenshot, bool forMixing
821813 uint32_t oldFramesInFlight = mFramesInFlight , oldImageCount = mImageCount ;
822814 mFramesInFlight = mDisplay ->cfg ().vulkan .nFramesInFlight ;
823815 mImageCount = mSwapChainImages .size ();
816+ if (mImageCount > sizeof (mUpdateUBOdrawMatrix ) * 8 ) {
817+ throw std::runtime_error (" Too many swapchain images" );
818+ }
824819
825820 if (mFramesInFlight != oldFramesInFlight || mImageCount != oldImageCount || !mCommandInfrastructureCreated ) {
826821 if (mCommandInfrastructureCreated ) {
@@ -868,6 +863,7 @@ void GPUDisplayBackendVulkan::recreateRendering(bool forScreenshot, bool forMixi
868863 }
869864 createPipeline ();
870865 needRecordCommandBuffers ();
866+ mUpdateUBOtextMatrix = mUpdateUBOmixMatrix = -1 ; // Screen / render size may have changed
871867}
872868
873869// ---------------------------- VULKAN OFFSCREEN BUFFERS ----------------------------
@@ -945,6 +941,7 @@ void GPUDisplayBackendVulkan::clearOffscreenBuffers()
945941 clearVector (mDownsampleImages , [&](auto & x) { clearImage (x); });
946942 clearVector (mZImages , [&](auto & x) { clearImage (x); });
947943 clearVector (mMixImages , [&](auto & x) { clearImage (x); });
944+ clearVector (mFontVertexBuffer , [&](auto & x) { if (x.size ) { clearBuffer (x); } });
948945 if (mMixingSupported ) {
949946 clearBuffer (mMixingTextureVertexArray );
950947 }
@@ -1214,11 +1211,8 @@ void GPUDisplayBackendVulkan::clearShaders()
12141211
12151212void GPUDisplayBackendVulkan::writeToBuffer (VulkanBuffer& buffer, size_t size, const void * srcData)
12161213{
1217- if (buffer.deviceMemory != 1 ) {
1218- void * dstData;
1219- CHKERR (mDevice .mapMemory (buffer.memory , 0 , buffer.size , {}, &dstData));
1220- memcpy (dstData, srcData, size);
1221- mDevice .unmapMemory (buffer.memory );
1214+ if (buffer.mapped ) {
1215+ memcpy (buffer.mapped , srcData, size);
12221216 } else {
12231217 auto tmp = createBuffer (size, srcData, vk::BufferUsageFlagBits::eTransferSrc, 0 );
12241218
@@ -1263,6 +1257,9 @@ GPUDisplayBackendVulkan::VulkanBuffer GPUDisplayBackendVulkan::createBuffer(size
12631257
12641258 buffer.size = size;
12651259 buffer.deviceMemory = deviceMemory;
1260+ if (deviceMemory != 1 ) {
1261+ CHKERR (mDevice .mapMemory (buffer.memory , 0 , VK_WHOLE_SIZE , {}, &buffer.mapped ));
1262+ }
12661263
12671264 if (srcData != nullptr ) {
12681265 writeToBuffer (buffer, size, srcData);
@@ -1274,7 +1271,7 @@ GPUDisplayBackendVulkan::VulkanBuffer GPUDisplayBackendVulkan::createBuffer(size
12741271void GPUDisplayBackendVulkan::clearBuffer (VulkanBuffer& buffer)
12751272{
12761273 mDevice .destroyBuffer (buffer.buffer , nullptr );
1277- mDevice .freeMemory (buffer.memory , nullptr );
1274+ mDevice .freeMemory (buffer.memory , nullptr ); // Implicitly unmaps
12781275}
12791276
12801277void GPUDisplayBackendVulkan::clearVertexBuffers ()
@@ -1287,12 +1284,6 @@ void GPUDisplayBackendVulkan::clearVertexBuffers()
12871284 clearBuffer (mIndirectCommandBuffer );
12881285 mIndirectCommandBuffer .size = 0 ;
12891286 }
1290- for (auto & buf : mFontVertexBuffer ) {
1291- if (buf.size ) {
1292- clearBuffer (buf);
1293- }
1294- buf.size = 0 ;
1295- }
12961287}
12971288
12981289// ---------------------------- VULKAN TEXTURES ----------------------------
@@ -1468,7 +1459,15 @@ void GPUDisplayBackendVulkan::prepareDraw(const hmm_mat4& proj, const hmm_mat4&
14681459 mHasDrawnText = false ;
14691460 mFrameCommandBuffers .clear ();
14701461 const hmm_mat4 modelViewProj = proj * view;
1471- writeToBuffer (mUniformBuffersMat [0 ][mCurrentImageIndex ], sizeof (modelViewProj), &modelViewProj);
1462+ static_assert (sizeof (modelViewProj) == sizeof (mLastMVP ));
1463+ if (memcmp (&modelViewProj, mLastMVP , sizeof (mLastMVP ))) {
1464+ memcpy (mLastMVP , &modelViewProj, sizeof (mLastMVP ));
1465+ mUpdateUBOdrawMatrix = -1 ;
1466+ }
1467+ if (mUpdateUBOdrawMatrix & (1u << mCurrentImageIndex )) {
1468+ mUpdateUBOdrawMatrix &= ~(1u << mCurrentImageIndex );
1469+ writeToBuffer (mUniformBuffersMat [0 ][mCurrentImageIndex ], sizeof (mLastMVP ), mLastMVP );
1470+ }
14721471 }
14731472
14741473 mCurrentCommandBuffer = toMixBuffer ? mCommandBuffersMix [mCurrentImageIndex ] : mCommandBuffers [mCurrentImageIndex ];
@@ -1577,9 +1576,11 @@ void GPUDisplayBackendVulkan::downsampleToFramebuffer(vk::CommandBuffer& command
15771576
15781577void GPUDisplayBackendVulkan::prepareText ()
15791578{
1580- hmm_mat4 proj = HMM_Orthographic (0 .f , mScreenWidth , 0 .f , mScreenHeight , -1 , 1 );
1581- writeToBuffer (mUniformBuffersMat [1 ][mCurrentImageIndex ], sizeof (proj), &proj);
1582-
1579+ if (mUpdateUBOtextMatrix & (1u << mCurrentImageIndex )) {
1580+ mUpdateUBOtextMatrix &= ~(1u << mCurrentImageIndex );
1581+ hmm_mat4 proj = HMM_Orthographic (0 .f , mScreenWidth , 0 .f , mScreenHeight , -1 , 1 );
1582+ writeToBuffer (mUniformBuffersMat [1 ][mCurrentImageIndex ], sizeof (proj), &proj);
1583+ }
15831584 mFontVertexBufferHost .clear ();
15841585 mTextDrawCommands .clear ();
15851586}
@@ -1598,15 +1599,20 @@ void GPUDisplayBackendVulkan::finishText()
15981599
15991600 cmdBeginRenderingLoad (mCommandBuffersText [mCurrentImageIndex ], mSwapChainImages [mCurrentImageIndex ], mSwapChainImageViews [mCurrentImageIndex ], mScreenWidth , mScreenHeight );
16001601
1601- if (mFontVertexBuffer [mCurrentImageIndex ].size ) {
1602- clearBuffer (mFontVertexBuffer [mCurrentImageIndex ]);
1602+ VulkanBuffer& fontBuffer = mFontVertexBuffer [mCurrentImageIndex ];
1603+ const size_t fontBufferSize = mFontVertexBufferHost .size () * sizeof (mFontVertexBufferHost [0 ]);
1604+ if (fontBuffer.size < fontBufferSize) { // Persistent per image, only grows
1605+ if (fontBuffer.size ) {
1606+ clearBuffer (fontBuffer);
1607+ }
1608+ fontBuffer = createBuffer (std::max (fontBufferSize, 2 * fontBuffer.size ), nullptr , vk::BufferUsageFlagBits::eVertexBuffer, 0 );
16031609 }
1604- mFontVertexBuffer [ mCurrentImageIndex ] = createBuffer ( mFontVertexBufferHost . size () * sizeof ( float ) , mFontVertexBufferHost .data (), vk::BufferUsageFlagBits::eVertexBuffer, 0 );
1610+ writeToBuffer (fontBuffer, fontBufferSize , mFontVertexBufferHost .data ());
16051611
16061612 mCommandBuffersText [mCurrentImageIndex ].bindPipeline (vk::PipelineBindPoint::eGraphics, mPipelines [3 ]);
16071613 mCommandBuffersText [mCurrentImageIndex ].bindDescriptorSets (vk::PipelineBindPoint::eGraphics, mPipelineLayoutTexture , 0 , 1 , &mDescriptorSets [1 ][mCurrentImageIndex ], 0 , nullptr );
16081614 vk::DeviceSize offsets[] = {0 };
1609- mCommandBuffersText [mCurrentImageIndex ].bindVertexBuffers (0 , 1 , &mFontVertexBuffer [ mCurrentImageIndex ] .buffer , offsets);
1615+ mCommandBuffersText [mCurrentImageIndex ].bindVertexBuffers (0 , 1 , &fontBuffer .buffer , offsets);
16101616
16111617 for (const auto & cmd : mTextDrawCommands ) {
16121618 mCommandBuffersText [mCurrentImageIndex ].pushConstants (mPipelineLayoutTexture , vk::ShaderStageFlagBits::eFragment, 0 , sizeof (cmd.color ), cmd.color );
@@ -1621,9 +1627,11 @@ void GPUDisplayBackendVulkan::finishText()
16211627
16221628void GPUDisplayBackendVulkan::mixImages (vk::CommandBuffer commandBuffer, float mixSlaveImage)
16231629{
1624- hmm_mat4 proj = HMM_Orthographic (0 .f , mRenderWidth , 0 .f , mRenderHeight , -1 , 1 );
1625- writeToBuffer (mUniformBuffersMat [2 ][mCurrentImageIndex ], sizeof (proj), &proj);
1626-
1630+ if (mUpdateUBOmixMatrix & (1u << mCurrentImageIndex )) {
1631+ mUpdateUBOmixMatrix &= ~(1u << mCurrentImageIndex );
1632+ hmm_mat4 proj = HMM_Orthographic (0 .f , mRenderWidth , 0 .f , mRenderHeight , -1 , 1 );
1633+ writeToBuffer (mUniformBuffersMat [2 ][mCurrentImageIndex ], sizeof (proj), &proj);
1634+ }
16271635 commandBuffer.reset ({});
16281636 vk::CommandBufferBeginInfo beginInfo{};
16291637 beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
@@ -1874,8 +1882,7 @@ void GPUDisplayBackendVulkan::readImageToPixels(vk::Image image, vk::ImageLayout
18741882 submitSingleTimeCommandBuffer (cmdBuffer);
18751883
18761884 const bool swapRB = format == vk::Format::eR8G8B8A8Unorm || format == vk::Format::eR8G8B8A8Srgb; // Raw copy in swapchain format, the BMP needs BGRA
1877- const char * data;
1878- CHKERR (mDevice .mapMemory (readBuffer.memory , 0 , VK_WHOLE_SIZE , {}, (void **)&data));
1885+ const char * data = (const char *)readBuffer.mapped ;
18791886 for (uint32_t i = 0 ; i < height; i++) { // BMP rows are bottom-up
18801887 char * dst = pixels.data () + i * width * bytesPerPixel;
18811888 memcpy (dst, data + (height - i - 1 ) * width * bytesPerPixel, width * bytesPerPixel);
@@ -1885,7 +1892,6 @@ void GPUDisplayBackendVulkan::readImageToPixels(vk::Image image, vk::ImageLayout
18851892 }
18861893 }
18871894 }
1888- mDevice .unmapMemory (readBuffer.memory );
18891895 clearBuffer (readBuffer);
18901896 if (mDisplay ->cfgR ().screenshotScaleFactor != 1 ) {
18911897 mDevice .freeMemory (dstImageMemory, nullptr );
0 commit comments