mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	new-line that clang-format didn't fix
address some comments
This commit is contained in:
		
							parent
							
								
									59b475a4b9
								
							
						
					
					
						commit
						5940361b81
					
				
					 16 changed files with 210 additions and 138 deletions
				
			
		|  | @ -161,16 +161,15 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|             continue; | ||||
|         button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); | ||||
|         connect(button_map[button_id], &QPushButton::clicked, [=]() { | ||||
|             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
 | ||||
|                     // `GMainWindow::OnConfigure()`
 | ||||
|                     ApplyConfiguration(); | ||||
|                     Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                 }, | ||||
|                 InputCommon::Polling::DeviceType::Button); | ||||
|             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
 | ||||
|                             // `GMainWindow::OnConfigure()`
 | ||||
|                             ApplyConfiguration(); | ||||
|                             Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                         }, | ||||
|                         InputCommon::Polling::DeviceType::Button); | ||||
|         }); | ||||
|         connect(button_map[button_id], &QPushButton::customContextMenuRequested, | ||||
|                 [=](const QPoint& menu_location) { | ||||
|  | @ -199,15 +198,14 @@ 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], | ||||
|                     [=](const Common::ParamPackage& params) { | ||||
|                         SetAnalogButton(params, analogs_param[analog_id], | ||||
|                                         analog_sub_buttons[sub_button_id]); | ||||
|                         ApplyConfiguration(); | ||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                     }, | ||||
|                     InputCommon::Polling::DeviceType::Button); | ||||
|                 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]); | ||||
|                                 ApplyConfiguration(); | ||||
|                                 Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                             }, | ||||
|                             InputCommon::Polling::DeviceType::Button); | ||||
|             }); | ||||
|             connect(analog_map_buttons[analog_id][sub_button_id], | ||||
|                     &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { | ||||
|  |  | |||
|  | @ -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
 | ||||
| } // 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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue