Merge branch 'master' into prx-improvements

This commit is contained in:
Elad 2025-01-18 14:30:38 +02:00 committed by GitHub
commit 5c4952b4ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 282 additions and 209 deletions

View file

@ -2021,7 +2021,7 @@ std::string fs::get_executable_dir()
return s_exe_dir;
}
const std::string& fs::get_config_dir()
const std::string& fs::get_config_dir([[maybe_unused]] bool get_config_subdirectory)
{
// Use magic static
static const std::string s_dir = []
@ -2103,6 +2103,14 @@ const std::string& fs::get_config_dir()
return dir;
}();
#ifdef _WIN32
if (get_config_subdirectory)
{
static const std::string subdir = s_dir + "config/";
return subdir;
}
#endif
return s_dir;
}
@ -2144,6 +2152,16 @@ const std::string& fs::get_cache_dir()
return s_dir;
}
const std::string& fs::get_log_dir()
{
#ifdef _WIN32
static const std::string s_dir = fs::get_config_dir() + "log/";
return s_dir;
#else
return fs::get_cache_dir();
#endif
}
const std::string& fs::get_temp_dir()
{
static const std::string s_dir = []

View file

@ -599,12 +599,15 @@ namespace fs
// Get executable containing directory
std::string get_executable_dir();
// Get configuration directory
const std::string& get_config_dir();
// Get configuration directory. Set get_config_subdirectory to true to get the nested config dir on windows.
const std::string& get_config_dir(bool get_config_subdirectory = false);
// Get common cache directory
const std::string& get_cache_dir();
// Get common log directory
const std::string& get_log_dir();
// Temporary directory
const std::string& get_temp_dir();

View file

@ -125,19 +125,15 @@ patch_engine::patch_engine()
std::string patch_engine::get_patch_config_path()
{
#ifdef _WIN32
const std::string config_dir = fs::get_config_dir() + "config/";
const std::string config_dir = fs::get_config_dir(true);
const std::string patch_path = config_dir + "patch_config.yml";
#ifdef _WIN32
if (!fs::create_path(config_dir))
{
patch_log.error("Could not create path: %s (%s)", patch_path, fs::g_tls_error);
}
return patch_path;
#else
return fs::get_config_dir() + "patch_config.yml";
#endif
return patch_path;
}
std::string patch_engine::get_patches_path()

View file

@ -25,7 +25,7 @@ void cfg_ipc::load()
void cfg_ipc::save() const
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
const std::string path_to_cfg = fs::get_config_dir(true);
if (!fs::create_path(path_to_cfg))
{
IPC.error("Could not create path: %s", path_to_cfg);
@ -42,11 +42,7 @@ void cfg_ipc::save() const
std::string cfg_ipc::get_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/ipc.yml";
#else
return fs::get_config_dir() + "ipc.yml";
#endif
return fs::get_config_dir(true) + "ipc.yml";
}
bool cfg_ipc::get_server_enabled() const

View file

@ -31,12 +31,12 @@ void MouseHandlerBase::save(utils::serial& ar)
ar(inited ? m_info.max_connect : 0);
}
bool MouseHandlerBase::is_time_for_update(double elapsed_time)
bool MouseHandlerBase::is_time_for_update(double elapsed_time_ms)
{
steady_clock::time_point now = steady_clock::now();
const double elapsed = (now - last_update).count() / 1000'000.;
const double elapsed_ms = (now - last_update).count() / 1'000'000.;
if (elapsed > elapsed_time)
if (elapsed_ms > elapsed_time_ms)
{
last_update = now;
return true;

View file

@ -127,7 +127,7 @@ protected:
std::vector<Mouse> m_mice;
steady_clock::time_point last_update{};
bool is_time_for_update(double elapsed_time = 10.0); // 4-10 ms, let's use 10 for now
bool is_time_for_update(double elapsed_time_ms = 10.0); // 4-10 ms, let's use 10 for now
public:
shared_mutex mutex;

View file

@ -8,11 +8,7 @@ cfg_camera g_cfg_camera;
cfg_camera::cfg_camera()
: cfg::node()
#ifdef _WIN32
, path(fs::get_config_dir() + "config/camera.yml")
#else
, path(fs::get_config_dir() + "camera.yml")
#endif
, path(fs::get_config_dir(true) + "camera.yml")
{
}

View file

@ -235,7 +235,7 @@ struct emulated_pads_config : cfg::node
m_mutex.lock();
bool result = false;
const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id);
const std::string cfg_name = fmt::format("%s%s.yml", fs::get_config_dir(true), cfg_id);
cfg_log.notice("Loading %s config: %s", cfg_id, cfg_name);
from_default();
@ -272,7 +272,7 @@ struct emulated_pads_config : cfg::node
{
std::lock_guard lock(m_mutex);
const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id);
const std::string cfg_name = fmt::format("%s%s.yml", fs::get_config_dir(true), cfg_id);
cfg_log.notice("Saving %s config to '%s'", cfg_id, cfg_name);
if (!fs::create_path(fs::get_parent_dir(cfg_name)))

View file

@ -4,11 +4,7 @@
#include "Utilities/File.h"
mouse_config::mouse_config()
#ifdef _WIN32
: cfg_name(fs::get_config_dir() + "config/config_mouse.yml")
#else
: cfg_name(fs::get_config_dir() + "config_mouse.yml")
#endif
: cfg_name(fs::get_config_dir(true) + "config_mouse.yml")
{
}

View file

@ -8,13 +8,7 @@ cfg_rb3drums g_cfg_rb3drums;
cfg_rb3drums::cfg_rb3drums()
: cfg::node()
#ifdef _WIN32
,
path(fs::get_config_dir() + "config/rb3drums.yml")
#else
,
path(fs::get_config_dir() + "rb3drums.yml")
#endif
, path(fs::get_config_dir(true) + "rb3drums.yml")
{
}

View file

@ -8,11 +8,7 @@ cfg_recording g_cfg_recording;
cfg_recording::cfg_recording()
: cfg::node()
#ifdef _WIN32
, path(fs::get_config_dir() + "config/recording.yml")
#else
, path(fs::get_config_dir() + "recording.yml")
#endif
, path(fs::get_config_dir(true) + "recording.yml")
{
}

View file

@ -59,11 +59,7 @@ namespace np
{
std::string get_players_history_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/players_history.yml";
#else
return fs::get_config_dir() + "players_history.yml";
#endif
return fs::get_config_dir(true) + "players_history.yml";
}
std::map<std::string, player_history> load_players_history()
@ -1440,7 +1436,7 @@ namespace np
void np_handler::save_players_history()
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
const std::string path_to_cfg = fs::get_config_dir(true);
if (!fs::create_path(path_to_cfg))
{
nph_log.error("Could not create path: %s", path_to_cfg);

View file

@ -34,7 +34,7 @@ void cfg_rpcn::load()
void cfg_rpcn::save() const
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
const std::string path_to_cfg = fs::get_config_dir(true);
if (!fs::create_path(path_to_cfg))
{
rpcn_log.error("Could not create path: %s", path_to_cfg);
@ -51,11 +51,7 @@ void cfg_rpcn::save() const
std::string cfg_rpcn::get_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/rpcn.yml";
#else
return fs::get_config_dir() + "rpcn.yml";
#endif
return fs::get_config_dir(true) + "rpcn.yml";
}
std::string cfg_rpcn::generate_npid()

View file

@ -24,7 +24,7 @@ void cfg_upnp::load()
void cfg_upnp::save() const
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
const std::string path_to_cfg = fs::get_config_dir(true);
if (!fs::create_path(path_to_cfg))
{
upnp_cfg_log.error("Could not create path: %s", path_to_cfg);
@ -51,9 +51,5 @@ void cfg_upnp::set_device_url(std::string_view url)
std::string cfg_upnp::get_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/upnp.yml";
#else
return fs::get_config_dir() + "upnp.yml";
#endif
return fs::get_config_dir(true) + "upnp.yml";
}

View file

@ -735,7 +735,7 @@ namespace rsx
utils::stream_vector(dst + 4, 0u, fog_mode, std::bit_cast<u32>(wpos_scale), std::bit_cast<u32>(wpos_bias));
}
void draw_command_processor::fill_constants_instancing_buffer(rsx::io_buffer& indirection_table_buf, rsx::io_buffer& constants_data_array_buffer, const VertexProgramBase& prog) const
void draw_command_processor::fill_constants_instancing_buffer(rsx::io_buffer& indirection_table_buf, rsx::io_buffer& constants_data_array_buffer, const VertexProgramBase* prog) const
{
auto& draw_call = REGS(m_ctx)->current_draw_clause;
@ -745,8 +745,9 @@ namespace rsx
// Temp indirection table. Used to track "running" updates.
rsx::simple_array<u32> instancing_indirection_table;
// indirection table size
const auto reloc_table = prog.has_indexed_constants ? decltype(prog.constant_ids){} : prog.constant_ids;
const auto redirection_table_size = prog.has_indexed_constants ? 468u : ::size32(prog.constant_ids);
const auto full_reupload = !prog || prog->has_indexed_constants;
const auto reloc_table = full_reupload ? decltype(prog->constant_ids){} : prog->constant_ids;
const auto redirection_table_size = full_reupload ? 468u : ::size32(prog->constant_ids);
instancing_indirection_table.resize(redirection_table_size);
// Temp constants data
@ -787,9 +788,9 @@ namespace rsx
continue;
}
const int translated_offset = prog.has_indexed_constants
const int translated_offset = full_reupload
? instance_config.patch_load_offset
: prog.TranslateConstantsRange(instance_config.patch_load_offset, instance_config.patch_load_count);
: prog->translate_constants_range(instance_config.patch_load_offset, instance_config.patch_load_count);
if (translated_offset >= 0)
{
@ -809,14 +810,14 @@ namespace rsx
continue;
}
ensure(!prog.has_indexed_constants);
ensure(!full_reupload);
// Sparse update. Update records individually instead of bulk
// FIXME: Range batching optimization
const auto load_end = instance_config.patch_load_offset + instance_config.patch_load_count;
for (u32 i = 0; i < redirection_table_size; ++i)
{
const auto read_index = prog.constant_ids[i];
const auto read_index = prog->constant_ids[i];
if (read_index < instance_config.patch_load_offset || read_index >= load_end)
{
// Reading outside "hot" range.

View file

@ -105,6 +105,6 @@ namespace rsx
// Fill instancing buffers. A single iobuf is used for both. 256byte alignment enforced to allow global bind
// Returns offsets to the index redirection lookup table and constants field array
void fill_constants_instancing_buffer(rsx::io_buffer& indirection_table_buf, rsx::io_buffer& constants_data_array_buffer, const VertexProgramBase& prog) const;
void fill_constants_instancing_buffer(rsx::io_buffer& indirection_table_buf, rsx::io_buffer& constants_data_array_buffer, const VertexProgramBase* prog) const;
};
}

View file

@ -878,7 +878,7 @@ void GLGSRender::load_program_env()
}
}
if (update_fragment_constants && !update_instruction_buffers)
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
// Fragment constants
auto mapping = m_fragment_constants_buffer->alloc_from_heap(fragment_constants_size, m_uniform_buffer_offset_align);
@ -978,12 +978,18 @@ void GLGSRender::load_program_env()
}
}
m_graphics_state.clear(
rsx::flags32_t handled_flags =
rsx::pipeline_state::fragment_state_dirty |
rsx::pipeline_state::vertex_state_dirty |
rsx::pipeline_state::transform_constants_dirty |
rsx::pipeline_state::fragment_constants_dirty |
rsx::pipeline_state::fragment_texture_state_dirty);
rsx::pipeline_state::fragment_texture_state_dirty;
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
handled_flags |= rsx::pipeline_state::fragment_constants_dirty;
}
m_graphics_state.clear(handled_flags);
}
bool GLGSRender::is_current_program_interpreted() const
@ -1039,13 +1045,19 @@ void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
{
if (!m_vertex_prog)
if (!m_program || !m_vertex_prog)
{
// Shouldn't be reachable, but handle it correctly anyway
m_graphics_state |= rsx::pipeline_state::transform_constants_dirty;
return;
}
if (!m_vertex_prog->overlaps_constants_range(index, count))
{
// Nothing meaningful to us
return;
}
std::pair<u32, u32> data_range {};
void* data_source = nullptr;
const auto bound_range = m_transform_constants_buffer->bound_range();
@ -1059,7 +1071,7 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
data_range = { bound_range.first + byte_offset, byte_count};
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->TranslateConstantsRange(index, count); xform_id >= 0)
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;

