mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- capture screenshot support
This commit is contained in:
parent
5d2917bb4f
commit
625cc11ea2
4 changed files with 91 additions and 22 deletions
|
@ -119,7 +119,7 @@ void VkPostprocess::BlitSceneToTexture()
|
|||
imageTransition1.execute(fb->GetDrawCommands());
|
||||
}
|
||||
|
||||
void VkPostprocess::BlitCurrentToImage(VulkanImage *dstimage, VkImageLayout *dstlayout)
|
||||
void VkPostprocess::BlitCurrentToImage(VulkanImage *dstimage, VkImageLayout *dstlayout, VkImageLayout finallayout)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
|
@ -134,7 +134,7 @@ void VkPostprocess::BlitCurrentToImage(VulkanImage *dstimage, VkImageLayout *dst
|
|||
VkPPImageTransition imageTransition0;
|
||||
imageTransition0.addImage(srcimage, srclayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
|
||||
imageTransition0.addImage(dstimage, dstlayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
|
||||
imageTransition0.execute(fb->GetDrawCommands());
|
||||
imageTransition0.execute(cmdbuffer);
|
||||
|
||||
VkImageBlit blit = {};
|
||||
blit.srcOffsets[0] = { 0, 0, 0 };
|
||||
|
@ -155,8 +155,8 @@ void VkPostprocess::BlitCurrentToImage(VulkanImage *dstimage, VkImageLayout *dst
|
|||
1, &blit, VK_FILTER_NEAREST);
|
||||
|
||||
VkPPImageTransition imageTransition1;
|
||||
imageTransition1.addImage(dstimage, dstlayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
|
||||
imageTransition1.execute(fb->GetDrawCommands());
|
||||
imageTransition1.addImage(dstimage, dstlayout, finallayout, false);
|
||||
imageTransition1.execute(cmdbuffer);
|
||||
}
|
||||
|
||||
void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders)
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
void ClearTonemapPalette();
|
||||
|
||||
void BlitSceneToTexture();
|
||||
void BlitCurrentToImage(VulkanImage *image, VkImageLayout *layout);
|
||||
void BlitCurrentToImage(VulkanImage *image, VkImageLayout *layout, VkImageLayout finallayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
void DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders);
|
||||
|
||||
private:
|
||||
|
|
|
@ -166,6 +166,26 @@ void VulkanFrameBuffer::Update()
|
|||
|
||||
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
|
||||
|
||||
SubmitCommands(true);
|
||||
|
||||
Flush3D.Unclock();
|
||||
|
||||
Finish.Reset();
|
||||
Finish.Clock();
|
||||
device->PresentFrame();
|
||||
device->WaitPresent();
|
||||
|
||||
mDrawCommands.reset();
|
||||
mUploadCommands.reset();
|
||||
mFrameDeleteList.clear();
|
||||
|
||||
Finish.Unclock();
|
||||
|
||||
Super::Update();
|
||||
}
|
||||
|
||||
void VulkanFrameBuffer::SubmitCommands(bool finish)
|
||||
{
|
||||
mDrawCommands->end();
|
||||
|
||||
if (mUploadCommands)
|
||||
|
@ -186,7 +206,7 @@ void VulkanFrameBuffer::Update()
|
|||
// Wait for upload commands to finish, then submit render commands
|
||||
VkSemaphore waitSemaphores[] = { mUploadSemaphore->semaphore, device->imageAvailableSemaphore->semaphore };
|
||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
submitInfo.waitSemaphoreCount = 2;
|
||||
submitInfo.waitSemaphoreCount = finish ? 2 : 1;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
@ -204,7 +224,7 @@ void VulkanFrameBuffer::Update()
|
|||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.waitSemaphoreCount = finish ? 1 : 0;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
@ -215,21 +235,6 @@ void VulkanFrameBuffer::Update()
|
|||
if (result < VK_SUCCESS)
|
||||
I_FatalError("Failed to submit command buffer! Error %d\n", result);
|
||||
}
|
||||
|
||||
Flush3D.Unclock();
|
||||
|
||||
Finish.Reset();
|
||||
Finish.Clock();
|
||||
device->PresentFrame();
|
||||
device->WaitPresent();
|
||||
|
||||
mDrawCommands.reset();
|
||||
mUploadCommands.reset();
|
||||
mFrameDeleteList.clear();
|
||||
|
||||
Finish.Unclock();
|
||||
|
||||
Super::Update();
|
||||
}
|
||||
|
||||
void VulkanFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
|
||||
|
@ -611,6 +616,67 @@ FTexture *VulkanFrameBuffer::WipeEndScreen()
|
|||
return tex;
|
||||
}
|
||||
|
||||
TArray<uint8_t> VulkanFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma)
|
||||
{
|
||||
int w = SCREENWIDTH;
|
||||
int h = SCREENHEIGHT;
|
||||
|
||||
// Convert from rgba16f to rgba8 using the GPU:
|
||||
ImageBuilder imgbuilder;
|
||||
imgbuilder.setFormat(VK_FORMAT_R8G8B8A8_UNORM);
|
||||
imgbuilder.setUsage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
imgbuilder.setSize(w, h);
|
||||
auto image = imgbuilder.create(device);
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
GetPostprocess()->BlitCurrentToImage(image.get(), &layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
// Staging buffer for download
|
||||
BufferBuilder bufbuilder;
|
||||
bufbuilder.setSize(w * h * 4);
|
||||
bufbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU);
|
||||
auto staging = bufbuilder.create(device);
|
||||
|
||||
// Copy from image to buffer
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageExtent.width = w;
|
||||
region.imageExtent.height = h;
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
GetDrawCommands()->copyImageToBuffer(image->image, layout, staging->buffer, 1, ®ion);
|
||||
|
||||
// Submit command buffers and wait for device to finish the work
|
||||
SubmitCommands(false);
|
||||
vkWaitForFences(device->device, 1, &device->renderFinishedFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||
vkResetFences(device->device, 1, &device->renderFinishedFence->fence);
|
||||
mDrawCommands.reset();
|
||||
mUploadCommands.reset();
|
||||
mFrameDeleteList.clear();
|
||||
|
||||
// Map and convert from rgba8 to rgb8
|
||||
TArray<uint8_t> ScreenshotBuffer(w * h * 3, true);
|
||||
uint8_t *pixels = (uint8_t*)staging->Map(0, w * h * 4);
|
||||
int dindex = 0;
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
int sindex = (h - y - 1) * w * 4;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
ScreenshotBuffer[dindex] = pixels[sindex];
|
||||
ScreenshotBuffer[dindex + 1] = pixels[sindex + 1];
|
||||
ScreenshotBuffer[dindex + 2] = pixels[sindex + 2];
|
||||
dindex += 3;
|
||||
sindex += 4;
|
||||
}
|
||||
}
|
||||
staging->Unmap();
|
||||
|
||||
pitch = w * 3;
|
||||
color_type = SS_RGB;
|
||||
gamma = 2.2f;
|
||||
return ScreenshotBuffer;
|
||||
}
|
||||
|
||||
void VulkanFrameBuffer::BeginFrame()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
|
|
|
@ -74,6 +74,8 @@ public:
|
|||
FTexture *WipeStartScreen() override;
|
||||
FTexture *WipeEndScreen() override;
|
||||
|
||||
TArray<uint8_t> GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override;
|
||||
|
||||
void SetVSync(bool vsync);
|
||||
|
||||
void Draw2D() override;
|
||||
|
@ -84,6 +86,7 @@ private:
|
|||
void DrawScene(HWDrawInfo *di, int drawmode);
|
||||
void PrintStartupLog();
|
||||
void CreateFanToTrisIndexBuffer();
|
||||
void SubmitCommands(bool finish);
|
||||
|
||||
std::unique_ptr<VkShaderManager> mShaderManager;
|
||||
std::unique_ptr<VkSamplerManager> mSamplerManager;
|
||||
|
|
Loading…
Reference in a new issue