Skip to content

Commit 0deeadf

Browse files
committed
vulkan: Allow native RGB8 screenshot framebuffers when available
Some notable devices support native RGB8 color-attachments: https://vulkan.gpuinfo.org/listdevicescoverage.php?optimaltilingformat=R8G8B8_UNORM&featureflagbit=COLOR_ATTACHMENT This removes the need to do a manual RGBA->RGB format conversion on the CPU in favor of a direct memcpy from the downloaded texture, when available.
1 parent b98e833 commit 0deeadf

File tree

1 file changed

+32
-9
lines changed

1 file changed

+32
-9
lines changed

core/rend/vulkan/vulkan_context.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,9 +1340,22 @@ bool VulkanContext::GetLastFrame(std::vector<u8>& data, int& width, int& height)
13401340
else
13411341
width = w;
13421342
}
1343+
1344+
vk::Format imageFormat = vk::Format::eR8G8B8A8Unorm;
1345+
const vk::ImageUsageFlags imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
1346+
1347+
// Test if RGB8 is natively supported to avoid having to do a format conversion
1348+
bool nativeRgb8 = false;
1349+
vk::ImageFormatProperties rgb8Properties{};
1350+
if (physicalDevice.getImageFormatProperties(vk::Format::eR8G8B8Unorm, vk::ImageType::e2D, vk::ImageTiling::eOptimal, imageUsage, {}, &rgb8Properties) == vk::Result::eSuccess)
1351+
{
1352+
nativeRgb8 = true;
1353+
imageFormat = vk::Format::eR8G8B8Unorm;
1354+
}
1355+
13431356
// color attachment
13441357
FramebufferAttachment attachment(physicalDevice, *device);
1345-
attachment.Init(width, height, vk::Format::eR8G8B8A8Unorm, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc, "screenshot");
1358+
attachment.Init(width, height, imageFormat, imageUsage, "screenshot");
13461359
// command buffer
13471360
vk::UniqueCommandBuffer commandBuffer = std::move(device->allocateCommandBuffersUnique(
13481361
vk::CommandBufferAllocateInfo(*commandPools.back(), vk::CommandBufferLevel::ePrimary, 1)).front());
@@ -1352,7 +1365,7 @@ bool VulkanContext::GetLastFrame(std::vector<u8>& data, int& width, int& height)
13521365
CommandBufferDebugScope _(commandBuffer.get(), "GetLastFrame", scopeColor);
13531366

13541367
// render pass
1355-
vk::AttachmentDescription attachmentDescription = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1,
1368+
vk::AttachmentDescription attachmentDescription = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), imageFormat, vk::SampleCountFlagBits::e1,
13561369
vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare,
13571370
vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferSrcOptimal);
13581371
vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal);
@@ -1417,15 +1430,25 @@ bool VulkanContext::GetLastFrame(std::vector<u8>& data, int& width, int& height)
14171430

14181431
const u8 *img = (const u8 *)attachment.GetBufferData()->MapMemory();
14191432
data.clear();
1420-
data.reserve(width * height * 3);
1421-
for (int y = 0; y < height; y++)
1433+
if (nativeRgb8)
14221434
{
1423-
for (int x = 0; x < width; x++)
1435+
// Format is already RGB, can be directly copied
1436+
data.resize(width * height * 3);
1437+
std::memcpy(data.data(), img, width* height * 3);
1438+
}
1439+
else
1440+
{
1441+
data.reserve(width * height * 3);
1442+
// RGBA -> RGB
1443+
for (int y = 0; y < height; y++)
14241444
{
1425-
data.push_back(*img++);
1426-
data.push_back(*img++);
1427-
data.push_back(*img++);
1428-
img++;
1445+
for (int x = 0; x < width; x++)
1446+
{
1447+
data.push_back(*img++);
1448+
data.push_back(*img++);
1449+
data.push_back(*img++);
1450+
img++;
1451+
}
14291452
}
14301453
}
14311454
attachment.GetBufferData()->UnmapMemory();

0 commit comments

Comments
 (0)