View file

@ -34,7 +34,8 @@ vec2 texture2DMSCoord(const in vec2 coords, const in uint flags)
return coords;
}
const vec2 wrapped_coords = mod(coords, vec2(1.0));
const vec2 wrapped_coords_raw = mod(coords, vec2(1.0));
const vec2 wrapped_coords = mod(wrapped_coords_raw + vec2(1.0), vec2(1.0));
const bvec2 wrap_control_mask = bvec2(uvec2(flags) & uvec2(WRAP_S_MASK, WRAP_T_MASK));
return _select(coords, wrapped_coords, wrap_control_mask);
}

View file

@ -110,7 +110,7 @@ namespace rsx
multisampled_textures == other.multisampled_textures;
}
int VertexProgramBase::TranslateConstantsRange(int first_index, int count) const
int VertexProgramBase::translate_constants_range(int first_index, int count) const
{
// The constant ids should be sorted, so just find the first one and check for continuity
int index = -1;
@ -157,4 +157,31 @@ namespace rsx
// OOB or partial match
return -1;
}
bool VertexProgramBase::overlaps_constants_range(int first_index, int count) const
{
if (has_indexed_constants)
{
return true;
}
const int last_index = first_index + count - 1;
// Early rejection test
if (constant_ids.empty() || first_index > constant_ids.back() || last_index < first_index)
{
return false;
}
// Check for any hits
for (auto& idx : constant_ids)
{
if (idx >= first_index && idx <= last_index)
{
return true;
}
}
return false;
}
}

