new-line that clang-format didn't fix
address some comments
This commit is contained in:
parent
59b475a4b9
commit
5940361b81
|
@ -161,16 +161,15 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||||
continue;
|
continue;
|
||||||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
|
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(button_map[button_id], &QPushButton::clicked, [=]() {
|
connect(button_map[button_id], &QPushButton::clicked, [=]() {
|
||||||
HandleClick(
|
HandleClick(button_map[button_id],
|
||||||
button_map[button_id],
|
[=](const Common::ParamPackage& params) {
|
||||||
[=](const Common::ParamPackage& params) {
|
buttons_param[button_id] = params;
|
||||||
buttons_param[button_id] = params;
|
// If the user closes the dialog, the changes are reverted in
|
||||||
// If the user closes the dialog, the changes are reverted in
|
// `GMainWindow::OnConfigure()`
|
||||||
// `GMainWindow::OnConfigure()`
|
ApplyConfiguration();
|
||||||
ApplyConfiguration();
|
Settings::SaveProfile(ui->profile->currentIndex());
|
||||||
Settings::SaveProfile(ui->profile->currentIndex());
|
},
|
||||||
},
|
InputCommon::Polling::DeviceType::Button);
|
||||||
InputCommon::Polling::DeviceType::Button);
|
|
||||||
});
|
});
|
||||||
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
|
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
|
||||||
[=](const QPoint& menu_location) {
|
[=](const QPoint& menu_location) {
|
||||||
|
@ -199,15 +198,14 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||||
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
|
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
|
||||||
Qt::CustomContextMenu);
|
Qt::CustomContextMenu);
|
||||||
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() {
|
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() {
|
||||||
HandleClick(
|
HandleClick(analog_map_buttons[analog_id][sub_button_id],
|
||||||
analog_map_buttons[analog_id][sub_button_id],
|
[=](const Common::ParamPackage& params) {
|
||||||
[=](const Common::ParamPackage& params) {
|
SetAnalogButton(params, analogs_param[analog_id],
|
||||||
SetAnalogButton(params, analogs_param[analog_id],
|
analog_sub_buttons[sub_button_id]);
|
||||||
analog_sub_buttons[sub_button_id]);
|
ApplyConfiguration();
|
||||||
ApplyConfiguration();
|
Settings::SaveProfile(ui->profile->currentIndex());
|
||||||
Settings::SaveProfile(ui->profile->currentIndex());
|
},
|
||||||
},
|
InputCommon::Polling::DeviceType::Button);
|
||||||
InputCommon::Polling::DeviceType::Button);
|
|
||||||
});
|
});
|
||||||
connect(analog_map_buttons[analog_id][sub_button_id],
|
connect(analog_map_buttons[analog_id][sub_button_id],
|
||||||
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
||||||
|
|
|
@ -34,7 +34,8 @@ void DetachedTasks::AddTask(std::function<void()> task) {
|
||||||
std::unique_lock lock{instance->mutex};
|
std::unique_lock lock{instance->mutex};
|
||||||
--instance->count;
|
--instance->count;
|
||||||
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
|
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
|
||||||
}).detach();
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // 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 <vector>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -6,17 +11,12 @@ namespace Common {
|
||||||
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;
|
||||||
u8* temp_row = new u8[line_size];
|
|
||||||
u32 offset_1;
|
|
||||||
u32 offset_2;
|
|
||||||
for (u64 line = 0; line < height / 2; line++) {
|
for (u64 line = 0; line < height / 2; line++) {
|
||||||
offset_1 = line * line_size;
|
const u32 offset_1 = line * line_size;
|
||||||
offset_2 = (height - line - 1) * line_size;
|
const u32 offset_2 = (height - line - 1) * line_size;
|
||||||
// Swap lines
|
// Swap lines
|
||||||
std::memcpy(temp_row, &tex[offset_1], line_size);
|
std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size,
|
||||||
std::memcpy(&tex[offset_1], &tex[offset_2], line_size);
|
tex.begin() + offset_2);
|
||||||
std::memcpy(&tex[offset_2], temp_row, line_size);
|
|
||||||
}
|
}
|
||||||
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
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -18,14 +18,11 @@
|
||||||
#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"
|
#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"
|
||||||
|
@ -102,6 +99,48 @@ System::ResultStatus System::SingleStep() {
|
||||||
return RunLoop(false);
|
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) {
|
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||||
app_loader = Loader::GetLoader(filepath);
|
app_loader = Loader::GetLoader(filepath);
|
||||||
if (!app_loader) {
|
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);
|
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>();
|
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) {
|
if (Settings::values.preload_textures) {
|
||||||
// Custom textures are currently stored as
|
// Custom textures are currently stored as
|
||||||
// load/textures/[TitleID]/tex1_[width]x[height]_[64-bit hash]_[format].png
|
// 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;
|
status = ResultStatus::Success;
|
||||||
m_emu_window = &emu_window;
|
m_emu_window = &emu_window;
|
||||||
m_filepath = filepath;
|
m_filepath = filepath;
|
||||||
|
@ -242,8 +277,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||||
|
|
||||||
timing = std::make_unique<Timing>();
|
timing = std::make_unique<Timing>();
|
||||||
|
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
|
||||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode);
|
[this] { PrepareReschedule(); }, system_mode);
|
||||||
|
|
||||||
if (Settings::values.use_cpu_jit) {
|
if (Settings::values.use_cpu_jit) {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
@ -345,21 +380,20 @@ 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() {
|
Core::CustomTexCache& System::CustomTexCache() {
|
||||||
return *custom_tex_cache;
|
return *custom_tex_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Core::CustomTexCache& System::CustomTexCache() const {
|
const Core::CustomTexCache& System::CustomTexCache() const {
|
||||||
return *custom_tex_cache;
|
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) {
|
||||||
|
|
|
@ -223,6 +223,8 @@ public:
|
||||||
/// Gets a const reference to the custom texture cache system
|
/// Gets a const reference to the custom texture cache system
|
||||||
const Core::CustomTexCache& CustomTexCache() const;
|
const Core::CustomTexCache& CustomTexCache() const;
|
||||||
|
|
||||||
|
/// Handles loading all custom textures from disk into cache.
|
||||||
|
void PreloadCustomTextures();
|
||||||
FrameLimiter frame_limiter;
|
FrameLimiter frame_limiter;
|
||||||
|
|
||||||
void SetStatus(ResultStatus new_status, const char* details = nullptr) {
|
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 <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "custom_tex_cache.h"
|
#include "custom_tex_cache.h"
|
||||||
|
|
||||||
namespace Core {
|
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();
|
return dumped_textures.find(hash) != dumped_textures.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +20,7 @@ void CustomTexCache::SetTextureDumped(const u64 hash) {
|
||||||
dumped_textures[hash] = true;
|
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();
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -14,12 +18,15 @@ struct CustomTexInfo {
|
||||||
// TODO: think of a better name for this class...
|
// TODO: think of a better name for this class...
|
||||||
class CustomTexCache {
|
class CustomTexCache {
|
||||||
public:
|
public:
|
||||||
const bool IsTextureDumped(const u64 hash);
|
CustomTexCache();
|
||||||
void SetTextureDumped(const u64 hash);
|
~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);
|
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:
|
private:
|
||||||
std::unordered_map<u64, bool> dumped_textures;
|
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::MboxData:
|
||||||
case CecDataPathType::MboxIcon:
|
case CecDataPathType::MboxIcon:
|
||||||
case CecDataPathType::MboxTitle:
|
case CecDataPathType::MboxTitle:
|
||||||
default: {
|
default: {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ public:
|
||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartPlayback(
|
void StartPlayback(const std::string& movie_file,
|
||||||
const std::string& movie_file, std::function<void()> completion_callback = [] {});
|
std::function<void()> completion_callback = [] {});
|
||||||
void StartRecording(const std::string& movie_file);
|
void StartRecording(const std::string& movie_file);
|
||||||
|
|
||||||
/// Prepare to override the clock before playing back movies
|
/// 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();
|
success_callback();
|
||||||
else
|
else
|
||||||
failure_callback();
|
failure_callback();
|
||||||
}).detach();
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||||
|
@ -268,7 +269,8 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||||
complete_event.Wait();
|
complete_event.Wait();
|
||||||
socket.Stop();
|
socket.Stop();
|
||||||
worker_thread.join();
|
worker_thread.join();
|
||||||
}).detach();
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
CalibrationConfigurationJob::~CalibrationConfigurationJob() {
|
CalibrationConfigurationJob::~CalibrationConfigurationJob() {
|
||||||
|
|
|
@ -17,8 +17,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
|
|
||||||
timing = std::make_unique<Core::Timing>();
|
timing = std::make_unique<Core::Timing>();
|
||||||
memory = std::make_unique<Memory::MemorySystem>();
|
memory = std::make_unique<Memory::MemorySystem>();
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0);
|
||||||
*memory, *timing, [] {}, 0);
|
|
||||||
|
|
||||||
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
||||||
page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
|
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]") {
|
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
||||||
Core::Timing timing;
|
Core::Timing timing;
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
memory, timing, [] {}, 0);
|
|
||||||
auto [server, client] = kernel.CreateSessionPair();
|
auto [server, client] = kernel.CreateSessionPair();
|
||||||
HLERequestContext context(kernel, std::move(server), nullptr);
|
HLERequestContext context(kernel, std::move(server), nullptr);
|
||||||
|
|
||||||
|
@ -236,8 +235,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
Core::Timing timing;
|
Core::Timing timing;
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
memory, timing, [] {}, 0);
|
|
||||||
auto [server, client] = kernel.CreateSessionPair();
|
auto [server, client] = kernel.CreateSessionPair();
|
||||||
HLERequestContext context(kernel, std::move(server), nullptr);
|
HLERequestContext context(kernel, std::move(server), nullptr);
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
Core::Timing timing;
|
Core::Timing timing;
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
memory, timing, [] {}, 0);
|
|
||||||
SECTION("these regions should not be mapped on an empty process") {
|
SECTION("these regions should not be mapped on an empty process") {
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
|
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));
|
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_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 dump_tex = false;
|
||||||
bool use_custom_tex = false;
|
bool use_custom_tex = false;
|
||||||
std::string dump_path; // Has to be declared here for logging later
|
std::string dump_path; // Has to be declared here for logging later
|
||||||
std::vector<u8> decoded_png;
|
Core::CustomTexInfo custom_tex_info;
|
||||||
u32 png_width = 0;
|
|
||||||
u32 png_height = 0;
|
|
||||||
u64 tex_hash = 0;
|
u64 tex_hash = 0;
|
||||||
Common::Rectangle custom_rect =
|
Common::Rectangle custom_rect =
|
||||||
rect; // Required for rect to function properly with custom textures
|
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)
|
if (Settings::values.dump_textures || Settings::values.custom_textures)
|
||||||
tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size);
|
tex_hash = Common::ComputeHash64(gl_buffer.get(), gl_buffer_size);
|
||||||
|
|
||||||
if (Settings::values.custom_textures) {
|
if (Settings::values.custom_textures)
|
||||||
const std::string load_path = fmt::format(
|
use_custom_tex = LoadCustomTextures(tex_hash, custom_tex_info, custom_rect);
|
||||||
"{}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 (Settings::values.dump_textures && !use_custom_tex)
|
||||||
if (FileUtil::Exists(load_path)) {
|
dump_tex = GetDumpPath(tex_hash, dump_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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load data from memory to the surface
|
// Load data from memory to the surface
|
||||||
GLint x0 = static_cast<GLint>(custom_rect.left);
|
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();
|
unscaled_tex.Create();
|
||||||
if (use_custom_tex) {
|
if (use_custom_tex) {
|
||||||
AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8),
|
AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8),
|
||||||
png_width, png_height);
|
custom_tex_info.width, custom_tex_info.height);
|
||||||
} else {
|
} else {
|
||||||
AllocateSurfaceTexture(unscaled_tex.handle, tuple, custom_rect.GetWidth(),
|
AllocateSurfaceTexture(unscaled_tex.handle, tuple, custom_rect.GetWidth(),
|
||||||
custom_rect.GetHeight());
|
custom_rect.GetHeight());
|
||||||
|
@ -975,36 +1003,22 @@ void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint r
|
||||||
&gl_buffer[buffer_offset]);
|
&gl_buffer[buffer_offset]);
|
||||||
} else {
|
} else {
|
||||||
if (res_scale == 1) {
|
if (res_scale == 1) {
|
||||||
AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8), png_width,
|
AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8),
|
||||||
png_height);
|
custom_tex_info.width, custom_tex_info.height);
|
||||||
cur_state.texture_units[0].texture_2d = texture.handle;
|
cur_state.texture_units[0].texture_2d = texture.handle;
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
}
|
}
|
||||||
// always going to be using rgba8
|
// 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);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, png_width, png_height, GL_RGBA, GL_UNSIGNED_BYTE,
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, custom_tex_info.width, custom_tex_info.height,
|
||||||
decoded_png.data());
|
GL_RGBA, GL_UNSIGNED_BYTE, custom_tex_info.tex.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
if (dump_tex) {
|
if (dump_tex)
|
||||||
// Dump texture to RGBA8 and encode as PNG
|
DumpTexture(target_tex, dump_path);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_state.texture_units[0].texture_2d = old_tex;
|
cur_state.texture_units[0].texture_2d = old_tex;
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
|
#include "core/custom_tex_cache.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "video_core/regs_framebuffer.h"
|
#include "video_core/regs_framebuffer.h"
|
||||||
#include "video_core/regs_texturing.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 LoadGLBuffer(PAddr load_start, PAddr load_end);
|
||||||
void FlushGLBuffer(PAddr flush_start, PAddr flush_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
|
// Upload/Download data in gl_buffer in/to this surface's texture
|
||||||
void UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle);
|
GLuint draw_fb_handle);
|
||||||
|
|
Reference in New Issue