@@ -1911,19 +1911,25 @@ void GPUDisplayBackendVulkan::OpenGLPrint(const char* s, float x, float y, float
19111911
19121912void GPUDisplayBackendVulkan::readImageToPixels (vk::Image image, vk::ImageLayout layout, std::vector<char >& pixels)
19131913{
1914+ const vk::Format format = mSurfaceFormat .format ;
1915+ if (format != vk::Format::eB8G8R8A8Unorm && format != vk::Format::eB8G8R8A8Srgb && format != vk::Format::eR8G8B8A8Unorm && format != vk::Format::eR8G8B8A8Srgb) {
1916+ GPUError (" Screenshot not supported for swapchain format %s, only 8 bit BGRA / RGBA" , vk::to_string (format).c_str ());
1917+ pixels.clear ();
1918+ return ;
1919+ }
19141920 uint32_t width = mScreenWidth * mDisplay ->cfgR ().screenshotScaleFactor ;
19151921 uint32_t height = mScreenHeight * mDisplay ->cfgR ().screenshotScaleFactor ;
19161922 static constexpr int32_t bytesPerPixel = 4 ;
19171923 pixels.resize (width * height * bytesPerPixel);
19181924
1919- vk::Image dstImage, dstImage2, src2 ;
1920- vk::DeviceMemory dstImageMemory, dstImageMemory2 ;
1921- createImageI ( mDevice , mPhysicalDevice , dstImage, dstImageMemory, width, height, vk::Format::eR8G8B8A8Unorm , vk::ImageUsageFlagBits ::eTransferDst, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, vk::ImageTiling::eLinear );
1925+ vk::Image dstImage, src ;
1926+ vk::DeviceMemory dstImageMemory;
1927+ VulkanBuffer readBuffer = createBuffer ( width * height * bytesPerPixel, nullptr , vk::BufferUsageFlagBits ::eTransferDst, 0 );
19221928 vk::CommandBuffer cmdBuffer = getSingleTimeCommandBuffer ();
19231929 cmdImageMemoryBarrier (cmdBuffer, image, vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferRead, layout, vk::ImageLayout::eTransferSrcOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
19241930 if (mDisplay ->cfgR ().screenshotScaleFactor != 1 ) {
1925- createImageI (mDevice , mPhysicalDevice , dstImage2, dstImageMemory2 , width, height, mSurfaceFormat .format , vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal, vk::ImageTiling::eOptimal);
1926- cmdImageMemoryBarrier (cmdBuffer, dstImage2 , {}, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
1931+ createImageI (mDevice , mPhysicalDevice , dstImage, dstImageMemory , width, height, mSurfaceFormat .format , vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal, vk::ImageTiling::eOptimal);
1932+ cmdImageMemoryBarrier (cmdBuffer, dstImage , {}, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
19271933 vk::Offset3D blitSizeSrc = {(int32_t )mRenderWidth , (int32_t )mRenderHeight , 1 };
19281934 vk::Offset3D blitSizeDst = {(int32_t )width, (int32_t )height, 1 };
19291935 vk::ImageBlit imageBlitRegion{};
@@ -1933,42 +1939,41 @@ void GPUDisplayBackendVulkan::readImageToPixels(vk::Image image, vk::ImageLayout
19331939 imageBlitRegion.dstSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
19341940 imageBlitRegion.dstSubresource .layerCount = 1 ;
19351941 imageBlitRegion.dstOffsets [1 ] = blitSizeDst;
1936- cmdBuffer.blitImage (image, vk::ImageLayout::eTransferSrcOptimal, dstImage2 , vk::ImageLayout::eTransferDstOptimal, 1 , &imageBlitRegion, vk::Filter::eLinear);
1937- src2 = dstImage2 ;
1938- cmdImageMemoryBarrier (cmdBuffer, dstImage2 , vk::AccessFlagBits::eMemoryRead , vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
1942+ cmdBuffer.blitImage (image, vk::ImageLayout::eTransferSrcOptimal, dstImage , vk::ImageLayout::eTransferDstOptimal, 1 , &imageBlitRegion, vk::Filter::eLinear);
1943+ src = dstImage ;
1944+ cmdImageMemoryBarrier (cmdBuffer, dstImage , vk::AccessFlagBits::eTransferWrite , vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
19391945 } else {
1940- src2 = image;
1946+ src = image;
19411947 }
19421948
1943- cmdImageMemoryBarrier (cmdBuffer, dstImage, {}, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
1944- vk::ImageCopy imageCopyRegion{};
1945- imageCopyRegion.srcSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
1946- imageCopyRegion.srcSubresource .layerCount = 1 ;
1947- imageCopyRegion.dstSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
1948- imageCopyRegion.dstSubresource .layerCount = 1 ;
1949- imageCopyRegion.extent .width = width;
1950- imageCopyRegion.extent .height = height;
1951- imageCopyRegion.extent .depth = 1 ;
1952- cmdBuffer.copyImage (src2, vk::ImageLayout::eTransferSrcOptimal, dstImage, vk::ImageLayout::eTransferDstOptimal, 1 , &imageCopyRegion);
1949+ vk::BufferImageCopy copyRegion{};
1950+ copyRegion.imageSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
1951+ copyRegion.imageSubresource .layerCount = 1 ;
1952+ copyRegion.imageExtent = vk::Extent3D{width, height, 1 };
1953+ cmdBuffer.copyImageToBuffer (src, vk::ImageLayout::eTransferSrcOptimal, readBuffer.buffer , 1 , ©Region);
19531954
1954- cmdImageMemoryBarrier (cmdBuffer, dstImage, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eMemoryRead, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eGeneral, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
1955+ vk::BufferMemoryBarrier hostBarrier{vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead, VK_QUEUE_FAMILY_IGNORED , VK_QUEUE_FAMILY_IGNORED , readBuffer.buffer , 0 , VK_WHOLE_SIZE };
1956+ cmdBuffer.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eHost, {}, 0 , nullptr , 1 , &hostBarrier, 0 , nullptr );
19551957 cmdImageMemoryBarrier (cmdBuffer, image, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryRead, vk::ImageLayout::eTransferSrcOptimal, layout, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer);
19561958 submitSingleTimeCommandBuffer (cmdBuffer);
19571959
1958- vk::ImageSubresource subResource{vk::ImageAspectFlagBits::eColor, 0 , 0 };
1959- vk::SubresourceLayout subResourceLayout = mDevice .getImageSubresourceLayout (dstImage, subResource);
1960+ const bool swapRB = format == vk::Format::eR8G8B8A8Unorm || format == vk::Format::eR8G8B8A8Srgb; // Raw copy in swapchain format, the BMP needs BGRA
19601961 const char * data;
1961- CHKERR (mDevice .mapMemory (dstImageMemory, 0 , VK_WHOLE_SIZE , {}, (void **)&data));
1962- data += subResourceLayout.offset ;
1963- for (uint32_t i = 0 ; i < height; i++) {
1964- memcpy (pixels.data () + i * width * bytesPerPixel, data + (height - i - 1 ) * width * bytesPerPixel, width * bytesPerPixel);
1965- }
1966- mDevice .unmapMemory (dstImageMemory);
1967- mDevice .freeMemory (dstImageMemory, nullptr );
1968- mDevice .destroyImage (dstImage, nullptr );
1962+ CHKERR (mDevice .mapMemory (readBuffer.memory , 0 , VK_WHOLE_SIZE , {}, (void **)&data));
1963+ for (uint32_t i = 0 ; i < height; i++) { // BMP rows are bottom-up
1964+ char * dst = pixels.data () + i * width * bytesPerPixel;
1965+ memcpy (dst, data + (height - i - 1 ) * width * bytesPerPixel, width * bytesPerPixel);
1966+ if (swapRB) {
1967+ for (uint32_t j = 0 ; j < width; j++) {
1968+ std::swap (dst[j * bytesPerPixel], dst[j * bytesPerPixel + 2 ]);
1969+ }
1970+ }
1971+ }
1972+ mDevice .unmapMemory (readBuffer.memory );
1973+ clearBuffer (readBuffer);
19691974 if (mDisplay ->cfgR ().screenshotScaleFactor != 1 ) {
1970- mDevice .freeMemory (dstImageMemory2 , nullptr );
1971- mDevice .destroyImage (dstImage2 , nullptr );
1975+ mDevice .freeMemory (dstImageMemory , nullptr );
1976+ mDevice .destroyImage (dstImage , nullptr );
19721977 }
19731978}
19741979
0 commit comments