View file

@ -67,6 +67,9 @@ namespace rsx
// Translates an incoming range of constants against our mapping.
// If there is no linear mapping available, return -1, otherwise returns the translated index of the first slot
// TODO: Move this somewhere else during refactor
int TranslateConstantsRange(int first_index, int count) const;
int translate_constants_range(int first_index, int count) const;
// Returns true if this program consumes any constants in the range [first, first + count - 1]
bool overlaps_constants_range(int first_index, int count) const;
};
}

View file

@ -688,10 +688,10 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
}
// Initialize optional allocation information with placeholders
m_vertex_env_buffer_info = { m_vertex_env_ring_info.heap->value, 0, 32 };
m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, 0, 32 };
m_fragment_env_buffer_info = { m_fragment_env_ring_info.heap->value, 0, 32 };
m_fragment_texture_params_buffer_info = { m_fragment_texture_params_ring_info.heap->value, 0, 32 };
m_vertex_env_buffer_info = { m_vertex_env_ring_info.heap->value, 0, 16 };
m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, 0, 16 };
m_fragment_env_buffer_info = { m_fragment_env_ring_info.heap->value, 0, 16 };
m_fragment_texture_params_buffer_info = { m_fragment_texture_params_ring_info.heap->value, 0, 16 };
m_raster_env_buffer_info = { m_raster_env_ring_info.heap->value, 0, 128 };
const auto limits = m_device->gpu().get_limits();
@ -2192,7 +2192,7 @@ void VKGSRender::load_program_env()
return std::make_pair(m_instancing_buffer_ring_info.map(constants_data_table_offset, size), size);
});
m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, *m_vertex_prog);
m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, m_vertex_prog);
m_instancing_buffer_ring_info.unmap();
m_instancing_indirection_buffer_info = { m_instancing_buffer_ring_info.heap->value, indirection_table_offset, indirection_table_buf.size() };
@ -2219,7 +2219,7 @@ void VKGSRender::load_program_env()
}
}
if (update_fragment_constants && !update_instruction_buffers)
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
check_heap_status(VK_HEAP_CHECK_FRAGMENT_CONSTANTS_STORAGE);
@ -2350,9 +2350,9 @@ void VKGSRender::load_program_env()
}
// Clear flags
u32 handled_flags = rsx::pipeline_state::fragment_state_dirty |
rsx::flags32_t handled_flags =
rsx::pipeline_state::fragment_state_dirty |
rsx::pipeline_state::vertex_state_dirty |
rsx::pipeline_state::fragment_constants_dirty |
rsx::pipeline_state::fragment_texture_state_dirty;
if (!update_instancing_data)
@ -2360,6 +2360,11 @@ void VKGSRender::load_program_env()
handled_flags |= rsx::pipeline_state::transform_constants_dirty;
}
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
handled_flags |= rsx::pipeline_state::fragment_constants_dirty;
}
m_graphics_state.clear(handled_flags);
}
@ -2438,13 +2443,19 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
{
if (!m_vertex_prog)
if (!m_program || !m_vertex_prog)
{
// Shouldn't be reachable, but handle it correctly anyway
m_graphics_state |= rsx::pipeline_state::transform_constants_dirty;
return;
}
if (!m_vertex_prog->overlaps_constants_range(index, count))
{
// Nothing meaningful to us
return;
}
// Hot-patching transform constants mid-draw (instanced draw)
std::pair<VkDeviceSize, VkDeviceSize> data_range;
void* data_source = nullptr;
@ -2458,7 +2469,7 @@ void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
data_range = { m_vertex_constants_buffer_info.offset + byte_offset, byte_count };
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->TranslateConstantsRange(index, count); xform_id >= 0)
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;

