new-line that clang-format didn't fix
address some comments
This commit is contained in:
		| @@ -161,8 +161,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||
|             continue; | ||||
|         button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); | ||||
|         connect(button_map[button_id], &QPushButton::clicked, [=]() { | ||||
|             HandleClick( | ||||
|                 button_map[button_id], | ||||
|             HandleClick(button_map[button_id], | ||||
|                         [=](const Common::ParamPackage& params) { | ||||
|                             buttons_param[button_id] = params; | ||||
|                             // If the user closes the dialog, the changes are reverted in | ||||
| @@ -199,8 +198,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||
|             analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( | ||||
|                 Qt::CustomContextMenu); | ||||
|             connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() { | ||||
|                 HandleClick( | ||||
|                     analog_map_buttons[analog_id][sub_button_id], | ||||
|                 HandleClick(analog_map_buttons[analog_id][sub_button_id], | ||||
|                             [=](const Common::ParamPackage& params) { | ||||
|                                 SetAnalogButton(params, analogs_param[analog_id], | ||||
|                                                 analog_sub_buttons[sub_button_id]); | ||||
|   | ||||
| @@ -34,7 +34,8 @@ void DetachedTasks::AddTask(std::function<void()> task) { | ||||
|         std::unique_lock lock{instance->mutex}; | ||||
|         --instance->count; | ||||
|         std::notify_all_at_thread_exit(instance->cv, std::move(lock)); | ||||
|     }).detach(); | ||||
|     }) | ||||
|         .detach(); | ||||
| } | ||||
|  | ||||
| } // namespace Common | ||||
|   | ||||
| @@ -1,3 +1,8 @@ | ||||
| // Copyright 2019 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| @@ -6,17 +11,12 @@ namespace Common { | ||||
| void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) { | ||||
|     ASSERT(tex.size() == width * height * 4); | ||||
|     const u64 line_size = width * 4; | ||||
|     u8* temp_row = new u8[line_size]; | ||||
|     u32 offset_1; | ||||
|     u32 offset_2; | ||||
|     for (u64 line = 0; line < height / 2; line++) { | ||||
|         offset_1 = line * line_size; | ||||
|         offset_2 = (height - line - 1) * line_size; | ||||
|         const u32 offset_1 = line * line_size; | ||||
|         const u32 offset_2 = (height - line - 1) * line_size; | ||||
|         // Swap lines | ||||
|         std::memcpy(temp_row, &tex[offset_1], line_size); | ||||
|         std::memcpy(&tex[offset_1], &tex[offset_2], line_size); | ||||
|         std::memcpy(&tex[offset_2], temp_row, line_size); | ||||
|         std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size, | ||||
|                          tex.begin() + offset_2); | ||||
|     } | ||||
|     delete[] temp_row; | ||||
| } | ||||
| } // namespace Common | ||||
| @@ -1,3 +1,7 @@ | ||||
| // Copyright 2019 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <vector> | ||||
|   | ||||
| @@ -18,14 +18,11 @@ | ||||
| #include "core/cheats/cheats.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| <<<<<<< HEAD | ||||
| #include "core/dumping/backend.h" | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
| #include "core/dumping/ffmpeg_backend.h" | ||||
| #endif | ||||
| ======= | ||||
| #include "core/custom_tex_cache.h" | ||||
| >>>>>>> 387a49d7... fix crashes, add custom texture cache, load textures from load directory | ||||
| #include "core/gdbstub/gdbstub.h" | ||||
| #include "core/hle/kernel/client_port.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| @@ -102,6 +99,48 @@ System::ResultStatus System::SingleStep() { | ||||
|     return RunLoop(false); | ||||
| } | ||||
|  | ||||
| void System::PreloadCustomTextures() { | ||||
|     // Custom textures are currently stored as | ||||
|     // load/textures/[TitleID]/tex1_[width]x[height]_[64-bit hash]_[format].png | ||||
|     const std::string load_path = | ||||
|         fmt::format("{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|                     Kernel().GetCurrentProcess()->codeset->program_id); | ||||
|  | ||||
|     if (FileUtil::Exists(load_path)) { | ||||
|         FileUtil::FSTEntry texture_files; | ||||
|         FileUtil::ScanDirectoryTree(load_path, texture_files); | ||||
|         for (const auto& file : texture_files.children) { | ||||
|             if (file.isDirectory) | ||||
|                 continue; | ||||
|             if (file.virtualName.substr(0, 5) != "tex1_") | ||||
|                 continue; | ||||
|  | ||||
|             u32 width; | ||||
|             u32 height; | ||||
|             u64 hash; | ||||
|             u32 format; // unused | ||||
|             // TODO: more modern way of doing this | ||||
|             if (std::sscanf(file.virtualName.c_str(), "tex1_%ux%u_%llX_%u.png", &width, &height, | ||||
|                             &hash, &format) == 4) { | ||||
|                 u32 png_width; | ||||
|                 u32 png_height; | ||||
|                 std::vector<u8> decoded_png; | ||||
|  | ||||
|                 u32 lodepng_ret = | ||||
|                     lodepng::decode(decoded_png, png_width, png_height, file.physicalName); | ||||
|                 if (lodepng_ret) { | ||||
|                     LOG_CRITICAL(Render_OpenGL, "Failed to preload custom texture: {}", | ||||
|                                  lodepng_error_text(lodepng_ret)); | ||||
|                 } else { | ||||
|                     LOG_INFO(Render_OpenGL, "Preloaded custom texture from {}", file.physicalName); | ||||
|                     Common::FlipRGBA8Texture(decoded_png, png_width, png_height); | ||||
|                     custom_tex_cache->CacheTexture(hash, decoded_png, png_width, png_height); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | ||||
|     app_loader = Loader::GetLoader(filepath); | ||||
|     if (!app_loader) { | ||||
| @@ -152,18 +191,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||
|         } | ||||
|     } | ||||
|     cheat_engine = std::make_unique<Cheats::CheatEngine>(*this); | ||||
| <<<<<<< HEAD | ||||
|     u64 title_id{0}; | ||||
|     if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { | ||||
|         LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", | ||||
|                   static_cast<u32>(load_result)); | ||||
|     } | ||||
|     perf_stats = std::make_unique<PerfStats>(title_id); | ||||
| ======= | ||||
|     custom_tex_cache = std::make_unique<Core::CustomTexCache>(); | ||||
| <<<<<<< HEAD | ||||
| >>>>>>> 387a49d7... fix crashes, add custom texture cache, load textures from load directory | ||||
| ======= | ||||
|     if (Settings::values.preload_textures) { | ||||
|         // Custom textures are currently stored as | ||||
|         // load/textures/[TitleID]/tex1_[width]x[height]_[64-bit hash]_[format].png | ||||
| @@ -206,7 +240,8 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| >>>>>>> 015582b2... implement custom texture preload | ||||
|     if (Settings::values.preload_textures) | ||||
|         PreloadCustomTextures(); | ||||
|     status = ResultStatus::Success; | ||||
|     m_emu_window = &emu_window; | ||||
|     m_filepath = filepath; | ||||
| @@ -242,8 +277,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo | ||||
|  | ||||
|     timing = std::make_unique<Timing>(); | ||||
|  | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>( | ||||
|         *memory, *timing, [this] { PrepareReschedule(); }, system_mode); | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, | ||||
|                                                     [this] { PrepareReschedule(); }, system_mode); | ||||
|  | ||||
|     if (Settings::values.use_cpu_jit) { | ||||
| #ifdef ARCHITECTURE_x86_64 | ||||
| @@ -345,21 +380,20 @@ const Cheats::CheatEngine& System::CheatEngine() const { | ||||
|     return *cheat_engine; | ||||
| } | ||||
|  | ||||
| <<<<<<< HEAD | ||||
| VideoDumper::Backend& System::VideoDumper() { | ||||
|     return *video_dumper; | ||||
| } | ||||
|  | ||||
| const VideoDumper::Backend& System::VideoDumper() const { | ||||
|     return *video_dumper; | ||||
| ======= | ||||
| } | ||||
|  | ||||
| Core::CustomTexCache& System::CustomTexCache() { | ||||
|     return *custom_tex_cache; | ||||
| } | ||||
|  | ||||
| const Core::CustomTexCache& System::CustomTexCache() const { | ||||
|     return *custom_tex_cache; | ||||
| >>>>>>> 387a49d7... fix crashes, add custom texture cache, load textures from load directory | ||||
| } | ||||
|  | ||||
| void System::RegisterMiiSelector(std::shared_ptr<Frontend::MiiSelector> mii_selector) { | ||||
|   | ||||
| @@ -223,6 +223,8 @@ public: | ||||
|     /// Gets a const reference to the custom texture cache system | ||||
|     const Core::CustomTexCache& CustomTexCache() const; | ||||
|  | ||||
|     /// Handles loading all custom textures from disk into cache. | ||||
|     void PreloadCustomTextures(); | ||||
|     FrameLimiter frame_limiter; | ||||
|  | ||||
|     void SetStatus(ResultStatus new_status, const char* details = nullptr) { | ||||
|   | ||||
| @@ -1,10 +1,18 @@ | ||||
| // Copyright 2019 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <stdexcept> | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| #include "custom_tex_cache.h" | ||||
|  | ||||
| namespace Core { | ||||
| const bool CustomTexCache::IsTextureDumped(const u64 hash) { | ||||
| CustomTexCache::CustomTexCache() {} | ||||
|  | ||||
| CustomTexCache::~CustomTexCache() {} | ||||
|  | ||||
| bool CustomTexCache::IsTextureDumped(u64 hash) const { | ||||
|     return dumped_textures.find(hash) != dumped_textures.end(); | ||||
| } | ||||
|  | ||||
| @@ -12,7 +20,7 @@ void CustomTexCache::SetTextureDumped(const u64 hash) { | ||||
|     dumped_textures[hash] = true; | ||||
| } | ||||
|  | ||||
| const bool CustomTexCache::IsTextureCached(const u64 hash) { | ||||
| bool CustomTexCache::IsTextureCached(u64 hash) const { | ||||
|     return custom_textures.find(hash) != custom_textures.end(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,7 @@ | ||||
| // Copyright 2019 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <unordered_map> | ||||
| @@ -14,12 +18,15 @@ struct CustomTexInfo { | ||||
| // TODO: think of a better name for this class... | ||||
| class CustomTexCache { | ||||
| public: | ||||
|     const bool IsTextureDumped(const u64 hash); | ||||
|     void SetTextureDumped(const u64 hash); | ||||
|     CustomTexCache(); | ||||
|     ~CustomTexCache(); | ||||
|  | ||||
|     const bool IsTextureCached(const u64 hash); | ||||
|     bool IsTextureDumped(u64 hash) const; | ||||
|     void SetTextureDumped(u64 hash); | ||||
|  | ||||
|     bool IsTextureCached(u64 hash) const; | ||||
|     const CustomTexInfo& LookupTexture(const u64 hash); | ||||
|     void CacheTexture(const u64 hash, const std::vector<u8>& tex, u32 width, u32 height); | ||||
|     void CacheTexture(u64 hash, const std::vector<u8>& tex, u32 width, u32 height); | ||||
|  | ||||
| private: | ||||
|     std::unordered_map<u64, bool> dumped_textures; | ||||
|   | ||||
| @@ -1340,8 +1340,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||
|     case CecDataPathType::MboxData: | ||||
|     case CecDataPathType::MboxIcon: | ||||
|     case CecDataPathType::MboxTitle: | ||||
|     default: { | ||||
|     } | ||||
|     default: {} | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -41,8 +41,8 @@ public: | ||||
|         return s_instance; | ||||
|     } | ||||
|  | ||||
|     void StartPlayback( | ||||
|         const std::string& movie_file, std::function<void()> completion_callback = [] {}); | ||||
|     void StartPlayback(const std::string& movie_file, | ||||
|                        std::function<void()> completion_callback = [] {}); | ||||
|     void StartRecording(const std::string& movie_file); | ||||
|  | ||||
|     /// Prepare to override the clock before playing back movies | ||||
|   | ||||
| @@ -217,7 +217,8 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie | ||||
|             success_callback(); | ||||
|         else | ||||
|             failure_callback(); | ||||
|     }).detach(); | ||||
|     }) | ||||
|         .detach(); | ||||
| } | ||||
|  | ||||
| CalibrationConfigurationJob::CalibrationConfigurationJob( | ||||
| @@ -268,7 +269,8 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | ||||
|         complete_event.Wait(); | ||||
|         socket.Stop(); | ||||
|         worker_thread.join(); | ||||
|     }).detach(); | ||||
|     }) | ||||
|         .detach(); | ||||
| } | ||||
|  | ||||
| CalibrationConfigurationJob::~CalibrationConfigurationJob() { | ||||
|   | ||||
| @@ -17,8 +17,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) | ||||
|  | ||||
|     timing = std::make_unique<Core::Timing>(); | ||||
|     memory = std::make_unique<Memory::MemorySystem>(); | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>( | ||||
|         *memory, *timing, [] {}, 0); | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0); | ||||
|  | ||||
|     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); | ||||
|     page_table = &kernel->GetCurrentProcess()->vm_manager.page_table; | ||||
|   | ||||
| @@ -23,8 +23,7 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) { | ||||
| TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { | ||||
|     Core::Timing timing; | ||||
|     Memory::MemorySystem memory; | ||||
|     Kernel::KernelSystem kernel( | ||||
|         memory, timing, [] {}, 0); | ||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0); | ||||
|     auto [server, client] = kernel.CreateSessionPair(); | ||||
|     HLERequestContext context(kernel, std::move(server), nullptr); | ||||
|  | ||||
| @@ -236,8 +235,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||
| TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | ||||
|     Core::Timing timing; | ||||
|     Memory::MemorySystem memory; | ||||
|     Kernel::KernelSystem kernel( | ||||
|         memory, timing, [] {}, 0); | ||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0); | ||||
|     auto [server, client] = kernel.CreateSessionPair(); | ||||
|     HLERequestContext context(kernel, std::move(server), nullptr); | ||||
|  | ||||
|   | ||||
| @@ -13,8 +13,7 @@ | ||||
| TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | ||||
|     Core::Timing timing; | ||||
|     Memory::MemorySystem memory; | ||||
|     Kernel::KernelSystem kernel( | ||||
|         memory, timing, [] {}, 0); | ||||
|     Kernel::KernelSystem kernel(memory, timing, [] {}, 0); | ||||
|     SECTION("these regions should not be mapped on an empty process") { | ||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); | ||||
|   | ||||
| @@ -856,6 +856,81 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool CachedSurface::LoadCustomTextures(u64 tex_hash, Core::CustomTexInfo& tex_info, | ||||
|                                        Common::Rectangle<u32>& custom_rect) { | ||||
|     bool result = false; | ||||
|     auto& custom_tex_cache = Core::System::GetInstance().CustomTexCache(); | ||||
|     const std::string load_path = | ||||
|         fmt::format("{}textures/{:016X}/tex1_{}x{}_{:016X}_{}.png", | ||||
|                     FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|                     Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id, | ||||
|                     width, height, tex_hash, static_cast<u32>(pixel_format)); | ||||
|  | ||||
|     if (!custom_tex_cache.IsTextureCached(tex_hash)) { | ||||
|         if (FileUtil::Exists(load_path)) { | ||||
|             u32 lodepng_ret = | ||||
|                 lodepng::decode(tex_info.tex, tex_info.width, tex_info.height, load_path); | ||||
|             if (lodepng_ret) { | ||||
|                 LOG_CRITICAL(Render_OpenGL, "Failed to load custom texture: {}", | ||||
|                              lodepng_error_text(lodepng_ret)); | ||||
|             } else { | ||||
|                 LOG_INFO(Render_OpenGL, "Loaded custom texture from {}", load_path); | ||||
|                 Common::FlipRGBA8Texture(tex_info.tex, tex_info.width, tex_info.height); | ||||
|                 custom_tex_cache.CacheTexture(tex_hash, tex_info.tex, tex_info.width, | ||||
|                                               tex_info.height); | ||||
|                 result = true; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         tex_info = custom_tex_cache.LookupTexture(tex_hash); | ||||
|         result = true; | ||||
|     } | ||||
|  | ||||
|     if (result) { | ||||
|         custom_rect.left = (custom_rect.left / width) * tex_info.width; | ||||
|         custom_rect.top = (custom_rect.top / height) * tex_info.height; | ||||
|         custom_rect.right = (custom_rect.right / width) * tex_info.width; | ||||
|         custom_rect.bottom = (custom_rect.bottom / height) * tex_info.height; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool CachedSurface::GetDumpPath(u64 tex_hash, std::string& path) { | ||||
|     auto& custom_tex_cache = Core::System::GetInstance().CustomTexCache(); | ||||
|     path = | ||||
|         fmt::format("{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), | ||||
|                     Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); | ||||
|     if (!FileUtil::CreateFullPath(path)) { | ||||
|         LOG_ERROR(Render, "Unable to create {}", path); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     path += fmt::format("tex1_{}x{}_{:016X}_{}.png", width, height, tex_hash, | ||||
|                         static_cast<u32>(pixel_format)); | ||||
|     if (!custom_tex_cache.IsTextureDumped(tex_hash) && !FileUtil::Exists(path)) { | ||||
|         custom_tex_cache.SetTextureDumped(tex_hash); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| void CachedSurface::DumpTexture(GLuint target_tex, const std::string& dump_path) { | ||||
|     // Dump texture to RGBA8 and encode as PNG | ||||
|     LOG_INFO(Render_OpenGL, "Dumping texture to {}", dump_path); | ||||
|     std::vector<u8> decoded_texture; | ||||
|     decoded_texture.resize(width * height * 4); | ||||
|     glBindTexture(GL_TEXTURE_2D, target_tex); | ||||
|     glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &decoded_texture[0]); | ||||
|     glBindTexture(GL_TEXTURE_2D, 0); | ||||
|     Common::FlipRGBA8Texture(decoded_texture, width, height); | ||||
|     u32 png_error = lodepng::encode(dump_path, decoded_texture, width, height); | ||||
|     if (png_error) { | ||||
|         LOG_CRITICAL(Render_OpenGL, "Failed to save decoded texture! {}", | ||||
|                      lodepng_error_text(png_error)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); | ||||
| void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle, | ||||
|                                     GLuint draw_fb_handle) { | ||||
| @@ -871,9 +946,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|     bool dump_tex = false; | ||||
|     bool use_custom_tex = false; | ||||
|     std::string dump_path; // Has to be declared here for logging later | ||||
|     std::vector<u8> decoded_png; | ||||
|     u32 png_width = 0; | ||||
|     u32 png_height = 0; | ||||
|     Core::CustomTexInfo custom_tex_info; | ||||
|     u64 tex_hash = 0; | ||||
|     Common::Rectangle custom_rect = | ||||
|         rect; // Required for rect to function properly with custom textures | ||||
| @@ -881,56 +954,11 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|     if (Settings::values.dump_textures || Settings::values.custom_textures) | ||||
|         tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size); | ||||
|  | ||||
|     if (Settings::values.custom_textures) { | ||||
|         const std::string load_path = fmt::format( | ||||
|             "{}textures/{:016X}/tex1_{}x{}_{:016X}_{}.png", | ||||
|             FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|             Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id, width, | ||||
|             height, tex_hash, static_cast<u32>(pixel_format)); | ||||
|     if (Settings::values.custom_textures) | ||||
|         use_custom_tex = LoadCustomTextures(tex_hash, custom_tex_info, custom_rect); | ||||
|  | ||||
|         if (!custom_tex_cache.IsTextureCached(tex_hash)) { | ||||
|             if (FileUtil::Exists(load_path)) { | ||||
|                 u32 lodepng_ret = lodepng::decode(decoded_png, png_width, png_height, load_path); | ||||
|                 if (lodepng_ret) | ||||
|                     LOG_CRITICAL(Render_OpenGL, "Failed to load custom texture: {}", | ||||
|                                  lodepng_error_text(lodepng_ret)); | ||||
|                 else { | ||||
|                     LOG_INFO(Render_OpenGL, "Loaded custom texture from {}", load_path); | ||||
|                     Common::FlipRGBA8Texture(decoded_png, png_width, png_height); | ||||
|                     custom_tex_cache.CacheTexture(tex_hash, decoded_png, png_width, png_height); | ||||
|                     use_custom_tex = true; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             const auto custom_tex_info = custom_tex_cache.LookupTexture(tex_hash); | ||||
|             decoded_png = custom_tex_info.tex; | ||||
|             png_width = custom_tex_info.width; | ||||
|             png_height = custom_tex_info.height; | ||||
|             use_custom_tex = true; | ||||
|         } | ||||
|  | ||||
|         if (png_width && png_height) { | ||||
|             custom_rect.left = (custom_rect.left / width) * png_width; | ||||
|             custom_rect.top = (custom_rect.top / height) * png_height; | ||||
|             custom_rect.right = (custom_rect.right / width) * png_width; | ||||
|             custom_rect.bottom = (custom_rect.bottom / height) * png_height; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (Settings::values.dump_textures && !use_custom_tex) { | ||||
|         dump_path = fmt::format( | ||||
|             "{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), | ||||
|             Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); | ||||
|         if (!FileUtil::CreateFullPath(dump_path)) | ||||
|             LOG_ERROR(Render, "Unable to create {}", dump_path); | ||||
|  | ||||
|         dump_path += fmt::format("tex1_{}x{}_{:016X}_{}.png", width, height, tex_hash, | ||||
|                                  static_cast<u32>(pixel_format)); | ||||
|         if (!custom_tex_cache.IsTextureDumped(tex_hash) && !FileUtil::Exists(dump_path)) { | ||||
|             custom_tex_cache.SetTextureDumped(tex_hash); | ||||
|             dump_tex = true; | ||||
|         } | ||||
|     } | ||||
|     if (Settings::values.dump_textures && !use_custom_tex) | ||||
|         dump_tex = GetDumpPath(tex_hash, dump_path); | ||||
|  | ||||
|     // Load data from memory to the surface | ||||
|     GLint x0 = static_cast<GLint>(custom_rect.left); | ||||
| @@ -950,7 +978,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|         unscaled_tex.Create(); | ||||
|         if (use_custom_tex) { | ||||
|             AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                    png_width, png_height); | ||||
|                                    custom_tex_info.width, custom_tex_info.height); | ||||
|         } else { | ||||
|             AllocateSurfaceTexture(unscaled_tex.handle, tuple, custom_rect.GetWidth(), | ||||
|                                    custom_rect.GetHeight()); | ||||
| @@ -975,36 +1003,22 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|                         &gl_buffer[buffer_offset]); | ||||
|     } else { | ||||
|         if (res_scale == 1) { | ||||
|             AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8), png_width, | ||||
|                                    png_height); | ||||
|             AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                    custom_tex_info.width, custom_tex_info.height); | ||||
|             cur_state.texture_units[0].texture_2d = texture.handle; | ||||
|             cur_state.Apply(); | ||||
|         } | ||||
|         // always going to be using rgba8 | ||||
|         glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(png_width)); | ||||
|         glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(custom_tex_info.width)); | ||||
|  | ||||
|         glActiveTexture(GL_TEXTURE0); | ||||
|         glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, png_width, png_height, GL_RGBA, GL_UNSIGNED_BYTE, | ||||
|                         decoded_png.data()); | ||||
|         glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, custom_tex_info.width, custom_tex_info.height, | ||||
|                         GL_RGBA, GL_UNSIGNED_BYTE, custom_tex_info.tex.data()); | ||||
|     } | ||||
|  | ||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||
|     if (dump_tex) { | ||||
|         // Dump texture to RGBA8 and encode as PNG | ||||
|         LOG_INFO(Render_OpenGL, "Dumping texture to {}", dump_path); | ||||
|         std::vector<u8> decoded_texture; | ||||
|         decoded_texture.resize(width * height * 4); | ||||
|         glBindTexture(GL_TEXTURE_2D, target_tex); | ||||
|         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &decoded_texture[0]); | ||||
|         glBindTexture(GL_TEXTURE_2D, 0); | ||||
|         Common::FlipRGBA8Texture(decoded_texture, width, height); | ||||
|         u32 png_error = lodepng::encode(dump_path, decoded_texture, width, height); | ||||
|         if (png_error) { | ||||
|             LOG_CRITICAL(Render_OpenGL, "Failed to save decoded texture! {}", | ||||
|                          lodepng_error_text(png_error)); | ||||
|         } | ||||
|         custom_tex_cache.SetTextureDumped(tex_hash); | ||||
|     } | ||||
|     if (dump_tex) | ||||
|         DumpTexture(target_tex, dump_path); | ||||
|  | ||||
|     cur_state.texture_units[0].texture_2d = old_tex; | ||||
|     cur_state.Apply(); | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/math_util.h" | ||||
| #include "core/custom_tex_cache.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/regs_framebuffer.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| @@ -377,6 +378,12 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface | ||||
|     void LoadGLBuffer(PAddr load_start, PAddr load_end); | ||||
|     void FlushGLBuffer(PAddr flush_start, PAddr flush_end); | ||||
|  | ||||
|     // Custom texture loading and dumping | ||||
|     bool LoadCustomTextures(u64 tex_hash, Core::CustomTexInfo& tex_info, | ||||
|                             Common::Rectangle<u32>& custom_rect); | ||||
|     bool GetDumpPath(u64 tex_hash, std::string& path); | ||||
|     void DumpTexture(GLuint target_tex, const std::string& dump_path); | ||||
|  | ||||
|     // Upload/Download data in gl_buffer in/to this surface's texture | ||||
|     void UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle, | ||||
|                          GLuint draw_fb_handle); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user