Support frame and video dumping from VideoCommon

This commit is contained in:
iwubcode
2017-05-30 23:44:03 -05:00
parent 79387dddb2
commit a9f0d1783b
17 changed files with 306 additions and 158 deletions

View File

@ -507,23 +507,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti
// are determined by guest state. Currently, the only way to catch these is to update every frame.
UpdateDrawRectangle();
// Render the frame dump image if enabled.
if (IsFrameDumping())
{
// If we haven't dumped a single frame yet, set up frame dumping.
if (!m_frame_dumping_active)
StartFrameDumping();
/* DrawFrameDump(scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height,
ticks);*/
}
else
{
// If frame dumping was previously enabled, flush all frames and remove the fence callback.
if (m_frame_dumping_active)
EndFrameDumping();
}
// Ensure the worker thread is not still submitting a previous command buffer.
// In other words, the last frame has been submitted (otherwise the next call would
// be a race, as the image may not have been consumed yet).
@ -856,7 +839,7 @@ void Renderer::OnFrameDumpImageReady(VkFence fence)
void Renderer::WriteFrameDumpImage(size_t index)
{
FrameDumpImage& frame = m_frame_dump_images[index];
/*FrameDumpImage& frame = m_frame_dump_images[index];
_assert_(frame.pending);
// Check fence has been signaled.
@ -873,14 +856,14 @@ void Renderer::WriteFrameDumpImage(size_t index)
static_cast<int>(frame.readback_texture->GetHeight()),
static_cast<int>(frame.readback_texture->GetRowStride()), frame.dump_state);
frame.pending = false;
frame.pending = false;*/
}
StagingTexture2D* Renderer::PrepareFrameDumpImage(u32 width, u32 height, u64 ticks)
{
// Ensure the last frame that was sent to the frame dump has completed encoding before we send
// the next image to it.
FinishFrameData();
//FinishFrameData();
// If the last image hasn't been written to the frame dump yet, write it now.
// This is necessary so that the worker thread is no more than one frame behind, and the pointer

View File

@ -113,23 +113,17 @@ void VKTexture::Bind(unsigned int stage)
StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView());
}
bool VKTexture::Save(const std::string& filename, unsigned int level)
std::optional<AbstractTexture::RawTextureInfo> VKTexture::MapFullImpl()
{
_assert_(level < m_config.levels);
// No support for optimization of full copy
return MapRegionImpl(0, 0, 0, m_config.width, m_config.height);
}
// We can't dump compressed textures currently (it would mean drawing them to a RGBA8
// framebuffer, and saving that). TextureCache does not call Save for custom textures
// anyway, so this is fine for now.
_assert_(m_config.format == AbstractTextureFormat::RGBA8);
// Determine dimensions of image we want to save.
u32 level_width = std::max(1u, m_config.width >> level);
u32 level_height = std::max(1u, m_config.height >> level);
// Use a temporary staging texture for the download. Certainly not optimal,
// but since we have to idle the GPU anyway it doesn't really matter.
std::unique_ptr<StagingTexture2D> staging_texture = StagingTexture2D::Create(
STAGING_BUFFER_TYPE_READBACK, level_width, level_height, TEXTURECACHE_TEXTURE_FORMAT);
std::optional<AbstractTexture::RawTextureInfo> VKTexture::MapRegionImpl(u32 level, u32 x, u32 y,
u32 width, u32 height)
{
m_staging_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height,
TEXTURECACHE_TEXTURE_FORMAT);
// Transition image to transfer source, and invalidate the current state,
// since we'll be executing the command buffer.
@ -138,9 +132,9 @@ bool VKTexture::Save(const std::string& filename, unsigned int level)
StateTracker::GetInstance()->EndRenderPass();
// Copy to download buffer.
staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
level_width, level_height, level, 0);
m_staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, x, y, width,
height, level, 0);
// Restore original state of texture.
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
@ -150,21 +144,23 @@ bool VKTexture::Save(const std::string& filename, unsigned int level)
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
// Map the staging texture so we can copy the contents out.
if (!staging_texture->Map())
if (!m_staging_texture->Map())
{
PanicAlert("Failed to map staging texture");
return false;
return {};
}
// Write texture out to file.
// It's okay to throw this texture away immediately, since we're done with it, and
// we blocked until the copy completed on the GPU anyway.
bool result = TextureToPng(reinterpret_cast<u8*>(staging_texture->GetMapPointer()),
static_cast<u32>(staging_texture->GetRowStride()), filename,
level_width, level_height);
return AbstractTexture::RawTextureInfo{reinterpret_cast<u8*>(m_staging_texture->GetMapPointer()),
static_cast<u32>(m_staging_texture->GetRowStride()), width,
height};
}
staging_texture->Unmap();
return result;
void VKTexture::Unmap()
{
if (!m_staging_texture)
return;
m_staging_texture->Unmap();
}
void VKTexture::CopyTextureRectangle(const MathUtil::Rectangle<int>& dst_rect,

View File

@ -20,7 +20,7 @@ public:
~VKTexture();
void Bind(unsigned int stage) override;
bool Save(const std::string& filename, unsigned int level) override;
void Unmap() override;
void CopyRectangleFromTexture(const AbstractTexture* source,
const MathUtil::Rectangle<int>& srcrect,
@ -47,7 +47,12 @@ private:
void ScaleTextureRectangle(const MathUtil::Rectangle<int>& dst_rect, Texture2D* src_texture,
const MathUtil::Rectangle<int>& src_rect);
std::optional<RawTextureInfo> MapFullImpl() override;
std::optional<RawTextureInfo> MapRegionImpl(u32 level, u32 x, u32 y, u32 width,
u32 height) override;
std::unique_ptr<Texture2D> m_texture;
std::unique_ptr<StagingTexture2D> m_staging_texture;
VkFramebuffer m_framebuffer;
};