implement custom texture preload
This commit is contained in:
		| @@ -165,6 +165,8 @@ void Config::ReadValues() { | ||||
|     // Utility | ||||
|     Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false); | ||||
|     Settings::values.custom_textures = sdl2_config->GetBoolean("Utility", "custom_textures", false); | ||||
|     Settings::values.preload_textures = | ||||
|         sdl2_config->GetBoolean("Utility", "preload_textures", false); | ||||
|  | ||||
|     // Audio | ||||
|     Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false); | ||||
|   | ||||
| @@ -186,6 +186,10 @@ dump_textures = | ||||
| # 0 (default): Off, 1: On | ||||
| custom_textures = | ||||
|  | ||||
| # Loads all custom textures into memory before booting. | ||||
| # 0 (default): Off, 1: On | ||||
| preload_textures = | ||||
|  | ||||
| [Audio] | ||||
| # Whether or not to enable DSP LLE | ||||
| # 0 (default): No, 1: Yes | ||||
|   | ||||
| @@ -17,8 +17,6 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | ||||
|     ui->setupUi(this); | ||||
|     SetConfiguration(); | ||||
|  | ||||
|     ui->layoutBox->setEnabled(!Settings::values.custom_layout); | ||||
|  | ||||
|     ui->hw_renderer_group->setEnabled(ui->toggle_hw_renderer->isChecked()); | ||||
|     connect(ui->toggle_hw_renderer, &QCheckBox::toggled, ui->hw_renderer_group, | ||||
|             &QWidget::setEnabled); | ||||
| @@ -36,21 +34,6 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | ||||
|         } | ||||
|     }); | ||||
| #endif | ||||
|  | ||||
|     connect(ui->render_3d_combobox, | ||||
|             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||||
|             [this](int currentIndex) { | ||||
|                 updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex) == | ||||
|                               Settings::StereoRenderOption::Anaglyph); | ||||
|             }); | ||||
|  | ||||
|     connect(ui->bg_button, &QPushButton::clicked, this, [this] { | ||||
|         const QColor new_bg_color = QColorDialog::getColor(bg_color); | ||||
|         if (!new_bg_color.isValid()) { | ||||
|             return; | ||||
|         } | ||||
|         UpdateBackgroundColorButton(new_bg_color); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| ConfigureGraphics::~ConfigureGraphics() = default; | ||||
| @@ -60,15 +43,6 @@ void ConfigureGraphics::SetConfiguration() { | ||||
|     ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader); | ||||
|     ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul); | ||||
|     ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit); | ||||
|     ui->resolution_factor_combobox->setCurrentIndex(Settings::values.resolution_factor); | ||||
|     ui->render_3d_combobox->setCurrentIndex(static_cast<int>(Settings::values.render_3d)); | ||||
|     ui->factor_3d->setValue(Settings::values.factor_3d); | ||||
|     updateShaders(Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph); | ||||
|     ui->toggle_linear_filter->setChecked(Settings::values.filter_mode); | ||||
|     ui->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option)); | ||||
|     ui->swap_screen->setChecked(Settings::values.swap_screen); | ||||
|     UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, | ||||
|                                                  Settings::values.bg_blue)); | ||||
| } | ||||
|  | ||||
| void ConfigureGraphics::ApplyConfiguration() { | ||||
| @@ -76,49 +50,6 @@ void ConfigureGraphics::ApplyConfiguration() { | ||||
|     Settings::values.use_hw_shader = ui->toggle_hw_shader->isChecked(); | ||||
|     Settings::values.shaders_accurate_mul = ui->toggle_accurate_mul->isChecked(); | ||||
|     Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); | ||||
|     Settings::values.resolution_factor = | ||||
|         static_cast<u16>(ui->resolution_factor_combobox->currentIndex()); | ||||
|     Settings::values.render_3d = | ||||
|         static_cast<Settings::StereoRenderOption>(ui->render_3d_combobox->currentIndex()); | ||||
|     Settings::values.factor_3d = ui->factor_3d->value(); | ||||
|     Settings::values.pp_shader_name = | ||||
|         ui->shader_combobox->itemText(ui->shader_combobox->currentIndex()).toStdString(); | ||||
|     Settings::values.filter_mode = ui->toggle_linear_filter->isChecked(); | ||||
|     Settings::values.layout_option = | ||||
|         static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex()); | ||||
|     Settings::values.swap_screen = ui->swap_screen->isChecked(); | ||||
|     Settings::values.dump_textures = ui->toggle_dump_textures->isChecked(); | ||||
|     Settings::values.custom_textures = ui->toggle_custom_textures->isChecked(); | ||||
|     Settings::values.bg_red = static_cast<float>(bg_color.redF()); | ||||
|     Settings::values.bg_green = static_cast<float>(bg_color.greenF()); | ||||
|     Settings::values.bg_blue = static_cast<float>(bg_color.blueF()); | ||||
| } | ||||
|  | ||||
| void ConfigureGraphics::updateShaders(bool anaglyph) { | ||||
|     ui->shader_combobox->clear(); | ||||
|  | ||||
|     if (anaglyph) | ||||
|         ui->shader_combobox->addItem("dubois (builtin)"); | ||||
|     else | ||||
|         ui->shader_combobox->addItem("none (builtin)"); | ||||
|  | ||||
|     ui->shader_combobox->setCurrentIndex(0); | ||||
|  | ||||
|     for (const auto& shader : OpenGL::GetPostProcessingShaderList(anaglyph)) { | ||||
|         ui->shader_combobox->addItem(QString::fromStdString(shader)); | ||||
|         if (Settings::values.pp_shader_name == shader) | ||||
|             ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ConfigureGraphics::UpdateBackgroundColorButton(const QColor& color) { | ||||
|     bg_color = color; | ||||
|  | ||||
|     QPixmap pixmap(ui->bg_button->size()); | ||||
|     pixmap.fill(bg_color); | ||||
|  | ||||
|     const QIcon color_icon(pixmap); | ||||
|     ui->bg_button->setIcon(color_icon); | ||||
| } | ||||
|  | ||||
| void ConfigureGraphics::RetranslateUI() { | ||||
|   | ||||
| @@ -354,6 +354,16 @@ | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QCheckBox" name="toggle_preload_textures"> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>Load all custom textures into memory on boot, instead of loading them when the game requires them.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Preload Custom Textures</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|   | ||||
| @@ -161,15 +161,16 @@ 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) { | ||||
| @@ -198,14 +199,15 @@ 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) { | ||||
|   | ||||
| @@ -84,6 +84,8 @@ add_library(common STATIC | ||||
|     swap.h | ||||
|     telemetry.cpp | ||||
|     telemetry.h | ||||
|     texture.cpp | ||||
|     texture.h | ||||
|     thread.cpp | ||||
|     thread.h | ||||
|     thread_queue_list.h | ||||
|   | ||||
| @@ -34,8 +34,7 @@ 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 | ||||
|   | ||||
							
								
								
									
										22
									
								
								src/common/texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/common/texture.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #include <vector> | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| 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; | ||||
|         // 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); | ||||
|     } | ||||
|     delete[] temp_row; | ||||
| } | ||||
| } // namespace Common | ||||
							
								
								
									
										8
									
								
								src/common/texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/common/texture.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Common { | ||||
| void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height); | ||||
| } | ||||
| @@ -460,7 +460,7 @@ endif() | ||||
| create_target_directory_groups(core) | ||||
|  | ||||
| target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) | ||||
| target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives) | ||||
| target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives lodepng) | ||||
| if (ENABLE_WEB_SERVICE) | ||||
|     target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) | ||||
|     target_link_libraries(core PRIVATE web_service) | ||||
|   | ||||
| @@ -4,10 +4,12 @@ | ||||
|  | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| #include <lodepng.h> | ||||
| #include "audio_core/dsp_interface.h" | ||||
| #include "audio_core/hle/hle.h" | ||||
| #include "audio_core/lle/lle.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/texture.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #ifdef ARCHITECTURE_x86_64 | ||||
| #include "core/arm/dynarmic/arm_dynarmic.h" | ||||
| @@ -159,7 +161,52 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||
|     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 | ||||
|         const std::string load_path = | ||||
|             fmt::format("{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|                         process->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); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| >>>>>>> 015582b2... implement custom texture preload | ||||
|     status = ResultStatus::Success; | ||||
|     m_emu_window = &emu_window; | ||||
|     m_filepath = filepath; | ||||
| @@ -195,8 +242,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 | ||||
|   | ||||
| @@ -1340,7 +1340,8 @@ 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 | ||||
|   | ||||
| @@ -172,6 +172,7 @@ struct Values { | ||||
|  | ||||
|     bool dump_textures; | ||||
|     bool custom_textures; | ||||
|     bool preload_textures; | ||||
|  | ||||
|     // Audio | ||||
|     bool enable_dsp_lle; | ||||
|   | ||||
| @@ -217,8 +217,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie | ||||
|             success_callback(); | ||||
|         else | ||||
|             failure_callback(); | ||||
|     }) | ||||
|         .detach(); | ||||
|     }).detach(); | ||||
| } | ||||
|  | ||||
| CalibrationConfigurationJob::CalibrationConfigurationJob( | ||||
| @@ -269,8 +268,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | ||||
|         complete_event.Wait(); | ||||
|         socket.Stop(); | ||||
|         worker_thread.join(); | ||||
|     }) | ||||
|         .detach(); | ||||
|     }).detach(); | ||||
| } | ||||
|  | ||||
| CalibrationConfigurationJob::~CalibrationConfigurationJob() { | ||||
|   | ||||
| @@ -17,7 +17,8 @@ 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,7 +23,8 @@ 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); | ||||
|  | ||||
| @@ -235,7 +236,8 @@ 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,7 +13,8 @@ | ||||
| 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); | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
| #include "common/math_util.h" | ||||
| #include "common/microprofile.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "common/texture.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "core/core.h" | ||||
| #include "core/custom_tex_cache.h" | ||||
| @@ -855,25 +856,6 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| // TODO: move this function to a better place | ||||
| void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) { | ||||
|     ASSERT(tex.size() == width * height * 4); | ||||
|     const u64 line_size = width * 4; | ||||
|     // Thanks MSVC for not being able to make variable length arrays | ||||
|     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; | ||||
|         // 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); | ||||
|     } | ||||
|     delete[] temp_row; | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| @@ -893,7 +875,8 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|     u32 png_width = 0; | ||||
|     u32 png_height = 0; | ||||
|     u64 tex_hash = 0; | ||||
|     Common::Rectangle custom_rect = rect; // Required for rect to function properly with custom textures | ||||
|     Common::Rectangle custom_rect = | ||||
|         rect; // Required for rect to function properly with custom textures | ||||
|  | ||||
|     if (Settings::values.dump_textures || Settings::values.custom_textures) | ||||
|         tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size); | ||||
| @@ -913,7 +896,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|                                  lodepng_error_text(lodepng_ret)); | ||||
|                 else { | ||||
|                     LOG_INFO(Render_OpenGL, "Loaded custom texture from {}", load_path); | ||||
|                     FlipRGBA8Texture(decoded_png, png_width, png_height); | ||||
|                     Common::FlipRGBA8Texture(decoded_png, png_width, png_height); | ||||
|                     custom_tex_cache.CacheTexture(tex_hash, decoded_png, png_width, png_height); | ||||
|                     use_custom_tex = true; | ||||
|                 } | ||||
| @@ -1014,7 +997,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|         glBindTexture(GL_TEXTURE_2D, target_tex); | ||||
|         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &decoded_texture[0]); | ||||
|         glBindTexture(GL_TEXTURE_2D, 0); | ||||
|         FlipRGBA8Texture(decoded_texture, width, height); | ||||
|         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! {}", | ||||
| @@ -1034,8 +1017,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r | ||||
|         scaled_rect.bottom *= res_scale; | ||||
|  | ||||
|         BlitTextures(unscaled_tex.handle, {0, custom_rect.GetHeight(), custom_rect.GetWidth(), 0}, | ||||
|                      texture.handle, | ||||
|                      scaled_rect, type, read_fb_handle, draw_fb_handle); | ||||
|                      texture.handle, scaled_rect, type, read_fb_handle, draw_fb_handle); | ||||
|     } | ||||
|  | ||||
|     InvalidateAllWatcher(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Khangaroo
					Khangaroo