View file

@ -387,7 +387,7 @@ namespace vk
struct stencilonly_unresolve : depth_resolve_base
{
VkClearRect region{};
VkClearRect clear_region{};
VkClearAttachment clear_info{};
stencilonly_unresolve()
@ -402,8 +402,8 @@ namespace vk
renderpass_config.set_depth_mask(false);
clear_info.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
region.baseArrayLayer = 0;
region.layerCount = 1;
clear_region.baseArrayLayer = 0;
clear_region.layerCount = 1;
static_parameters_width = 3;
@ -425,7 +425,7 @@ namespace vk
void emit_geometry(vk::command_buffer& cmd) override
{
vkCmdClearAttachments(cmd, 1, &clear_info, 1, &region);
vkCmdClearAttachments(cmd, 1, &clear_info, 1, &clear_region);
for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1)
{
@ -444,8 +444,8 @@ namespace vk
auto stencil_view = resolve_image->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY), VK_IMAGE_ASPECT_STENCIL_BIT);
region.rect.extent.width = resolve_image->width();
region.rect.extent.height = resolve_image->height();
clear_region.rect.extent.width = msaa_image->width();
clear_region.rect.extent.height = msaa_image->height();
overlay_pass::run(
cmd,

View file

@ -400,6 +400,7 @@ namespace rsx
fp.texture_state.multisampled_textures = data.fp_multisampled_textures;
fp.texcoord_control_mask = data.fp_texcoord_control;
fp.two_sided_lighting = !!(data.fp_lighting_flags & 0x1);
fp.mrt_buffers_count = data.fp_mrt_count;
return result;
}

