From c2cc128f1b6be695a4facd3c0fd697a24c3df17a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 30 Oct 2017 22:00:15 +1000 Subject: [PATCH] AbstractTexture: Implement Save using new common methods --- Source/Core/VideoBackends/OGL/TextureCache.h | 3 -- Source/Core/VideoCommon/AbstractTexture.cpp | 32 +++++++++++++++----- Source/Core/VideoCommon/AbstractTexture.h | 4 ++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h index ae848c8c9c..50366f7d1a 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.h +++ b/Source/Core/VideoBackends/OGL/TextureCache.h @@ -97,7 +97,4 @@ private: std::map, TextureDecodingProgramInfo> m_texture_decoding_program_info; std::array m_texture_decoding_buffer_views; }; - -bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, - int virtual_height, unsigned int level); } diff --git a/Source/Core/VideoCommon/AbstractTexture.cpp b/Source/Core/VideoCommon/AbstractTexture.cpp index 7e09be5344..109bb52897 100644 --- a/Source/Core/VideoCommon/AbstractTexture.cpp +++ b/Source/Core/VideoCommon/AbstractTexture.cpp @@ -6,8 +6,10 @@ #include "Common/Assert.h" #include "Common/MsgHandler.h" +#include "VideoCommon/AbstractStagingTexture.h" #include "VideoCommon/AbstractTexture.h" #include "VideoCommon/ImageWrite.h" +#include "VideoCommon/RenderBase.h" AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c) { @@ -20,17 +22,33 @@ bool AbstractTexture::Save(const std::string& filename, unsigned int level) // 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); + _assert_(!IsCompressedFormat(m_config.format)); + _assert_(level < m_config.levels); - auto result = level == 0 ? Map() : Map(level); + // 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); - if (!result.has_value()) - { + // Use a temporary staging texture for the download. Certainly not optimal, + // but this is not a frequently-executed code path.. + TextureConfig readback_texture_config(level_width, level_height, 1, 1, + AbstractTextureFormat::RGBA8, false); + auto readback_texture = + g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config); + if (!readback_texture) return false; - } - auto raw_data = result.value(); - return TextureToPng(raw_data.data, raw_data.stride, filename, raw_data.width, raw_data.height); + // Copy to the readback texture's buffer. + readback_texture->CopyFromTexture(this, 0, level); + readback_texture->Flush(); + + // Map it so we can encode it to the file. + if (!readback_texture->Map()) + return false; + + return TextureToPng(reinterpret_cast(readback_texture->GetMappedPointer()), + static_cast(readback_texture->GetMappedStride()), filename, level_width, + level_height); } std::optional AbstractTexture::Map() diff --git a/Source/Core/VideoCommon/AbstractTexture.h b/Source/Core/VideoCommon/AbstractTexture.h index d2ef2272fc..c18e1f17d3 100644 --- a/Source/Core/VideoCommon/AbstractTexture.h +++ b/Source/Core/VideoCommon/AbstractTexture.h @@ -17,8 +17,8 @@ class AbstractTexture public: explicit AbstractTexture(const TextureConfig& c); virtual ~AbstractTexture(); + virtual void Bind(unsigned int stage) = 0; - bool Save(const std::string& filename, unsigned int level); struct RawTextureInfo { @@ -43,6 +43,8 @@ public: virtual void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) = 0; + bool Save(const std::string& filename, unsigned int level); + static bool IsCompressedFormat(AbstractTextureFormat format); static size_t CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length); static size_t GetTexelSizeForFormat(AbstractTextureFormat format);