Skip to content

Commit 4df63c0

Browse files
committed
GPU Vulkan Backend: fix taking screenshots if runtime uses non-standard row-pitch
1 parent 3a0d31e commit 4df63c0

1 file changed

Lines changed: 37 additions & 32 deletions

File tree

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

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,19 +1911,25 @@ void GPUDisplayBackendVulkan::OpenGLPrint(const char* s, float x, float y, float
19111911

19121912
void 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, &copyRegion);
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

Comments
 (0)