View file

@ -347,9 +347,40 @@ void Emulator::Init()
{
jit_runtime::initialize();
const std::string emu_dir = rpcs3::utils::get_emu_dir();
auto make_path_verbose = [&](const std::string& path, bool must_exist_outside_emu_dir)
{
if (fs::is_dir(path))
{
return true;
}
if (must_exist_outside_emu_dir)
{
const std::string parent = fs::get_parent_dir(path);
const std::string emu_dir_no_delim = emu_dir.substr(0, emu_dir.find_last_not_of(fs::delim) + 1);
if (parent != emu_dir_no_delim && GetCallbacks().resolve_path(parent) != GetCallbacks().resolve_path(emu_dir_no_delim))
{
sys_log.fatal("Cannot use '%s' for Virtual File System because it does not exist.\nPlease specify an existing and writable directory path in Toolbar -> Manage -> Virtual File System.", path);
return false;
}
}
if (!fs::create_path(path))
{
sys_log.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error);
return false;
}
return true;
};
if (!g_tty)
{
const auto tty_path = fs::get_cache_dir() + "TTY.log";
make_path_verbose(fs::get_log_dir(), true);
const auto tty_path = fs::get_log_dir() + "TTY.log";
g_tty.open(tty_path, fs::rewrite + fs::append);
if (!g_tty)
@ -374,7 +405,22 @@ void Emulator::Init()
g_cfg_defaults = g_cfg.to_string();
const std::string cfg_path = fs::get_config_dir() + "/config.yml";
const std::string cfg_path = fs::get_config_dir(true) + "config.yml";
// Move file from deprecated location to new location
#ifdef _WIN32
const std::string old_path = fs::get_config_dir(false) + "config.yml";
if (fs::is_file(old_path))
{
sys_log.notice("Found deprecated config.yml file: '%s'", old_path);
if (!fs::rename(old_path, cfg_path, false))
{
sys_log.error("Failed to move '%s' to '%s' (error='%s')", old_path, cfg_path, fs::g_tls_error);
}
}
#endif
// Save new global config if it doesn't exist or is empty
if (fs::stat_t info{}; !fs::get_stat(cfg_path, info) || info.size == 0)
@ -387,7 +433,6 @@ void Emulator::Init()
sys_log.notice("Using VFS config:\n%s", g_cfg_vfs.to_string());
// Mount all devices
const std::string emu_dir = rpcs3::utils::get_emu_dir();
const std::string elf_dir = fs::get_parent_dir(m_path);
const std::string dev_bdvd = g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, emu_dir); // Only used for make_path
const std::string dev_hdd0 = g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, emu_dir);
@ -487,34 +532,6 @@ void Emulator::Init()
g_backup_cfg.from_string(g_cfg.to_string());
// Create directories (can be disabled if necessary)
auto make_path_verbose = [&](const std::string& path, bool must_exist_outside_emu_dir)
{
if (fs::is_dir(path))
{
return true;
}
if (must_exist_outside_emu_dir)
{
const std::string parent = fs::get_parent_dir(path);
const std::string emu_dir_no_delim = emu_dir.substr(0, emu_dir.find_last_not_of(fs::delim) + 1);
if (parent != emu_dir_no_delim && GetCallbacks().resolve_path(parent) != GetCallbacks().resolve_path(emu_dir_no_delim))
{
sys_log.fatal("Cannot use '%s' for Virtual File System because it does not exist.\nPlease specify an existing and writable directory path in Toolbar -> Manage -> Virtual File System.", path);
return false;
}
}
if (!fs::create_path(path))
{
sys_log.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error);
return false;
}
return true;
};
const std::string save_path = dev_hdd0 + "home/" + m_usr + "/savedata/";
const std::string user_path = dev_hdd0 + "home/" + m_usr + "/localusername";
@ -3621,7 +3638,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
if (usz attempted_read_size = utils::sub_saturate<usz>(g_tty.pos(), m_tty_file_init_pos))
{
if (fs::file tty_read_fd{fs::get_cache_dir() + "TTY.log"})
if (fs::file tty_read_fd{fs::get_log_dir() + "TTY.log"})
{
// Enforce an arbitrary limit for now to avoid OOM in case the guest code has bombarded TTY
// 3MB, this should be enough
@ -4466,7 +4483,7 @@ void Emulator::SaveSettings(const std::string& settings, const std::string& titl
if (title_id.empty())
{
config_name = fs::get_config_dir() + "/config.yml";
config_name = fs::get_config_dir(true) + "config.yml";
}
else
{

View file

@ -123,7 +123,7 @@ bool games_config::save_nl()
YAML::Emitter out;
out << m_games;
fs::pending_file temp(fs::get_config_dir() + "/games.yml");
fs::pending_file temp(fs::get_config_dir(true) + "games.yml");
if (temp.file && temp.file.write(out.c_str(), out.size()) >= out.size() && temp.commit())
{
@ -147,7 +147,24 @@ void games_config::load()
m_games.clear();
if (fs::file f{fs::get_config_dir() + "/games.yml", fs::read + fs::create})
const std::string path = fs::get_config_dir(true) + "games.yml";
// Move file from deprecated location to new location
#ifdef _WIN32
const std::string old_path = fs::get_config_dir(false) + "games.yml";
if (fs::is_file(old_path))
{
cfg_log.notice("Found deprecated games.yml file: '%s'", old_path);
if (!fs::rename(old_path, path, false))
{
cfg_log.error("Failed to move '%s' to '%s' (error='%s')", old_path, path, fs::g_tls_error);
}
}
#endif
if (fs::file f{path, fs::read + fs::create})
{
auto [result, error] = yaml_load(f.to_string());

View file

@ -311,11 +311,7 @@ namespace rpcs3::utils
std::string get_custom_config_dir()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/custom_configs/";
#else
return fs::get_config_dir() + "custom_configs/";
#endif
return fs::get_config_dir(true) + "custom_configs/";
}
std::string get_custom_config_path(const std::string& identifier)
@ -330,11 +326,7 @@ namespace rpcs3::utils
std::string get_input_config_root()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/input_configs/";
#else
return fs::get_config_dir() + "input_configs/";
#endif
return fs::get_config_dir(true) + "input_configs/";
}
std::string get_input_config_dir(const std::string& title_id)

View file

@ -115,7 +115,7 @@ void cfg_vfs::load()
void cfg_vfs::save() const
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
const std::string path_to_cfg = fs::get_config_dir(true);
if (!fs::create_path(path_to_cfg))
{
vfs_log.error("Could not create path: %s", path_to_cfg);
@ -140,9 +140,5 @@ void cfg_vfs::save() const
std::string cfg_vfs::get_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/vfs.yml";
#else
return fs::get_config_dir() + "vfs.yml";
#endif
return fs::get_config_dir(true) + "vfs.yml";
}

View file

@ -125,6 +125,18 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
case QEvent::KeyRelease:
Key(static_cast<QKeyEvent*>(ev), false);
break;
case QEvent::Leave:
{
// Issue mouse move on leave. Otherwise we may not get any mouse event at the screen borders.
const QPoint window_pos = m_target->mapToGlobal(m_target->position()) / m_target->devicePixelRatio();
const QPoint cursor_pos = QCursor::pos() - window_pos;
if (cursor_pos.x() <= 0 || cursor_pos.x() >= m_target->width() || cursor_pos.y() <= 0 || cursor_pos.y() >= m_target->height())
{
MouseMove(cursor_pos);
}
break;
}
default:
return false;
}
@ -218,38 +230,44 @@ void basic_mouse_handler::MouseMove(QMouseEvent* event)
if (is_time_for_update())
{
// get the screen dimensions
const QSize screen = m_target->size();
const QPoint e_pos = event->pos();
if (m_target && m_target->isActive() && get_mouse_lock_state())
{
// get the center of the screen in global coordinates
QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2);
// reset the mouse to the center for consistent results since edge movement won't be registered
QCursor::setPos(m_target->screen(), p_center);
// convert the center into screen coordinates
p_center = m_target->mapFromGlobal(p_center);
// current mouse position, starting at the center
static QPoint p_real(p_center);
// get the delta of the mouse position to the screen center
const QPoint p_delta = e_pos - p_center;
// update the current position without leaving the screen borders
p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width()));
p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height()));
// pass the 'real' position and the current delta to the screen center
MouseHandlerBase::Move(0, p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y());
}
else
{
// pass the absolute position
MouseHandlerBase::Move(0, e_pos.x(), e_pos.y(), screen.width(), screen.height());
}
MouseMove(event->pos());
}
}
void basic_mouse_handler::MouseMove(const QPoint& e_pos)
{
if (!m_target) return;
// get the screen dimensions
const QSize screen = m_target->size();
if (m_target->isActive() && get_mouse_lock_state())
{
// get the center of the screen in global coordinates
QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2);
// reset the mouse to the center for consistent results since edge movement won't be registered
QCursor::setPos(m_target->screen(), p_center);
// convert the center into screen coordinates
p_center = m_target->mapFromGlobal(p_center);
// current mouse position, starting at the center
static QPoint p_real(p_center);
// get the delta of the mouse position to the screen center
const QPoint p_delta = e_pos - p_center;
// update the current position without leaving the screen borders
p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width()));
p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height()));
// pass the 'real' position and the current delta to the screen center
MouseHandlerBase::Move(0, p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y());
}
else
{
// pass the absolute position
MouseHandlerBase::Move(0, e_pos.x(), e_pos.y(), screen.width(), screen.height());
}
}

