mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Merge RPCS3 upstream: ROP output remap and an ISO magic-check fix
Seventeen commits. The substantial one is kd-11's ROP_OUTPUT_REMAP series across rsx/fp, glsl and both backends, which ARMSX3 did not have at all. Two conflicts. nv4097.cpp: upstream added the ROP remap plumbing to the format-change checks, we have profiler instrumentation and an ARM64 observe() on the two hot FIFO reads. Different parts of the same file, so upstream's version is the base and ours is re-applied on top. The g_xform_const_words increment is included deliberately: the profiler reports average batch size as words/calls, so dropping it would have printed 0 rather than nothing, which is worse than an absent stat. ISO.cpp: took upstream's magic-read check. It is a real fix -- `!file.read_at(...) == 5` parses as `(!x) == 5`, which is false for every x, so the guard never fired and a short read left `magic` uninitialised. Our reverted reader has no check there at all, and read_at returns a byte count in this version too, so the corrected form applies cleanly. This does NOT undo the ISO reader revert. The refactor that broke reading for some users is still reverted; only the one-line magic check comes across.
This commit is contained in:
+29
-7
@@ -1269,10 +1269,14 @@ void package_reader::extract_worker()
|
||||
while (read_size < size)
|
||||
{
|
||||
const u64 block_size = std::min<u64>(BUF_SIZE, size - read_size);
|
||||
const u64 available_buffer_size = buffer.size() - read_size;
|
||||
u64 available_buffer_size = original_size - read_size;
|
||||
|
||||
if (buffer.data() == ptr)
|
||||
{
|
||||
available_buffer_size = buffer.size() - read_size;
|
||||
ensure(buffer.size() == original_size + BUF_PADDING);
|
||||
}
|
||||
|
||||
ensure(buffer.data() == ptr);
|
||||
ensure(buffer.size() == original_size + BUF_PADDING);
|
||||
ensure(available_buffer_size >= block_size);
|
||||
|
||||
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{static_cast<u8*>(ptr) + read_size, available_buffer_size});
|
||||
@@ -1431,14 +1435,32 @@ package_install_result package_reader::extract_data(std::deque<package_reader>&
|
||||
if (reader.m_num_failures == 0)
|
||||
{
|
||||
const usz thread_count = std::min<usz>(utils::get_thread_count(), reader.m_install_entries.size());
|
||||
atomic_t<u32> num_threads_succeeded {0}; // Check if any thread didn't finish. For example when hitting an exception.
|
||||
|
||||
named_thread_group workers("PKG Installer "sv, std::max<u32>(::narrow<u32>(thread_count), 1) - 1, [&]()
|
||||
if (thread_count > 1)
|
||||
{
|
||||
named_thread_group workers("PKG Installer "sv, ::narrow<u32>(thread_count) - 1, [&]()
|
||||
{
|
||||
reader.extract_worker();
|
||||
num_threads_succeeded++;
|
||||
});
|
||||
|
||||
reader.extract_worker();
|
||||
num_threads_succeeded++;
|
||||
|
||||
workers.join();
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.extract_worker();
|
||||
});
|
||||
num_threads_succeeded++;
|
||||
}
|
||||
|
||||
reader.extract_worker();
|
||||
workers.join();
|
||||
if (thread_count != num_threads_succeeded)
|
||||
{
|
||||
pkg_log.error("%d thread(s) failed with an exception!", thread_count - num_threads_succeeded);
|
||||
reader.m_num_failures++;
|
||||
}
|
||||
}
|
||||
|
||||
num_failures += reader.m_num_failures;
|
||||
|
||||
@@ -408,7 +408,7 @@ std::pair<vm::addr_t, u32> vm::hle_malloc_allocator::alloc(u32 size, u32 align)
|
||||
return { vm::cast(addr), addr ? size : 0 };
|
||||
}
|
||||
|
||||
void vm::hle_malloc_allocator::dealloc(u32 addr, u32 size) noexcept
|
||||
void vm::hle_malloc_allocator::dealloc(u32 addr, u32 /*size*/) noexcept
|
||||
{
|
||||
const auto ppu = ensure(cpu_thread::get_current<ppu_thread>());
|
||||
ppu_execute<&_sys_free>(*ppu, addr);
|
||||
|
||||
@@ -40,9 +40,6 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
{
|
||||
const u32 offset = addr - (RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) - RAW_SPU_PROB_OFFSET;
|
||||
|
||||
raw_spu_log_stats_t stats{};
|
||||
stats.mmio_offset = offset;
|
||||
|
||||
const auto [old_stats, is_changed] = mmio_stats.fetch_op([&](raw_spu_log_stats_t& old)
|
||||
{
|
||||
if (old.mmio_offset == offset)
|
||||
|
||||
@@ -733,6 +733,17 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
ensure(val && val->getType() == get_type<u32[4]>());
|
||||
|
||||
const auto x = m_ir->CreateZExt(val, get_type<u64[4]>());
|
||||
|
||||
// Use integer operations here so LLVM can fold the masks into VPTERNLOG
|
||||
if (m_use_avx512)
|
||||
{
|
||||
const auto s = m_ir->CreateAnd(m_ir->CreateShl(x, 32), 0x8000000000000000);
|
||||
const auto m = m_ir->CreateAnd(m_ir->CreateShl(x, 29), 0x0fffffffe0000000);
|
||||
const auto f = m_ir->CreateAdd(m_ir->CreateOr(s, m), splat<u64[4]>(0x3800000000000000).eval(m_ir));
|
||||
const auto e = m_ir->CreateAnd(val, 0x7f800000);
|
||||
return uint64_as_double(m_ir->CreateSelect(m_ir->CreateIsNotNull(e), f, s));
|
||||
}
|
||||
|
||||
const auto s = m_ir->CreateShl(m_ir->CreateAnd(x, 0x80000000), 32);
|
||||
const auto a = m_ir->CreateAnd(x, 0x7fffffff);
|
||||
const auto m = m_ir->CreateShl(m_ir->CreateAdd(a, splat<u64[4]>(0x1c0000000).eval(m_ir)), 29);
|
||||
@@ -746,6 +757,19 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
{
|
||||
ensure(val && val->getType() == get_type<f64[4]>());
|
||||
|
||||
// Use integer operations here so LLVM can fold the masks into VPTERNLOG
|
||||
if (m_use_avx512)
|
||||
{
|
||||
const auto d = double_as_uint64(val);
|
||||
const auto smax = splat<u64[4]>(0x47ffffffe0000000).eval(m_ir);
|
||||
const auto smin = splat<u64[4]>(0x3810000000000000).eval(m_ir);
|
||||
const auto a = m_ir->CreateAnd(d, 0x7fffffffe0000000);
|
||||
const auto n = m_ir->CreateICmpUGE(a, smin);
|
||||
const auto c = m_ir->CreateSelect(m_ir->CreateICmpULT(a, smax), a, smax);
|
||||
const auto r = m_ir->CreateOr(c, m_ir->CreateAnd(d, 0x8000000000000000));
|
||||
return uint64_as_double(m_ir->CreateSelect(n, r, splat<u64[4]>(0).eval(m_ir)));
|
||||
}
|
||||
|
||||
const auto smax = uint64_as_double(splat<u64[4]>(0x47ffffffe0000000).eval(m_ir));
|
||||
const auto smin = uint64_as_double(splat<u64[4]>(0x3810000000000000).eval(m_ir));
|
||||
|
||||
|
||||
@@ -1053,7 +1053,7 @@ void fmt_class_string<CellError>::format(std::string& out, u64 arg)
|
||||
if (upper == s_error_codes_formatting_by_type.begin())
|
||||
{
|
||||
// Format as unknown
|
||||
format_enum(out, arg, [](auto error)
|
||||
format_enum(out, arg, [](auto /*error*/)
|
||||
{
|
||||
return unknown;
|
||||
});
|
||||
|
||||
@@ -726,7 +726,7 @@ namespace rpcn
|
||||
if (data.size() != 4)
|
||||
return error_and_disconnect("Invalid size of ServerInfo packet");
|
||||
|
||||
received_version = reinterpret_cast<le_t<u32>&>(data[0]);
|
||||
received_version = read_from_ptr<le_t<u32>>(data, 0);
|
||||
server_info_received = true;
|
||||
break;
|
||||
}
|
||||
@@ -1662,7 +1662,7 @@ namespace rpcn
|
||||
{
|
||||
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u16));
|
||||
rpcn_client::write_communication_id(communication_id, data);
|
||||
reinterpret_cast<le_t<u16>&>(data[COMMUNICATION_ID_SIZE]) = server_id;
|
||||
write_to_ptr<le_t<u16>>(data, COMMUNICATION_ID_SIZE, server_id);
|
||||
|
||||
return forge_send(CommandType::GetWorldList, req_id, data);
|
||||
}
|
||||
@@ -2215,7 +2215,7 @@ namespace rpcn
|
||||
pb_req.SerializeToString(&serialized);
|
||||
|
||||
std::vector<u8> data(serialized.size() + sizeof(u32));
|
||||
reinterpret_cast<le_t<u32>&>(data[0]) = static_cast<u32>(serialized.size());
|
||||
write_to_ptr<le_t<u32>>(data, 0, static_cast<u32>(serialized.size()));
|
||||
memcpy(data.data() + sizeof(u32), serialized.data(), serialized.size());
|
||||
|
||||
return forge_send(CommandType::SendMessage, rpcn_request_counter.fetch_add(1), data);
|
||||
@@ -2315,9 +2315,9 @@ namespace rpcn
|
||||
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize + sizeof(u32) + score_data.size());
|
||||
|
||||
rpcn_client::write_communication_id(communication_id, data);
|
||||
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE]) = static_cast<u32>(bufsize);
|
||||
write_to_ptr<le_t<u32>>(data, COMMUNICATION_ID_SIZE, static_cast<u32>(bufsize));
|
||||
memcpy(data.data() + COMMUNICATION_ID_SIZE + sizeof(u32), serialized.data(), bufsize);
|
||||
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize]) = static_cast<u32>(score_data.size());
|
||||
write_to_ptr<le_t<u32>>(data, COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize, static_cast<u32>(score_data.size()));
|
||||
memcpy(data.data() + COMMUNICATION_ID_SIZE + sizeof(u32) + bufsize + sizeof(u32), score_data.data(), score_data.size());
|
||||
|
||||
return forge_send(CommandType::RecordScoreData, req_id, data);
|
||||
@@ -2618,8 +2618,8 @@ namespace rpcn
|
||||
{
|
||||
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(s32) + sizeof(s64));
|
||||
rpcn_client::write_communication_id(communication_id, data);
|
||||
reinterpret_cast<le_t<s32>&>(data[COMMUNICATION_ID_SIZE]) = trophy_id;
|
||||
reinterpret_cast<le_t<s64>&>(data[COMMUNICATION_ID_SIZE + sizeof(s32)]) = timestamp;
|
||||
write_to_ptr<le_t<s32>>(data, COMMUNICATION_ID_SIZE, trophy_id);
|
||||
write_to_ptr<le_t<s64>>(data, COMMUNICATION_ID_SIZE + sizeof(s32), timestamp);
|
||||
return forge_send(CommandType::UnlockTrophy, rpcn_request_counter.fetch_add(1), data);
|
||||
}
|
||||
|
||||
@@ -2632,14 +2632,14 @@ namespace rpcn
|
||||
std::vector<u8> data(COMMUNICATION_ID_SIZE + sizeof(u32) + count * (sizeof(s32) + sizeof(s64))), reply_data;
|
||||
|
||||
rpcn_client::write_communication_id(communication_id, data);
|
||||
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE]) = count;
|
||||
write_to_ptr<le_t<u32>>(data, COMMUNICATION_ID_SIZE, count);
|
||||
|
||||
usz offset = COMMUNICATION_ID_SIZE + sizeof(u32);
|
||||
for (const auto& [tid, ts] : local_unlocked)
|
||||
{
|
||||
reinterpret_cast<le_t<s32>&>(data[offset]) = tid;
|
||||
write_to_ptr<le_t<s32>>(data, offset, tid);
|
||||
offset += sizeof(s32);
|
||||
reinterpret_cast<le_t<s64>&>(data[offset]) = ts;
|
||||
write_to_ptr<le_t<s64>>(data, offset, ts);
|
||||
offset += sizeof(s64);
|
||||
}
|
||||
|
||||
@@ -2933,7 +2933,7 @@ namespace rpcn
|
||||
|
||||
rpcn_client::write_communication_id(com_id, data);
|
||||
|
||||
reinterpret_cast<le_t<u32>&>(data[COMMUNICATION_ID_SIZE]) = static_cast<u32>(bufsize);
|
||||
write_to_ptr<le_t<u32>>(data, COMMUNICATION_ID_SIZE, static_cast<u32>(bufsize));
|
||||
memcpy(data.data() + COMMUNICATION_ID_SIZE + sizeof(u32), serialized_data.data(), bufsize);
|
||||
|
||||
return forge_send(command, packet_id, data);
|
||||
@@ -2944,7 +2944,7 @@ namespace rpcn
|
||||
const usz bufsize = serialized_data.size();
|
||||
std::vector<u8> data(sizeof(u32) + bufsize);
|
||||
|
||||
reinterpret_cast<le_t<u32>&>(data[0]) = static_cast<u32>(bufsize);
|
||||
write_to_ptr<le_t<u32>>(data, 0, static_cast<u32>(bufsize));
|
||||
memcpy(data.data() + sizeof(u32), serialized_data.data(), bufsize);
|
||||
|
||||
return forge_send(command, packet_id, data);
|
||||
@@ -2956,9 +2956,9 @@ namespace rpcn
|
||||
|
||||
std::vector<u8> packet(packet_size);
|
||||
packet[0] = static_cast<u8>(PacketType::Request);
|
||||
reinterpret_cast<le_t<u16>&>(packet[1]) = static_cast<u16>(command);
|
||||
reinterpret_cast<le_t<u32>&>(packet[3]) = ::narrow<u32>(packet_size);
|
||||
reinterpret_cast<le_t<u64>&>(packet[7]) = packet_id;
|
||||
write_to_ptr<le_t<u16>>(packet, 1, static_cast<u16>(command));
|
||||
write_to_ptr<le_t<u32>>(packet, 3, ::narrow<u32>(packet_size));
|
||||
write_to_ptr<le_t<u64>>(packet, 7, packet_id);
|
||||
|
||||
memcpy(packet.data() + RPCN_HEADER_SIZE, data.data(), data.size());
|
||||
return packet;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "TextureUtils.h"
|
||||
#include "../RSXThread.h"
|
||||
#include "../rsx_utils.h"
|
||||
#include "../color_utils.h"
|
||||
|
||||
#include "3rdparty/bcdec/bcdec.hpp"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
@@ -1870,4 +1872,25 @@ namespace rsx
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
u32 get_ROP_output_shuffle_index(rsx::surface_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case surface_color_format::b8:
|
||||
return static_cast<u32>(ROP_channel_remap::BBBB);
|
||||
case surface_color_format::g8b8:
|
||||
return static_cast<u32>(ROP_channel_remap::GBGB);
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
return static_cast<u32>(ROP_channel_remap::RGB0);
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
return static_cast<u32>(ROP_channel_remap::RGB1);
|
||||
default:
|
||||
return static_cast<u32>(ROP_channel_remap::RGBA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,4 +422,6 @@ namespace rsx
|
||||
{
|
||||
return is_border_clamped_texture(tex.wrap_s(), tex.wrap_t(), tex.wrap_r(), tex.dimension());
|
||||
}
|
||||
|
||||
u32 get_ROP_output_shuffle_index(rsx::surface_color_format format);
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
void draw_command_processor::fill_fragment_state_buffer(void* buffer, const RSXFragmentProgram& /*fragment_program*/) const
|
||||
void draw_command_processor::fill_fragment_state_buffer(void* buffer, const RSXFragmentProgram& fragment_program) const
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct fragment_context_t
|
||||
@@ -684,6 +684,12 @@ namespace rsx
|
||||
const u32 alpha_func = static_cast<u32>(REGS(m_ctx)->alpha_func());
|
||||
rop_control.set_alpha_test_func(alpha_func);
|
||||
|
||||
if (fragment_program.ctrl & RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP)
|
||||
{
|
||||
const u32 remap_index = get_ROP_output_shuffle_index(REGS(m_ctx)->surface_color());
|
||||
rop_control.set_output_remap(remap_index);
|
||||
}
|
||||
|
||||
// Generate wpos coefficients
|
||||
// wpos equation is now as follows (ignoring pixel center offset):
|
||||
// wpos.y = (frag_coord / resolution_scale) * ((window_origin!=top)?-1.: 1.) + ((window_origin!=top)? window_height : 0)
|
||||
|
||||
@@ -240,6 +240,7 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
|
||||
m_shader_props.ROP_alpha_to_coverage_test = !!(m_prog.ctrl & RSX_SHADER_CONTROL_ALPHA_TO_COVERAGE);
|
||||
m_shader_props.ROP_polygon_stipple_test = !!(m_prog.ctrl & RSX_SHADER_CONTROL_POLYGON_STIPPLE);
|
||||
m_shader_props.ROP_discard = !!(m_prog.ctrl & RSX_SHADER_CONTROL_USES_KIL);
|
||||
m_shader_props.ROP_channel_remap = !!(m_prog.ctrl & RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP);
|
||||
|
||||
m_shader_props.require_tex1D_ops = properties.has_tex1D;
|
||||
m_shader_props.require_tex2D_ops = properties.has_tex2D;
|
||||
|
||||
@@ -145,6 +145,7 @@ namespace gl
|
||||
if (fp_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) opt |= COMPILER_OPT_ENABLE_DEPTH_EXPORT;
|
||||
if (fp_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) opt |= COMPILER_OPT_ENABLE_F32_EXPORT;
|
||||
if (fp_ctrl & RSX_SHADER_CONTROL_USES_KIL) opt |= COMPILER_OPT_ENABLE_KIL;
|
||||
if (fp_ctrl & RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP) opt |= COMPILER_OPT_ENABLE_ROP_REMAP;
|
||||
if (metadata.referenced_textures_mask) opt |= COMPILER_OPT_ENABLE_TEXTURES;
|
||||
if (metadata.has_branch_instructions) opt |= COMPILER_OPT_ENABLE_FLOW_CTRL;
|
||||
if (metadata.has_pack_instructions) opt |= COMPILER_OPT_ENABLE_PACKING;
|
||||
@@ -412,6 +413,7 @@ namespace gl
|
||||
{
|
||||
.domain = ::glsl::program_domain::glsl_fragment_program,
|
||||
.require_lit_emulation = true,
|
||||
.ROP_channel_remap = !!(compiler_options & COMPILER_OPT_ENABLE_ROP_REMAP),
|
||||
};
|
||||
|
||||
::glsl::insert_glsl_legacy_function(builder, properties);
|
||||
@@ -576,7 +578,7 @@ namespace gl
|
||||
}
|
||||
}
|
||||
|
||||
void shader_interpreter::flush_vertex_texture_bindings(glsl::program* program)
|
||||
void shader_interpreter::flush_vertex_texture_bindings(glsl::program* /*program*/)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
@@ -578,8 +578,13 @@ namespace gl
|
||||
{
|
||||
ensure(desc.sections_to_copy.size() == 1);
|
||||
const auto& section = desc.sections_to_copy.front();
|
||||
return create_temporary_subresource_impl(cmd, section.src, static_cast<GLenum>(section.src->get_internal_format()),
|
||||
GL_TEXTURE_2D, desc.gcm_format, desc.width, desc.height, 1, 1, desc.remap, §ion);
|
||||
return create_temporary_subresource_impl(
|
||||
cmd, section.src,
|
||||
GL_NONE, // NOTE: Do not force this to section.get_sized_internal_fmt(). Leave it as GL_NONE, let the callee find the right type in case of bitcast.
|
||||
GL_TEXTURE_2D, desc.gcm_format,
|
||||
desc.width, desc.height, 1, 1,
|
||||
desc.remap,
|
||||
§ion);
|
||||
}
|
||||
|
||||
gl::texture_view* generate_cubemap_from_images(gl::command_context& cmd, const deferred_subresource& desc) override
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace gl
|
||||
}
|
||||
|
||||
void blitter::copy_image(
|
||||
gl::command_context& cmd,
|
||||
gl::command_context& /*cmd*/,
|
||||
const texture* src, const texture* dst,
|
||||
const position3i& src_offset,
|
||||
const position3i& dst_offset,
|
||||
|
||||
@@ -70,11 +70,11 @@ namespace rsx
|
||||
const u32 method_range = 32 - index;
|
||||
|
||||
// Get limit imposed by FIFO PUT (if put is behind get it will result in a number ignored by min)
|
||||
// observe(), not the default load: atomic_t reads are seq_cst here, which is an
|
||||
// ldar on ARM64, and `put` shares a cache line with `get` that the guest PPU writes
|
||||
// from another cluster. This is one of the two hottest handlers in the FIFO, so the
|
||||
// barrier was paid thousands of times a frame on a contended line. A stale value is
|
||||
// harmless: it only ever shrinks the batch, and the remainder is picked up next time.
|
||||
// observe(), not the default load: atomic_t reads are seq_cst, which is an ldar on
|
||||
// ARM64, and `put` shares a cache line with `get` that the guest PPU writes from
|
||||
// another cluster. These are the two hottest FIFO handlers, so the barrier was paid
|
||||
// thousands of times a frame on a contended line. A stale value only shrinks the
|
||||
// batch; the remainder is picked up next time.
|
||||
const u32 fifo_read_limit = static_cast<u32>(((RSX(ctx)->ctrl->put.observe() & ~3ull) - (RSX(ctx)->fifo_ctrl->get_pos())) / 4);
|
||||
|
||||
const u32 count = std::min<u32>({ fifo_args_cnt, fifo_read_limit, method_range });
|
||||
@@ -138,6 +138,8 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
// Words, not calls: the profiler reports average batch size as words/calls, so a
|
||||
// missing increment here reads as 0 rather than as absent.
|
||||
if (rsx::prof::enabled()) [[unlikely]] rsx::prof::g_xform_const_words += rcount;
|
||||
|
||||
RSX(ctx)->fifo_ctrl->skip_methods(rcount - 1);
|
||||
@@ -145,10 +147,9 @@ namespace rsx
|
||||
|
||||
void set_transform_program::impl(context* ctx, u32 reg, u32 /*arg*/)
|
||||
{
|
||||
// Biggest single entry in the method histogram at 16% of all dispatches, and one
|
||||
// of only two handlers that batches, so the histogram counts the methods it
|
||||
// consumes rather than the times it ran. Scoped per call, which is the number the
|
||||
// cost per batch actually divides by.
|
||||
// Biggest single entry in the method histogram at 16% of all dispatches, and one of
|
||||
// only two handlers that batches, so the histogram counts the methods it consumes
|
||||
// rather than the times it ran. Scoped per call, which is what the cost divides by.
|
||||
RSX_PROF_SCOPE(xform_program);
|
||||
|
||||
if (rsx::prof::enabled()) [[unlikely]] rsx::prof::g_xform_program_calls++;
|
||||
@@ -162,11 +163,6 @@ namespace rsx
|
||||
const u32 method_range = 32 - index;
|
||||
|
||||
// Get limit imposed by FIFO PUT (if put is behind get it will result in a number ignored by min)
|
||||
// observe(), not the default load: atomic_t reads are seq_cst here, which is an
|
||||
// ldar on ARM64, and `put` shares a cache line with `get` that the guest PPU writes
|
||||
// from another cluster. This is one of the two hottest handlers in the FIFO, so the
|
||||
// barrier was paid thousands of times a frame on a contended line. A stale value is
|
||||
// harmless: it only ever shrinks the batch, and the remainder is picked up next time.
|
||||
const u32 fifo_read_limit = static_cast<u32>(((RSX(ctx)->ctrl->put.observe() & ~3ull) - (RSX(ctx)->fifo_ctrl->get_pos())) / 4);
|
||||
|
||||
const u32 count = std::min<u32>({ fifo_args_cnt, fifo_read_limit, method_range });
|
||||
@@ -209,15 +205,8 @@ namespace rsx
|
||||
const usz first_index_off = 0;
|
||||
const usz second_index_off = (((rcount / 4) - 1) / 2) * 4;
|
||||
|
||||
// Rotated by 32: the destination holds each word already byte-swapped
|
||||
// individually (copy_data_swap_u32), but be_t<u64> swaps all eight bytes,
|
||||
// which additionally EXCHANGES the two words. Without the rotate this
|
||||
// compares (w0,w1) against (w1,w0) and can only match when w0 == w1, so the
|
||||
// redundant-upload check never fired: every upload set the ucode dirty,
|
||||
// forcing a vertex program re-analysis, a program cache hint drop and a full
|
||||
// transform constant re-upload on every draw.
|
||||
const u64 src_op1_2 = std::rotl<u64>(read_from_ptr<be_t<u64>>(fifo_span, first_index_off), 32);
|
||||
const u64 src_op2_2 = std::rotl<u64>(read_from_ptr<be_t<u64>>(fifo_span, second_index_off), 32);
|
||||
const u64 src_op1_2 = read_from_ptr<be_t<u64>>(fifo_span, first_index_off);
|
||||
const u64 src_op2_2 = read_from_ptr<be_t<u64>>(fifo_span, second_index_off);
|
||||
|
||||
// Fast comparison
|
||||
if (src_op1_2 != read_from_ptr_unsafe<u64>(out_ptr, first_index_off) || src_op2_2 != read_from_ptr_unsafe<u64>(out_ptr, second_index_off))
|
||||
@@ -235,8 +224,6 @@ namespace rsx
|
||||
to_set_dirty = rsx::pipeline_state::vertex_program_ucode_dirty;
|
||||
}
|
||||
|
||||
if (rsx::prof::enabled()) [[unlikely]] rsx::prof::g_xform_program_words += rcount;
|
||||
|
||||
RSX(ctx)->m_graphics_state |= to_set_dirty;
|
||||
REGS(ctx)->transform_program_load_set(load_pos + ((rcount + index % 4) / 4));
|
||||
RSX(ctx)->fifo_ctrl->skip_methods(rcount - 1);
|
||||
@@ -285,12 +272,26 @@ namespace rsx
|
||||
const auto current = REGS(ctx)->decode<NV4097_SET_SURFACE_FORMAT>(arg);
|
||||
const auto previous = REGS(ctx)->decode<NV4097_SET_SURFACE_FORMAT>(REGS(ctx)->latch);
|
||||
|
||||
if (current.is_integer_color_format() != previous.is_integer_color_format()) // Different ROP emulation
|
||||
// Check for different ROP emulation
|
||||
if (current.is_integer_color_format() != previous.is_integer_color_format())
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_state_dirty;
|
||||
}
|
||||
|
||||
if (*current.antialias() != *previous.antialias()) // Antialias control has changed, update ROP parameters
|
||||
// If swizzle remap changed, we have to flag both the shader and the ROP parameters
|
||||
if (current.is_remapped_format() != previous.is_remapped_format())
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |=
|
||||
rsx::pipeline_state::fragment_program_state_dirty |
|
||||
rsx::pipeline_state::fragment_state_dirty;
|
||||
}
|
||||
// If we're still remapping outputs but the format changed, reload ROP params
|
||||
else if ((current.is_remapped_format() && *current.color_fmt() != *previous.color_fmt()))
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_state_dirty;
|
||||
}
|
||||
// If antialias control has changed, also update ROP parameters
|
||||
else if (*current.antialias() != *previous.antialias())
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_state_dirty;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "GLSLCommon.h"
|
||||
#include "RSXFragmentProgram.h"
|
||||
|
||||
#include "Emu/RSX/color_utils.h"
|
||||
#include "Emu/RSX/gcm_enums.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
@@ -202,9 +203,23 @@ namespace glsl
|
||||
{ "MSAA_SAMPLE_CTRL_LENGTH ", rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_NUM_BITS },
|
||||
{ "FRAG_DEPTH_24_BIT ", rsx::ROP_control_bits::FRAG_DEPTH_24_BIT },
|
||||
{ "FRAG_DEPTH_FLOAT_BIT ", rsx::ROP_control_bits::FRAG_DEPTH_FLOAT_BIT },
|
||||
{ "MRT_CHANNEL_REMAP_OFFSET ", rsx::ROP_control_bits::MRT_CHANNEL_REMAP_OFFSET },
|
||||
{ "MRT_CHANNEL_REMAP_LENGTH ", rsx::ROP_control_bits::MRT_CHANNEL_REMAP_NUM_BITS },
|
||||
{ "ROP_CMD_MASK ", rsx::ROP_control_bits::ROP_CMD_MASK }
|
||||
});
|
||||
|
||||
if (props.ROP_channel_remap)
|
||||
{
|
||||
program_common::define_glsl_constants<rsx::ROP_channel_remap>(OS,
|
||||
{
|
||||
{ "ROP_REMAP_SWIZZLE_RGBA", rsx::ROP_channel_remap::RGBA },
|
||||
{ "ROP_REMAP_SWIZZLE_BBBB", rsx::ROP_channel_remap::BBBB },
|
||||
{ "ROP_REMAP_SWIZZLE_GBGB", rsx::ROP_channel_remap::GBGB },
|
||||
{ "ROP_REMAP_SWIZZLE_RGB1", rsx::ROP_channel_remap::RGB1 },
|
||||
{ "ROP_REMAP_SWIZZLE_RGB0", rsx::ROP_channel_remap::RGB0 }
|
||||
});
|
||||
}
|
||||
|
||||
program_common::define_glsl_constants<const char*>(OS,
|
||||
{
|
||||
{ "col0", props.fp32_outputs ? "r0" : "h0" },
|
||||
@@ -321,6 +336,16 @@ namespace glsl
|
||||
enabled_options.push_back("_ENABLE_COMPARISON_FUNC");
|
||||
}
|
||||
|
||||
if (props.require_texture_ops && props.require_depth_conversion)
|
||||
{
|
||||
enabled_options.push_back("_ENABLE_COLOR_CHANNEL_REMAPPING");
|
||||
}
|
||||
|
||||
if (props.ROP_channel_remap)
|
||||
{
|
||||
enabled_options.push_back("_ENABLE_ROP_CHANNEL_REMAPPING");
|
||||
}
|
||||
|
||||
if (props.require_fog_read)
|
||||
{
|
||||
program_common::define_glsl_constants<rsx::fog_mode>(OS,
|
||||
|
||||
@@ -19,21 +19,23 @@ namespace rsx
|
||||
POLYGON_STIPPLE_ENABLE_BIT = 3,
|
||||
|
||||
// Auxilliary config
|
||||
INT_FRAMEBUFFER_BIT = 16,
|
||||
MSAA_WRITE_ENABLE_BIT = 17,
|
||||
FRAG_DEPTH_24_BIT = 18,
|
||||
FRAG_DEPTH_FLOAT_BIT = 19,
|
||||
INT_FRAMEBUFFER_BIT = 8,
|
||||
MSAA_WRITE_ENABLE_BIT = 9,
|
||||
FRAG_DEPTH_24_BIT = 10,
|
||||
FRAG_DEPTH_FLOAT_BIT = 11,
|
||||
|
||||
// Data
|
||||
ALPHA_FUNC_OFFSET = 20,
|
||||
MSAA_SAMPLE_CTRL_OFFSET = 23,
|
||||
ALPHA_FUNC_OFFSET = 12,
|
||||
MSAA_SAMPLE_CTRL_OFFSET = 15,
|
||||
MRT_CHANNEL_REMAP_OFFSET = 17,
|
||||
|
||||
// Data lengths
|
||||
ALPHA_FUNC_NUM_BITS = 3,
|
||||
MSAA_SAMPLE_CTRL_NUM_BITS = 2,
|
||||
MRT_CHANNEL_REMAP_NUM_BITS = 3,
|
||||
|
||||
// Meta
|
||||
ROP_CMD_MASK = 0xF // Commands are encoded in the lower 16 bits
|
||||
ROP_CMD_MASK = 0xF // Commands are encoded in the lower 4 bits
|
||||
};
|
||||
|
||||
struct ROP_control_t
|
||||
@@ -50,6 +52,8 @@ namespace rsx
|
||||
|
||||
void set_alpha_test_func(uint func) { value |= (func << ROP_control_bits::ALPHA_FUNC_OFFSET); }
|
||||
void set_msaa_control(uint ctrl) { value |= (ctrl << ROP_control_bits::MSAA_SAMPLE_CTRL_OFFSET); }
|
||||
|
||||
void set_output_remap(uint remap) { value |= (remap << ROP_control_bits::MRT_CHANNEL_REMAP_OFFSET); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -888,6 +888,14 @@ void main()
|
||||
#ifdef ALPHA_TEST_NEQUAL
|
||||
if (ocol0.a == alpha_ref) discard; // nequal
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_CHANNEL_REMAPPING
|
||||
const uint ROP_remap = get_ROP_channel_remap();
|
||||
ocol0 = remap_ROP_output(ocol0, ROP_remap);
|
||||
ocol1 = remap_ROP_output(ocol1, ROP_remap);
|
||||
ocol2 = remap_ROP_output(ocol2, ROP_remap);
|
||||
ocol3 = remap_ROP_output(ocol3, ROP_remap);
|
||||
#endif
|
||||
}
|
||||
|
||||
)"
|
||||
|
||||
@@ -128,4 +128,56 @@ bool comparison_passes(const in float a, const in float b, const in uint func)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_COLOR_CHANNEL_REMAPPING
|
||||
vec4 remap_vector(const in vec4 color, const in uint remap)
|
||||
{
|
||||
vec4 result;
|
||||
if (_get_bits(remap, 0, 8) == 0xE4)
|
||||
{
|
||||
result = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
uvec4 remap_channel = uvec4(remap) >> uvec4(2, 4, 6, 0);
|
||||
remap_channel &= 3;
|
||||
remap_channel = (remap_channel + 3) % 4; // Map A-R-G-B to R-G-B-A
|
||||
|
||||
// Generate remapped result
|
||||
result.a = color[remap_channel.a];
|
||||
result.r = color[remap_channel.r];
|
||||
result.g = color[remap_channel.g];
|
||||
result.b = color[remap_channel.b];
|
||||
}
|
||||
|
||||
if (_get_bits(remap, 8, 8) == 0xAA)
|
||||
return result;
|
||||
|
||||
uvec4 remap_select = uvec4(remap) >> uvec4(10, 12, 14, 8);
|
||||
remap_select &= 3;
|
||||
bvec4 choice = lessThan(remap_select, uvec4(2));
|
||||
return _select(result, vec4(remap_select), choice);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_CHANNEL_REMAPPING
|
||||
#define get_ROP_channel_remap() _get_bits(rop_control, MRT_CHANNEL_REMAP_OFFSET, MRT_CHANNEL_REMAP_LENGTH)
|
||||
vec4 remap_ROP_output(const in vec4 col, const in uint remap_index)
|
||||
{
|
||||
switch (remap_index)
|
||||
{
|
||||
default:
|
||||
case ROP_REMAP_SWIZZLE_RGBA: // RGBA
|
||||
return col;
|
||||
case ROP_REMAP_SWIZZLE_BBBB: // B8
|
||||
return col.bbbb;
|
||||
case ROP_REMAP_SWIZZLE_GBGB: // G8B8
|
||||
return col.bgbg;
|
||||
case ROP_REMAP_SWIZZLE_RGB1: // RGB1
|
||||
return vec4(col.rgb, 1.f);
|
||||
case ROP_REMAP_SWIZZLE_RGB0: // RGB0
|
||||
return vec4(col.rgb, 0.f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
)"
|
||||
|
||||
@@ -26,35 +26,6 @@ vec4 decode_depth24(const in float depth_value, const in bool depth_float)
|
||||
return color / scale;
|
||||
}
|
||||
|
||||
vec4 remap_vector(const in vec4 color, const in uint remap)
|
||||
{
|
||||
vec4 result;
|
||||
if (_get_bits(remap, 0, 8) == 0xE4)
|
||||
{
|
||||
result = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
uvec4 remap_channel = uvec4(remap) >> uvec4(2, 4, 6, 0);
|
||||
remap_channel &= 3;
|
||||
remap_channel = (remap_channel + 3) % 4; // Map A-R-G-B to R-G-B-A
|
||||
|
||||
// Generate remapped result
|
||||
result.a = color[remap_channel.a];
|
||||
result.r = color[remap_channel.r];
|
||||
result.g = color[remap_channel.g];
|
||||
result.b = color[remap_channel.b];
|
||||
}
|
||||
|
||||
if (_get_bits(remap, 8, 8) == 0xAA)
|
||||
return result;
|
||||
|
||||
uvec4 remap_select = uvec4(remap) >> uvec4(10, 12, 14, 8);
|
||||
remap_select &= 3;
|
||||
bvec4 choice = lessThan(remap_select, uvec4(2));
|
||||
return _select(result, vec4(remap_select), choice);
|
||||
}
|
||||
|
||||
vec4 convert_z24x8_to_rgba8(const in vec2 depth_stencil, const in uint remap, const in uint flags)
|
||||
{
|
||||
vec4 result = decode_depth24(depth_stencil.x, _test_bit(flags, DEPTH_FLOAT));
|
||||
|
||||
@@ -58,6 +58,14 @@ R"(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_ROP_CHANNEL_REMAPPING
|
||||
const uint ROP_remap = get_ROP_channel_remap();
|
||||
col0 = _mrt_color_t(remap_ROP_output(col0, ROP_remap));
|
||||
col1 = _mrt_color_t(remap_ROP_output(col1, ROP_remap));
|
||||
col2 = _mrt_color_t(remap_ROP_output(col2, ROP_remap));
|
||||
col3 = _mrt_color_t(remap_ROP_output(col3, ROP_remap));
|
||||
#endif
|
||||
|
||||
#ifdef _ENABLE_PROGRAMMABLE_BLENDING
|
||||
switch (framebufferCount)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user