diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index fde0d4632..229f60d72 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include Log_SetChannel(HostDisplay); @@ -277,22 +278,15 @@ std::tuple HostDisplay::ConvertWindowCoordinatesToDisplayCoordinates(s return std::make_tuple(static_cast(display_x), static_cast(display_y)); } -bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, - const char* filename, bool clear_alpha /* = true */, bool flip_y /* = false */, - u32 resize_width /* = 0 */, u32 resize_height /* = 0 */) +static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp, + bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height, + std::vector texture_data, u32 texture_data_stride) { - std::vector texture_data(width * height); - u32 texture_data_stride = sizeof(u32) * width; - if (!DownloadTexture(texture_handle, x, y, width, height, texture_data.data(), texture_data_stride)) - { - Log_ErrorPrintf("Texture download failed"); - return false; - } - const char* extension = std::strrchr(filename, '.'); + const char* extension = std::strrchr(filename.c_str(), '.'); if (!extension) { - Log_ErrorPrintf("Unable to determine file extension for '%s'", filename); + Log_ErrorPrintf("Unable to determine file extension for '%s'", filename.c_str()); return false; } @@ -333,13 +327,6 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u texture_data_stride = resized_texture_stride; } - auto fp = FileSystem::OpenManagedCFile(filename, "wb"); - if (!fp) - { - Log_ErrorPrintf("Can't open file '%s': errno %d", filename, errno); - return false; - } - const auto write_func = [](void* context, void* data, int size) { std::fwrite(data, 1, size, static_cast(context)); }; @@ -350,30 +337,62 @@ bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u result = (stbi_write_png_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), texture_data_stride) != 0); } - else if (StringUtil::Strcasecmp(filename, ".jpg") == 0) + else if (StringUtil::Strcasecmp(filename.c_str(), ".jpg") == 0) { result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), 95) != 0); } - else if (StringUtil::Strcasecmp(filename, ".tga") == 0) + else if (StringUtil::Strcasecmp(filename.c_str(), ".tga") == 0) { result = (stbi_write_tga_to_func(write_func, fp.get(), width, height, 4, texture_data.data()) != 0); } - else if (StringUtil::Strcasecmp(filename, ".bmp") == 0) + else if (StringUtil::Strcasecmp(filename.c_str(), ".bmp") == 0) { result = (stbi_write_bmp_to_func(write_func, fp.get(), width, height, 4, texture_data.data()) != 0); } if (!result) { - Log_ErrorPrintf("Unknown extension in filename '%s' or save error: '%s'", filename, extension); + Log_ErrorPrintf("Unknown extension in filename '%s' or save error: '%s'", filename.c_str(), extension); return false; } return true; } +bool HostDisplay::WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, + const char* filename, bool clear_alpha /* = true */, bool flip_y /* = false */, + u32 resize_width /* = 0 */, u32 resize_height /* = 0 */, + bool compress_on_thread /* = false */) +{ + std::vector texture_data(width * height); + u32 texture_data_stride = sizeof(u32) * width; + if (!DownloadTexture(texture_handle, x, y, width, height, texture_data.data(), texture_data_stride)) + { + Log_ErrorPrintf("Texture download failed"); + return false; + } + + auto fp = FileSystem::OpenManagedCFile(filename, "wb"); + if (!fp) + { + Log_ErrorPrintf("Can't open file '%s': errno %d", filename, errno); + return false; + } + + if (!compress_on_thread) + { + return CompressAndWriteTextureToFile(width, height, filename, std::move(fp), clear_alpha, flip_y, resize_width, + resize_height, std::move(texture_data), texture_data_stride); + } + + std::thread compress_thread(CompressAndWriteTextureToFile, width, height, filename, std::move(fp), clear_alpha, + flip_y, resize_width, resize_height, std::move(texture_data), texture_data_stride); + compress_thread.detach(); + return true; +} + bool HostDisplay::WriteDisplayTextureToFile(const char* filename, bool full_resolution /* = true */, - bool apply_aspect_ratio /* = true */) + bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = false */) { if (!m_display_texture_handle || m_display_texture_format != HostDisplayPixelFormat::RGBA8) return false; @@ -436,7 +455,7 @@ bool HostDisplay::WriteDisplayTextureToFile(const char* filename, bool full_reso return WriteTextureToFile(m_display_texture_handle, m_display_texture_view_x, read_y, m_display_texture_view_width, read_height, filename, true, flip_y, static_cast(resize_width), - static_cast(resize_height)); + static_cast(resize_height), compress_on_thread); } bool HostDisplay::WriteDisplayTextureToBuffer(std::vector* buffer, u32 resize_width /* = 0 */, diff --git a/src/core/host_display.h b/src/core/host_display.h index 5bc06121f..7c9e5bf3c 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -195,10 +195,12 @@ public: /// Helper function to save texture data to a PNG. If flip_y is set, the image will be flipped aka OpenGL. bool WriteTextureToFile(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, const char* filename, - bool clear_alpha = true, bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0); + bool clear_alpha = true, bool flip_y = false, u32 resize_width = 0, u32 resize_height = 0, + bool compress_on_thread = false); /// Helper function to save current display texture to PNG. - bool WriteDisplayTextureToFile(const char* filename, bool full_resolution = true, bool apply_aspect_ratio = true); + bool WriteDisplayTextureToFile(const char* filename, bool full_resolution = true, bool apply_aspect_ratio = true, + bool compress_on_thread = false); /// Helper function to save current display texture to a buffer. bool WriteDisplayTextureToBuffer(std::vector* buffer, u32 resize_width = 0, u32 resize_height = 0,