View file

@ -24,6 +24,7 @@ public:
void MouseButton(QMouseEvent* event, bool pressed);
void MouseScroll(QWheelEvent* event);
void MouseMove(QMouseEvent* event);
void MouseMove(const QPoint& e_pos);
bool eventFilter(QObject* obj, QEvent* ev) override;
private:

View file

@ -7,11 +7,7 @@ cfg_ps_moves g_cfg_move;
cfg_ps_moves::cfg_ps_moves()
: cfg::node()
#ifdef _WIN32
, path(fs::get_config_dir() + "config/ps_move.yml")
#else
, path(fs::get_config_dir() + "ps_move.yml")
#endif
, path(fs::get_config_dir(true) + "ps_move.yml")
{
}

View file

@ -96,7 +96,7 @@ bool raw_mice_config::load()
m_mutex.lock();
bool result = false;
const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id);
const std::string cfg_name = fmt::format("%s%s.yml", fs::get_config_dir(true), cfg_id);
cfg_log.notice("Loading %s config: %s", cfg_id, cfg_name);
from_default();
@ -123,7 +123,7 @@ void raw_mice_config::save()
{
std::lock_guard lock(m_mutex);
const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id);
const std::string cfg_name = fmt::format("%s%s.yml", fs::get_config_dir(true), cfg_id);
cfg_log.notice("Saving %s config to '%s'", cfg_id, cfg_name);
if (!fs::create_path(fs::get_parent_dir(cfg_name)))

