fix crashes, add custom texture cache, load textures from load directory
This commit is contained in:
parent
f866b2a917
commit
6d90c42a79
|
@ -164,6 +164,7 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false);
|
Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false);
|
||||||
|
Settings::values.custom_textures = sdl2_config->GetBoolean("Utility", "custom_textures", false);
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);
|
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);
|
||||||
|
|
|
@ -182,6 +182,10 @@ swap_screen =
|
||||||
# 0 (default): Off, 1: On
|
# 0 (default): Off, 1: On
|
||||||
dump_textures =
|
dump_textures =
|
||||||
|
|
||||||
|
# Reads PNG files from load/textures/[Title ID]/ and replaces textures.
|
||||||
|
# 0 (default): Off, 1: On
|
||||||
|
custom_textures =
|
||||||
|
|
||||||
[Audio]
|
[Audio]
|
||||||
# Whether or not to enable DSP LLE
|
# Whether or not to enable DSP LLE
|
||||||
# 0 (default): No, 1: Yes
|
# 0 (default): No, 1: Yes
|
||||||
|
|
|
@ -231,9 +231,11 @@ void Config::ReadControlValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::ReadUtilityValues() {
|
void Config::ReadUtilityValues() {
|
||||||
|
|
||||||
qt_config->beginGroup("Utility");
|
qt_config->beginGroup("Utility");
|
||||||
|
|
||||||
Settings::values.dump_textures = ReadSetting("dump_textures", false).toBool();
|
Settings::values.dump_textures = ReadSetting("dump_textures", false).toBool();
|
||||||
|
Settings::values.custom_textures = ReadSetting("custom_textures", false).toBool();
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,6 +706,7 @@ void Config::SaveUtilityValues() {
|
||||||
qt_config->beginGroup("Utility");
|
qt_config->beginGroup("Utility");
|
||||||
|
|
||||||
WriteSetting("dump_textures", Settings::values.dump_textures, false);
|
WriteSetting("dump_textures", Settings::values.dump_textures, false);
|
||||||
|
WriteSetting("custom_textures", Settings::values.custom_textures, false);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||||
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
|
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
|
||||||
Settings::values.swap_screen = ui->swap_screen->isChecked();
|
Settings::values.swap_screen = ui->swap_screen->isChecked();
|
||||||
Settings::values.dump_textures = ui->toggle_dump_textures->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_red = static_cast<float>(bg_color.redF());
|
||||||
Settings::values.bg_green = static_cast<float>(bg_color.greenF());
|
Settings::values.bg_green = static_cast<float>(bg_color.greenF());
|
||||||
Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
|
Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
|
||||||
|
|
|
@ -334,6 +334,16 @@
|
||||||
<string>Utility</string>
|
<string>Utility</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_custom_textures">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Replace textures with PNG files.</p><p>Textures are loaded from load/textures/[Title ID]/.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Custom Textures (Hardware Renderer only)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_dump_textures">
|
<widget class="QCheckBox" name="toggle_dump_textures">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
@ -347,19 +357,6 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#define DLL_DIR "external_dlls"
|
#define DLL_DIR "external_dlls"
|
||||||
#define SHADER_DIR "shaders"
|
#define SHADER_DIR "shaders"
|
||||||
#define DUMP_DIR "dump"
|
#define DUMP_DIR "dump"
|
||||||
|
#define LOAD_DIR "load"
|
||||||
|
|
||||||
// Filenames
|
// Filenames
|
||||||
// Files in the directory returned by GetUserPath(UserPath::LogDir)
|
// Files in the directory returned by GetUserPath(UserPath::LogDir)
|
||||||
|
|
|
@ -713,6 +713,7 @@ void SetUserPath(const std::string& path) {
|
||||||
g_paths.emplace(UserPath::DLLDir, user_path + DLL_DIR DIR_SEP);
|
g_paths.emplace(UserPath::DLLDir, user_path + DLL_DIR DIR_SEP);
|
||||||
g_paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
|
g_paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
|
||||||
g_paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
|
g_paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
|
||||||
|
g_paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& GetUserPath(UserPath path) {
|
const std::string& GetUserPath(UserPath path) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ enum class UserPath {
|
||||||
ConfigDir,
|
ConfigDir,
|
||||||
DLLDir,
|
DLLDir,
|
||||||
DumpDir,
|
DumpDir,
|
||||||
|
LoadDir,
|
||||||
LogDir,
|
LogDir,
|
||||||
NANDDir,
|
NANDDir,
|
||||||
RootDir,
|
RootDir,
|
||||||
|
|
|
@ -36,6 +36,8 @@ add_library(core STATIC
|
||||||
core.h
|
core.h
|
||||||
core_timing.cpp
|
core_timing.cpp
|
||||||
core_timing.h
|
core_timing.h
|
||||||
|
custom_tex_cache.cpp
|
||||||
|
custom_tex_cache.h
|
||||||
dumping/backend.cpp
|
dumping/backend.cpp
|
||||||
dumping/backend.h
|
dumping/backend.h
|
||||||
file_sys/archive_backend.cpp
|
file_sys/archive_backend.cpp
|
||||||
|
|
|
@ -16,10 +16,14 @@
|
||||||
#include "core/cheats/cheats.h"
|
#include "core/cheats/cheats.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
<<<<<<< HEAD
|
||||||
#include "core/dumping/backend.h"
|
#include "core/dumping/backend.h"
|
||||||
#ifdef ENABLE_FFMPEG_VIDEO_DUMPER
|
#ifdef ENABLE_FFMPEG_VIDEO_DUMPER
|
||||||
#include "core/dumping/ffmpeg_backend.h"
|
#include "core/dumping/ffmpeg_backend.h"
|
||||||
#endif
|
#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/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -146,12 +150,16 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
||||||
|
<<<<<<< HEAD
|
||||||
u64 title_id{0};
|
u64 title_id{0};
|
||||||
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
||||||
static_cast<u32>(load_result));
|
static_cast<u32>(load_result));
|
||||||
}
|
}
|
||||||
perf_stats = std::make_unique<PerfStats>(title_id);
|
perf_stats = std::make_unique<PerfStats>(title_id);
|
||||||
|
=======
|
||||||
|
custom_tex_cache = std::make_unique<Core::CustomTexCache>();
|
||||||
|
>>>>>>> 387a49d7... fix crashes, add custom texture cache, load textures from load directory
|
||||||
status = ResultStatus::Success;
|
status = ResultStatus::Success;
|
||||||
m_emu_window = &emu_window;
|
m_emu_window = &emu_window;
|
||||||
m_filepath = filepath;
|
m_filepath = filepath;
|
||||||
|
@ -290,12 +298,21 @@ const Cheats::CheatEngine& System::CheatEngine() const {
|
||||||
return *cheat_engine;
|
return *cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
VideoDumper::Backend& System::VideoDumper() {
|
VideoDumper::Backend& System::VideoDumper() {
|
||||||
return *video_dumper;
|
return *video_dumper;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VideoDumper::Backend& System::VideoDumper() const {
|
const VideoDumper::Backend& System::VideoDumper() const {
|
||||||
return *video_dumper;
|
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) {
|
void System::RegisterMiiSelector(std::shared_ptr<Frontend::MiiSelector> mii_selector) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/custom_tex_cache.h"
|
||||||
#include "core/frontend/applets/mii_selector.h"
|
#include "core/frontend/applets/mii_selector.h"
|
||||||
#include "core/frontend/applets/swkbd.h"
|
#include "core/frontend/applets/swkbd.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
@ -216,7 +217,12 @@ public:
|
||||||
/// Gets a const reference to the video dumper backend
|
/// Gets a const reference to the video dumper backend
|
||||||
const VideoDumper::Backend& VideoDumper() const;
|
const VideoDumper::Backend& VideoDumper() const;
|
||||||
|
|
||||||
std::unique_ptr<PerfStats> perf_stats;
|
/// Gets a reference to the custom texture cache system
|
||||||
|
Core::CustomTexCache& CustomTexCache();
|
||||||
|
|
||||||
|
/// Gets a const reference to the custom texture cache system
|
||||||
|
const Core::CustomTexCache& CustomTexCache() const;
|
||||||
|
|
||||||
FrameLimiter frame_limiter;
|
FrameLimiter frame_limiter;
|
||||||
|
|
||||||
void SetStatus(ResultStatus new_status, const char* details = nullptr) {
|
void SetStatus(ResultStatus new_status, const char* details = nullptr) {
|
||||||
|
@ -289,6 +295,9 @@ private:
|
||||||
/// Video dumper backend
|
/// Video dumper backend
|
||||||
std::unique_ptr<VideoDumper::Backend> video_dumper;
|
std::unique_ptr<VideoDumper::Backend> video_dumper;
|
||||||
|
|
||||||
|
/// Custom texture cache system
|
||||||
|
std::unique_ptr<Core::CustomTexCache> custom_tex_cache;
|
||||||
|
|
||||||
/// RPC Server for scripting support
|
/// RPC Server for scripting support
|
||||||
std::unique_ptr<RPC::RPCServer> rpc_server;
|
std::unique_ptr<RPC::RPCServer> rpc_server;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "custom_tex_cache.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
const bool CustomTexCache::IsTextureDumped(const u64 hash) {
|
||||||
|
return dumped_textures.find(hash) != dumped_textures.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomTexCache::SetTextureDumped(const u64 hash) {
|
||||||
|
dumped_textures[hash] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool CustomTexCache::IsTextureCached(const u64 hash) {
|
||||||
|
return custom_textures.find(hash) != custom_textures.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomTexInfo& CustomTexCache::LookupTexture(const u64 hash) {
|
||||||
|
return custom_textures.at(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomTexCache::CacheTexture(const u64 hash, const std::vector<u8>& tex, u32 width,
|
||||||
|
u32 height) {
|
||||||
|
custom_textures[hash] = {width, height, tex};
|
||||||
|
}
|
||||||
|
} // namespace Core
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
struct CustomTexInfo {
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
std::vector<u8> tex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: think of a better name for this class...
|
||||||
|
class CustomTexCache {
|
||||||
|
public:
|
||||||
|
const bool IsTextureDumped(const u64 hash);
|
||||||
|
void SetTextureDumped(const u64 hash);
|
||||||
|
|
||||||
|
const bool IsTextureCached(const u64 hash);
|
||||||
|
const CustomTexInfo& LookupTexture(const u64 hash);
|
||||||
|
void CacheTexture(const u64 hash, const std::vector<u8>& tex, u32 width, u32 height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<u64, bool> dumped_textures;
|
||||||
|
std::unordered_map<u64, CustomTexInfo> custom_textures;
|
||||||
|
};
|
||||||
|
} // namespace Core
|
|
@ -88,6 +88,7 @@ void LogSettings() {
|
||||||
LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option));
|
LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option));
|
||||||
LogSetting("Layout_SwapScreen", Settings::values.swap_screen);
|
LogSetting("Layout_SwapScreen", Settings::values.swap_screen);
|
||||||
LogSetting("Utility_DumpTextures", Settings::values.dump_textures);
|
LogSetting("Utility_DumpTextures", Settings::values.dump_textures);
|
||||||
|
LogSetting("Utility_CustomTextures", Settings::values.custom_textures);
|
||||||
LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle);
|
LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle);
|
||||||
LogSetting("Audio_EnableDspLleMultithread", Settings::values.enable_dsp_lle_multithread);
|
LogSetting("Audio_EnableDspLleMultithread", Settings::values.enable_dsp_lle_multithread);
|
||||||
LogSetting("Audio_OutputEngine", Settings::values.sink_id);
|
LogSetting("Audio_OutputEngine", Settings::values.sink_id);
|
||||||
|
|
|
@ -171,6 +171,7 @@ struct Values {
|
||||||
std::string pp_shader_name;
|
std::string pp_shader_name;
|
||||||
|
|
||||||
bool dump_textures;
|
bool dump_textures;
|
||||||
|
bool custom_textures;
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
bool enable_dsp_lle;
|
bool enable_dsp_lle;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/custom_tex_cache.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -856,7 +857,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
||||||
|
|
||||||
// TODO: move this function to a better place
|
// TODO: move this function to a better place
|
||||||
void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) {
|
void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) {
|
||||||
assert(tex.size() = width * height * 4);
|
ASSERT(tex.size() == width * height * 4);
|
||||||
const u64 line_size = width * 4;
|
const u64 line_size = width * 4;
|
||||||
// Thanks MSVC for not being able to make variable length arrays
|
// Thanks MSVC for not being able to make variable length arrays
|
||||||
u8* temp_row = new u8[line_size];
|
u8* temp_row = new u8[line_size];
|
||||||
|
@ -883,39 +884,61 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
|
|
||||||
ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format));
|
ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format));
|
||||||
|
|
||||||
// Decode and dump texture if texture dumping is enabled
|
// Read custom texture
|
||||||
// or read texture and replace
|
auto& custom_tex_cache = Core::System::GetInstance().CustomTexCache();
|
||||||
bool should_dump = false;
|
bool dump_tex = false;
|
||||||
bool should_use_custom_tex = false;
|
bool use_custom_tex = false;
|
||||||
std::string dump_path;
|
std::string dump_path; // Has to be declared here for logging later
|
||||||
std::vector<u8> decoded_png;
|
std::vector<u8> decoded_png;
|
||||||
u32 png_width;
|
u32 png_width;
|
||||||
u32 png_height;
|
u32 png_height;
|
||||||
if (Settings::values.dump_textures) {
|
u64 tex_hash = 0;
|
||||||
dump_path = fmt::format("{}/textures", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir));
|
|
||||||
if (!FileUtil::IsDirectory(dump_path))
|
if (Settings::values.dump_textures || Settings::values.custom_textures)
|
||||||
FileUtil::CreateDir(dump_path);
|
tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size);
|
||||||
dump_path += fmt::format(
|
|
||||||
"/{:016X}",
|
if (Settings::values.custom_textures) {
|
||||||
Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id);
|
const std::string load_path = fmt::format(
|
||||||
if (!FileUtil::IsDirectory(dump_path))
|
"{}textures/{:016X}/tex1_{}x{}_{:016X}_{}.png",
|
||||||
FileUtil::CreateDir(dump_path);
|
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||||
// Hash the encoded texture
|
Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id,
|
||||||
const u64 tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size);
|
width, height, tex_hash, static_cast<u32>(pixel_format));
|
||||||
dump_path += fmt::format("/tex1_{}x{}_{:016X}_{}.png", width, height, tex_hash,
|
|
||||||
static_cast<u32>(pixel_format));
|
if (!custom_tex_cache.IsTextureCached(tex_hash)) {
|
||||||
if (!FileUtil::Exists(dump_path))
|
if (FileUtil::Exists(load_path)) {
|
||||||
should_dump = true;
|
u32 lodepng_ret = lodepng::decode(decoded_png, png_width, png_height, load_path);
|
||||||
else {
|
|
||||||
u32 lodepng_ret = lodepng::decode(decoded_png, png_width, png_height, dump_path);
|
|
||||||
if (lodepng_ret)
|
if (lodepng_ret)
|
||||||
LOG_CRITICAL(Render_OpenGL, "Failed to load custom texture: {}",
|
LOG_CRITICAL(Render_OpenGL, "Failed to load custom texture: {}",
|
||||||
lodepng_error_text(lodepng_ret));
|
lodepng_error_text(lodepng_ret));
|
||||||
else {
|
else {
|
||||||
|
LOG_INFO(Render_OpenGL, "Loaded custom texture from {}", load_path);
|
||||||
FlipRGBA8Texture(decoded_png, png_width, png_height);
|
FlipRGBA8Texture(decoded_png, png_width, png_height);
|
||||||
should_use_custom_tex = true;
|
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 (Settings::values.dump_textures) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load data from memory to the surface
|
// Load data from memory to the surface
|
||||||
|
@ -929,7 +952,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
// If not 1x scale, create 1x texture that we will blit from to replace texture subrect in
|
// If not 1x scale, create 1x texture that we will blit from to replace texture subrect in
|
||||||
// surface
|
// surface
|
||||||
OGLTexture unscaled_tex;
|
OGLTexture unscaled_tex;
|
||||||
if (res_scale != 1 && !should_use_custom_tex) {
|
if (res_scale != 1 && !use_custom_tex) {
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
y0 = 0;
|
y0 = 0;
|
||||||
|
|
||||||
|
@ -946,7 +969,7 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||||
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
|
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
|
||||||
if (!should_use_custom_tex) {
|
if (!use_custom_tex) {
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride));
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride));
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -968,11 +991,11 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
}
|
}
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
if (should_dump) {
|
if (dump_tex) {
|
||||||
// Dump texture to RGBA8 and encode as PNG
|
// Dump texture to RGBA8 and encode as PNG
|
||||||
LOG_INFO(Render_OpenGL, "Dumping texture to {}", dump_path);
|
LOG_INFO(Render_OpenGL, "Dumping texture to {}", dump_path);
|
||||||
std::vector<u8> decoded_texture;
|
std::vector<u8> decoded_texture;
|
||||||
decoded_texture.resize(rect.GetWidth() * rect.GetHeight() * 4);
|
decoded_texture.resize(width * height * 4);
|
||||||
glBindTexture(GL_TEXTURE_2D, target_tex);
|
glBindTexture(GL_TEXTURE_2D, target_tex);
|
||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &decoded_texture[0]);
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &decoded_texture[0]);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
@ -982,12 +1005,13 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
LOG_CRITICAL(Render_OpenGL, "Failed to save decoded texture! {}",
|
LOG_CRITICAL(Render_OpenGL, "Failed to save decoded texture! {}",
|
||||||
lodepng_error_text(png_error));
|
lodepng_error_text(png_error));
|
||||||
}
|
}
|
||||||
|
custom_tex_cache.SetTextureDumped(tex_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_state.texture_units[0].texture_2d = old_tex;
|
cur_state.texture_units[0].texture_2d = old_tex;
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
|
|
||||||
if (res_scale != 1 && !should_use_custom_tex) {
|
if (res_scale != 1 && !use_custom_tex) {
|
||||||
auto scaled_rect = rect;
|
auto scaled_rect = rect;
|
||||||
scaled_rect.left *= res_scale;
|
scaled_rect.left *= res_scale;
|
||||||
scaled_rect.top *= res_scale;
|
scaled_rect.top *= res_scale;
|
||||||
|
|
Reference in New Issue