diff --git a/rpcs3/Emu/RSX/Common/buffer_stream.hpp b/rpcs3/Emu/RSX/Common/buffer_stream.hpp index ff68d6008d..5cf4da22fa 100644 --- a/rpcs3/Emu/RSX/Common/buffer_stream.hpp +++ b/rpcs3/Emu/RSX/Common/buffer_stream.hpp @@ -40,10 +40,15 @@ namespace utils /** * Stream a 128 bits vector from src to dst. */ - static inline - void stream_vector_from_memory(void* dst, void* src) + template + void stream_vector_from_memory(void* dst, void* src) { - const __m128i vector = _mm_loadu_si128(reinterpret_cast<__m128i*>(src)); - _mm_stream_si128(reinterpret_cast<__m128i*>(dst), vector); + auto _src = reinterpret_cast<__m128i*>(src); + auto _dst = reinterpret_cast<__m128i*>(dst); + for (int i = 0; i < Count; ++i, ++_src, ++_dst) + { + const __m128i vector = _mm_loadu_si128(_src); + _mm_stream_si128(_dst, vector); + } } } diff --git a/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp b/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp index 46edb42175..449900cef1 100644 --- a/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp +++ b/rpcs3/Emu/RSX/Core/RSXDrawCommands.cpp @@ -664,7 +664,21 @@ namespace rsx void draw_command_processor::fill_fragment_state_buffer(void* buffer, const RSXFragmentProgram& /*fragment_program*/) const { +#pragma pack(push, 1) + struct fragment_context_t + { + f32 fog_param0; + f32 fog_param1; + u32 rop_control; + f32 alpha_ref; + u32 fog_mode; + f32 wpos_scale; + f32 wpos_bias[2]; + }; +#pragma pack(pop) + ROP_control_t rop_control{}; + alignas(16) fragment_context_t payload{}; if (REGS(m_ctx)->alpha_test_enabled()) { @@ -720,10 +734,6 @@ namespace rsx } } - const f32 fog0 = REGS(m_ctx)->fog_params_0(); - const f32 fog1 = REGS(m_ctx)->fog_params_1(); - const u32 fog_mode = static_cast(REGS(m_ctx)->fog_equation()); - // Check if framebuffer is actually an XRGB format and not a WZYX format switch (REGS(m_ctx)->surface_color()) { @@ -745,21 +755,37 @@ namespace rsx } // Generate wpos coefficients - // wpos equation is now as follows: + // 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) // wpos.x = (frag_coord / resolution_scale) // wpos.zw = frag_coord.zw + payload.fog_param0 = REGS(m_ctx)->fog_params_0(); + payload.fog_param1 = REGS(m_ctx)->fog_params_1(); + payload.fog_mode = static_cast(REGS(m_ctx)->fog_equation()); + payload.rop_control = rop_control.value; + payload.alpha_ref = REGS(m_ctx)->alpha_ref(); + + const auto window_origin = REGS(m_ctx)->shader_window_origin(); const u32 window_height = REGS(m_ctx)->shader_window_height(); + const auto pixel_center = REGS(m_ctx)->pixel_center(); const f32 resolution_scale = (window_height <= static_cast(g_cfg.video.min_scalable_dimension)) ? 1.f : rsx::get_resolution_scale(); - const f32 wpos_scale = (window_origin == rsx::window_origin::top) ? (1.f / resolution_scale) : (-1.f / resolution_scale); - const f32 wpos_bias = (window_origin == rsx::window_origin::top) ? 0.f : window_height; - const f32 alpha_ref = REGS(m_ctx)->alpha_ref(); - u32* dst = static_cast(buffer); - utils::stream_vector(dst, std::bit_cast(fog0), std::bit_cast(fog1), rop_control.value, std::bit_cast(alpha_ref)); - utils::stream_vector(dst + 4, 0u, fog_mode, std::bit_cast(wpos_scale), std::bit_cast(wpos_bias)); + payload.wpos_scale = (window_origin == rsx::window_origin::top) ? (1.f / resolution_scale) : (-1.f / resolution_scale); + payload.wpos_bias[0] = 0.f; + payload.wpos_bias[1] = (window_origin == rsx::window_origin::top) ? 0.f : window_height; + + if (pixel_center == window_pixel_center::integer) + { + // We could technically fix this shader side, but... + // 1. We have full control over gl_FragCoord consumption, so fix it using our own pipeline as it is an emulated input. + // 2. Vulkan does not support pixel_center_integer decoration. SPIR-V modules only permit pixel center at half offset. + payload.wpos_bias[0] -= 0.5f; + payload.wpos_bias[1] -= 0.5f; + } + + utils::stream_vector_from_memory<2>(buffer, &payload); } 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 diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index e59d27a2aa..4cbd92eecd 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -175,10 +175,9 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) " float fog_param1;\n" " uint rop_control;\n" " float alpha_ref;\n" - " uint reserved;\n" " uint fog_mode;\n" " float wpos_scale;\n" - " float wpos_bias;\n" + " vec2 wpos_bias;\n" "};\n\n" "layout(std140, binding = " << GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT << ") uniform TextureParametersBuffer\n" diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXDefines2.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXDefines2.glsl index 62ec4a06c0..490b57850b 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXDefines2.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXDefines2.glsl @@ -43,10 +43,9 @@ struct fragment_context_t float fog_param1; uint rop_control; float alpha_ref; - uint reserved; uint fog_mode; float wpos_scale; - float wpos_bias; + vec2 wpos_bias; }; )" diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl index de133b3a22..e40373f64c 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl @@ -38,7 +38,7 @@ bool _fragment_discard = false; vec4 get_wpos() { float abs_scale = abs(wpos_scale); - return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(0., wpos_bias, 0., 0.); + return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(wpos_bias, 0., 0.); } #endif diff --git a/rpcs3/Emu/RSX/rsx_decode.h b/rpcs3/Emu/RSX/rsx_decode.h index 10b58d59c4..bdb99f199f 100644 --- a/rpcs3/Emu/RSX/rsx_decode.h +++ b/rpcs3/Emu/RSX/rsx_decode.h @@ -3132,7 +3132,7 @@ struct registers_decoder return to_window_origin(window_shader_origin_raw()); } - auto window_shader_pixel_center() const + auto pixel_center() const { return to_window_pixel_center(window_shader_pixel_center_raw()); } @@ -3146,7 +3146,7 @@ struct registers_decoder static void dump(std::string& out, const decoded_type& decoded) { fmt::append(out, "Viewport: height: %u origin: %s pixel center: %s", decoded.window_shader_height() - , decoded.window_shader_origin(), decoded.window_shader_pixel_center()); + , decoded.window_shader_origin(), decoded.pixel_center()); } }; diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index 60be7ec14e..c9621c3282 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -226,9 +226,9 @@ namespace rsx return decode().window_shader_origin(); } - window_pixel_center shader_window_pixel() const + window_pixel_center pixel_center() const { - return decode().window_shader_pixel_center(); + return decode().pixel_center(); } u16 shader_window_height() const