Merge branch 'master' into raw_mouse_fix

This commit is contained in:
Megamouse 2025-01-16 13:52:12 +01:00 committed by GitHub
commit ce736e3578
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 172 additions and 43 deletions

@ -1 +1 @@
Subproject commit f5e92d76973a7a53f517579bc95d61483bf108c0
Subproject commit 51f5bd68b9b806d2c92b4318164d28b49357da31

2
3rdparty/pugixml vendored

@ -1 +1 @@
Subproject commit db78afc2b7d8f043b4bc6b185635d949ea2ed2a8
Subproject commit ee86beb30e4973f5feffe3ce63bfa4fbadf72f38

View file

@ -21,7 +21,7 @@ using namespace std::literals::string_literals;
#include <cwchar>
#include <Windows.h>
static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
static std::unique_ptr<wchar_t[]> to_wchar(std::string_view source)
{
// String size + null terminator
const usz buf_size = source.size() + 1;
@ -44,7 +44,7 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
std::memcpy(buffer.get() + 32768 + 4, L"UNC\\", 4 * sizeof(wchar_t));
}
ensure(MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get() + 32768 + (unc ? 8 : 4), size)); // "to_wchar"
ensure(MultiByteToWideChar(CP_UTF8, 0, source.data(), size, buffer.get() + 32768 + (unc ? 8 : 4), size)); // "to_wchar"
// Canonicalize wide path (replace '/', ".", "..", \\ repetitions, etc)
ensure(GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1); // "to_wchar"

View file

@ -49,12 +49,11 @@ std::string rXmlNode::GetName()
return {};
}
std::string rXmlNode::GetAttribute(const std::string& name)
std::string rXmlNode::GetAttribute(std::string_view name)
{
if (handle)
{
const auto pred = [&name](const pugi::xml_attribute& attr) { return (name == attr.name()); };
if (const pugi::xml_attribute attr = handle.find_attribute(pred))
if (const pugi::xml_attribute attr = handle.attribute(name))
{
if (const pugi::char_t* value = attr.value())
{
@ -86,7 +85,7 @@ rXmlDocument::rXmlDocument()
{
}
pugi::xml_parse_result rXmlDocument::Read(const std::string& data)
pugi::xml_parse_result rXmlDocument::Read(std::string_view data)
{
if (handle)
{

View file

@ -23,7 +23,7 @@ struct rXmlNode
std::shared_ptr<rXmlNode> GetChildren();
std::shared_ptr<rXmlNode> GetNext();
std::string GetName();
std::string GetAttribute(const std::string& name);
std::string GetAttribute(std::string_view name);
std::string GetNodeContent();
pugi::xml_node handle{};
@ -34,7 +34,7 @@ struct rXmlDocument
rXmlDocument();
rXmlDocument(const rXmlDocument& other) = delete;
rXmlDocument &operator=(const rXmlDocument& other) = delete;
pugi::xml_parse_result Read(const std::string& data);
pugi::xml_parse_result Read(std::string_view data);
virtual std::shared_ptr<rXmlNode> GetRoot();
pugi::xml_document handle{};

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

@ -111,6 +111,65 @@ extern char **environ;
LOG_CHANNEL(sys_log, "SYS");
LOG_CHANNEL(q_debug, "QDEBUG");
#ifdef _WIN32
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);
}
}
for (const wchar_t* key : { L"Software\\Microsoft\\OneDrive\\Accounts\\Personal" })
{
HKEY hkey = NULL;
LSTATUS status = RegOpenKeyW(HKEY_CURRENT_USER, key, &hkey);
if (status != ERROR_SUCCESS)
{
sys_log.trace("get_one_drive_paths: RegOpenKeyW failed: %s (key='%s')", fmt::win_error{static_cast<unsigned long>(status), nullptr}, wchar_to_utf8(key));
continue;
}
std::wstring path_buffer;
static_cast<DWORD>(path_buffer.size() - 1);
DWORD type = 0U;
do
{
path_buffer.resize(path_buffer.size() + MAX_PATH);
DWORD buffer_size = static_cast<DWORD>(path_buffer.size() - 1);
status = RegQueryValueExW(hkey, L"UserFolder", NULL, &type, reinterpret_cast<LPBYTE>(path_buffer.data()), &buffer_size);
}
while (status == ERROR_MORE_DATA);
const LSTATUS close_status = RegCloseKey(hkey);
if (close_status != ERROR_SUCCESS)
{
sys_log.error("get_one_drive_paths: RegCloseKey failed: %s", fmt::win_error{static_cast<unsigned long>(close_status), nullptr});
}
if (status != ERROR_SUCCESS)
{
sys_log.error("get_one_drive_paths: RegQueryValueExW failed: %s", fmt::win_error{static_cast<unsigned long>(status), nullptr});
continue;
}
if ((type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ))
{
const std::string path = wchar_to_utf8(path_buffer.data());
sys_log.notice("get_one_drive_paths: Found OneDrive registry path: '%s' (key='%s')", path, wchar_to_utf8(key));
paths.insert(path);
}
}
return paths;
}
#endif
[[noreturn]] extern void report_fatal_error(std::string_view _text, bool is_html = false, bool include_help_text = true)
{
#ifdef __linux__
@ -1135,6 +1194,21 @@ int main(int argc, char** argv)
return 1;
}
}
#ifdef _WIN32
// Check OneDrive locations
for (const std::string& one_drive_path : get_one_drive_paths())
{
if (Emu.IsPathInsideDir(emu_dir, one_drive_path))
{
report_fatal_error(QObject::tr(
"RPCS3 should never be run from a OneDrive path!\n"
"Please move RPCS3 to a location not synced by OneDrive.\n"
"Current location:\n%0").arg(QString::fromStdString(emu_dir)).toStdString());
return 1;
}
}
#endif
}
// Set timerslack value for Linux. The default value is 50,000ns. Change this to just 1 since we value precise timers.