View file

@ -115,14 +115,16 @@ LOG_CHANNEL(q_debug, "QDEBUG");
std::set<std::string> get_one_drive_paths()
{
std::set<std::string> paths;
for (const char* key : { "OneDrive", "OneDriveConsumer", "OneDriveCommercial" })
{
if (const char* env_path = std::getenv(key))
{
sys_log.notice("get_one_drive_paths: Found OneDrive env path: '%s' (key='%s')", env_path, key);
paths.insert(env_path);
}
}
// NOTE: Disabled. The environment variables can lead to false positives.
//for (const char* key : { "OneDrive", "OneDriveConsumer", "OneDriveCommercial" })
//{
// if (const char* env_path = std::getenv(key))
// {
// sys_log.notice("get_one_drive_paths: Found OneDrive env path: '%s' (key='%s')", env_path, key);
// paths.insert(env_path);
// }
//}
for (const wchar_t* key : { L"Software\\Microsoft\\OneDrive\\Accounts\\Personal" })
{
@ -135,7 +137,6 @@ std::set<std::string> get_one_drive_paths()
}
std::wstring path_buffer;
static_cast<DWORD>(path_buffer.size() - 1);
DWORD type = 0U;
do
@ -154,7 +155,7 @@ std::set<std::string> get_one_drive_paths()
if (status != ERROR_SUCCESS)
{
sys_log.error("get_one_drive_paths: RegQueryValueExW failed: %s", fmt::win_error{static_cast<unsigned long>(status), nullptr});
sys_log.trace("get_one_drive_paths: RegQueryValueExW failed: %s", fmt::win_error{static_cast<unsigned long>(status), nullptr});
continue;
}
@ -569,7 +570,7 @@ int main(int argc, char** argv)
}
const std::string lock_name = fs::get_cache_dir() + "RPCS3.buf";
const std::string log_name = fs::get_cache_dir() + "RPCS3.log";
const std::string log_name = fs::get_log_dir() + "RPCS3.log";
static fs::file instance_lock;

