Merge pull request #2346 from nikeinikei/vk_screenshot_fix

vulkan: closes #2289
This commit is contained in:
Sasha Szpakowski
2026-08-01 17:23:33 -03:00
committed by GitHub
2 changed files with 54 additions and 49 deletions
+53 -48
View File
@@ -393,7 +393,7 @@ void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
startRenderPass();
}
void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallbackData)
image::ImageData *Graphics::submitGpuCommands(SubmitMode submitMode)
{
flushBatchedDraws();
@@ -515,6 +515,8 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
if (result != VK_SUCCESS)
throw love::Exception("Failed to submit Vulkan draw command buffer: %s", Vulkan::getErrorString(result));
image::ImageData *screenshotImageData = nullptr;
if (submitMode == SUBMIT_NOPRESENT || submitMode == SUBMIT_RESTART || screenshotBuffer != VK_NULL_HANDLE)
{
vkQueueWaitIdle(graphicsQueue);
@@ -530,63 +532,54 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
{
auto imageModule = Module::getInstance<love::image::Image>(M_IMAGE);
for (int i = 0; i < (int)pendingScreenshotCallbacks.size(); i++)
try
{
const auto &info = pendingScreenshotCallbacks[i];
image::ImageData *img = nullptr;
try
screenshotImageData = imageModule->newImageData(
swapChainExtent.width,
swapChainExtent.height,
PIXELFORMAT_RGBA8_UNORM,
screenshotAllocationInfo.pMappedData);
}
catch (love::Exception &)
{
for (int i = 0; i < (int)pendingScreenshotCallbacks.size(); i++)
{
img = imageModule->newImageData(
swapChainExtent.width,
swapChainExtent.height,
PIXELFORMAT_RGBA8_UNORM,
screenshotAllocationInfo.pMappedData);
const auto &ninfo = pendingScreenshotCallbacks[i];
ninfo.callback(&ninfo, nullptr, nullptr);
}
catch (love::Exception &)
{
info.callback(&info, nullptr, nullptr);
for (int j = i + 1; j < (int)pendingScreenshotCallbacks.size(); j++)
{
const auto& ninfo = pendingScreenshotCallbacks[j];
ninfo.callback(&ninfo, nullptr, nullptr);
}
vmaDestroyBuffer(vmaAllocator, screenshotBuffer, screenshotAllocation);
pendingScreenshotCallbacks.clear();
throw;
}
uint8 *screenshot = (uint8*)img->getData();
if (swapChainImageFormat == VK_FORMAT_B8G8R8A8_UNORM || swapChainImageFormat == VK_FORMAT_B8G8R8A8_SRGB)
{
// Convert from BGRA to RGBA and replace alpha with full opacity.
for (size_t i = 0; i < img->getSize(); i += 4)
{
uint8 r = screenshot[i + 2];
screenshot[i + 2] = screenshot[i + 0];
screenshot[i + 0] = r;
screenshot[i + 3] = 255;
}
}
else
{
// Replace alpha with full opacity.
for (size_t i = 0; i < img->getSize(); i += 4)
screenshot[i + 3] = 255;
}
info.callback(&info, img, screenshotCallbackData);
img->release();
vmaDestroyBuffer(vmaAllocator, screenshotBuffer, screenshotAllocation);
pendingScreenshotCallbacks.clear();
throw;
}
vmaDestroyBuffer(vmaAllocator, screenshotBuffer, screenshotAllocation);
pendingScreenshotCallbacks.clear();
uint8 *screenshot = (uint8*)screenshotImageData->getData();
if (swapChainImageFormat == VK_FORMAT_B8G8R8A8_UNORM || swapChainImageFormat == VK_FORMAT_B8G8R8A8_SRGB)
{
// Convert from BGRA to RGBA and replace alpha with full opacity.
for (size_t i = 0; i < screenshotImageData->getSize(); i += 4)
{
uint8 r = screenshot[i + 2];
screenshot[i + 2] = screenshot[i + 0];
screenshot[i + 0] = r;
screenshot[i + 3] = 255;
}
}
else
{
// Replace alpha with full opacity.
for (size_t i = 0; i < screenshotImageData->getSize(); i += 4)
screenshot[i + 3] = 255;
}
}
if (submitMode == SUBMIT_RESTART)
startRecordingGraphicsCommands();
}
return screenshotImageData;
}
void Graphics::present(void *screenshotCallbackdata)
@@ -602,7 +595,7 @@ void Graphics::present(void *screenshotCallbackdata)
deprecations.draw(this);
submitGpuCommands(SUBMIT_PRESENT, screenshotCallbackdata);
image::ImageData *screenshotImageData = submitGpuCommands(SUBMIT_PRESENT);
VkResult result = VK_SUCCESS;
@@ -672,6 +665,18 @@ void Graphics::present(void *screenshotCallbackdata)
realFrameIndex++;
beginFrame();
if (screenshotImageData)
{
for (int i = 0; i < pendingScreenshotCallbacks.size(); i++)
{
const auto &info = pendingScreenshotCallbacks[i];
info.callback(&info, screenshotImageData, screenshotCallbackdata);
}
pendingScreenshotCallbacks.clear();
screenshotImageData->release();
}
}
void Graphics::backbufferChanged(const BackbufferSettings &settings)
+1 -1
View File
@@ -282,7 +282,7 @@ public:
VkCommandBuffer getCommandBufferForDataTransfer();
void queueCleanUp(std::function<void()> cleanUp);
void addReadbackCallback(std::function<void()> callback);
void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr);
image::ImageData *submitGpuCommands(SubmitMode);
VkSampler getCachedSampler(const SamplerState &sampler);
SharedDescriptorPools *acquireDescriptorPools(int dynamicUniformBuffers, int sampledTextures, int storageTextures, int texelBuffers, int storageBuffers);
void releaseDescriptorPools(SharedDescriptorPools *pools);