View file

@ -93,7 +93,7 @@ void emu_settings::LoadSettings(const std::string& title_id, bool create_config_
m_title_id = title_id;
// Create config path if necessary
fs::create_path(title_id.empty() ? fs::get_config_dir() : rpcs3::utils::get_custom_config_dir());
fs::create_path(title_id.empty() ? fs::get_config_dir(true) : rpcs3::utils::get_custom_config_dir());
// Load default config
auto [default_config, default_error] = yaml_load(g_cfg_defaults);
@ -113,7 +113,7 @@ void emu_settings::LoadSettings(const std::string& title_id, bool create_config_
if (create_config_from_global)
{
// Add global config
const std::string global_config_path = fs::get_config_dir() + "config.yml";
const std::string global_config_path = fs::get_config_dir(true) + "config.yml";
fs::g_tls_error = fs::error::ok;
fs::file config(global_config_path, fs::read + fs::create);
auto [global_config, global_error] = yaml_load(config ? config.to_string() : "");

View file

@ -157,7 +157,7 @@ log_frame::log_frame(std::shared_ptr<gui_settings> _gui_settings, QWidget* paren
setWidget(m_tabWidget);
// Open or create TTY.log
m_tty_file.open(fs::get_cache_dir() + "TTY.log", fs::read + fs::create);
m_tty_file.open(fs::get_log_dir() + "TTY.log", fs::read + fs::create);
CreateAndConnectActions();
LoadSettings();

View file

@ -2676,8 +2676,8 @@ void main_window::CreateConnects()
return;
}
const std::string archived_path = fs::get_cache_dir() + "RPCS3.log.gz";
const std::string raw_file_path = fs::get_cache_dir() + "RPCS3.log";
const std::string archived_path = fs::get_log_dir() + "RPCS3.log.gz";
const std::string raw_file_path = fs::get_log_dir() + "RPCS3.log";
fs::stat_t raw_stat{};
fs::stat_t archived_stat{};

View file

@ -13,19 +13,15 @@ namespace gui
{
std::string get_uuid_path()
{
#ifdef _WIN32
const std::string config_dir = fs::get_config_dir() + "config/";
const std::string config_dir = fs::get_config_dir(true);
const std::string uuid_path = config_dir + "uuid";
#ifdef _WIN32
if (!fs::create_path(config_dir))
{
uuid_log.error("Could not create path: %s (%s)", uuid_path, fs::g_tls_error);
}
return uuid_path;
#else
return fs::get_config_dir() + "uuid";
#endif
return uuid_path;
}
std::string make_uuid()