diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index 6f60855f9f..70238a88b7 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -229,6 +229,9 @@ void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex) float alpha_ref = alpha_ref_raw / 255.f; memcpy((char*)mapped_buffer + 16 * sizeof(float), &is_alpha_tested, sizeof(int)); memcpy((char*)mapped_buffer + 17 * sizeof(float), &alpha_ref, sizeof(float)); + memcpy((char*)mapped_buffer + 18 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS], sizeof(float)); + memcpy((char*)mapped_buffer + 19 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS + 1], sizeof(float)); + m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 256)); D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index 5cf7c69190..e98655200c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -39,6 +39,8 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS) OS << " float4x4 scaleOffsetMat;" << std::endl; OS << " int isAlphaTested;" << std::endl; OS << " float alphaRef;" << std::endl; + OS << " float fog_param0;\n"; + OS << " float fog_param1;\n"; OS << "};" << std::endl; } @@ -141,6 +143,36 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) } } +namespace +{ + // Note: It's not clear whether fog is computed per pixel or per vertex. + // But it makes more sense to compute exp of interpoled value than to interpolate exp values. + void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode) + { + switch (mode) + { + case rsx::fog_mode::linear: + OS << " float4 fogc = fog_param1 * In.fogc + (fog_param0 - 1.);\n"; + return; + case rsx::fog_mode::exponential: + OS << " float4 fogc = exp(11.084 * (fog_param1 * In.fogc + fog_param0 - 1.5));\n"; + return; + case rsx::fog_mode::exponential2: + OS << " float4 fogc = exp(-pow(4.709 * (fog_param1 * In.fogc + fog_param0 - 1.5)), 2.);\n"; + return; + case rsx::fog_mode::linear_abs: + OS << " float4 fogc = fog_param1 * abs(In.fogc) + (fog_param0 - 1.);\n"; + return; + case rsx::fog_mode::exponential_abs: + OS << " float4 fogc = exp(11.084 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5));\n"; + return; + case rsx::fog_mode::exponential2_abs: + OS << " float4 fogc = exp(-pow(4.709 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5)), 2.);\n"; + return; + } + } +} + void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) { insert_d3d12_legacy_function(OS); @@ -169,6 +201,11 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) continue; } } + if (PI.name == "fogc") + { + insert_fog_declaration(OS, m_prog.fog_equation); + continue; + } if (PI.name == "ssa") continue; OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl; @@ -179,6 +216,7 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) if (m_prog.origin_mode == rsx::window_origin::bottom) OS << " gl_FragCoord.y = (" << std::to_string(m_prog.height) << " - gl_FragCoord.y);\n"; OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n"; + // Declare output for (const ParamType &PT : m_parr.params[PF_PARAM_NONE]) { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp index be2b94db36..2688e08930 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp @@ -33,6 +33,8 @@ void D3D12VertexProgramDecompiler::insertHeader(std::stringstream &OS) OS << " float4x4 scaleOffsetMat;" << std::endl; OS << " int isAlphaTested;" << std::endl; OS << " float alphaRef;" << std::endl; + OS << " float fog_param0;\n"; + OS << " float fog_param1;\n"; OS << "};" << std::endl; } diff --git a/rpcs3/Emu/RSX/GCM.cpp b/rpcs3/Emu/RSX/GCM.cpp index 27a8990281..57f8b4269b 100644 --- a/rpcs3/Emu/RSX/GCM.cpp +++ b/rpcs3/Emu/RSX/GCM.cpp @@ -806,6 +806,30 @@ rsx::comparaison_function rsx::to_comparaison_function(u16 in) throw EXCEPTION("Wrong comparaison function %x", in); } +enum +{ + CELL_GCM_FOG_MODE_LINEAR = 0x2601, + CELL_GCM_FOG_MODE_EXP = 0x0800, + CELL_GCM_FOG_MODE_EXP2 = 0x0801, + CELL_GCM_FOG_MODE_EXP_ABS = 0x0802, + CELL_GCM_FOG_MODE_EXP2_ABS = 0x0803, + CELL_GCM_FOG_MODE_LINEAR_ABS = 0x0804, +}; + +rsx::fog_mode rsx::to_fog_mode(u32 in) +{ + switch (in) + { + case CELL_GCM_FOG_MODE_LINEAR: return rsx::fog_mode::linear; + case CELL_GCM_FOG_MODE_EXP: return rsx::fog_mode::exponential; + case CELL_GCM_FOG_MODE_EXP2: return rsx::fog_mode::exponential2; + case CELL_GCM_FOG_MODE_EXP_ABS: return rsx::fog_mode::exponential_abs; + case CELL_GCM_FOG_MODE_EXP2_ABS: return rsx::fog_mode::exponential2_abs; + case CELL_GCM_FOG_MODE_LINEAR_ABS: return rsx::fog_mode::linear_abs; + } + throw EXCEPTION("Wrong fog mode %x", in); +} + enum { diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index 882972911c..f9d6aae57b 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -141,6 +141,18 @@ namespace rsx }; comparaison_function to_comparaison_function(u16 in); + + enum class fog_mode : u8 + { + linear, + exponential, + exponential2, + exponential_abs, + exponential2_abs, + linear_abs + }; + + fog_mode to_fog_mode(u32 in); } enum @@ -497,13 +509,6 @@ enum CELL_GCM_ATTRIB_OUTPUT_MASK_TEX6 = 1 << 20, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX7 = 1 << 21, - CELL_GCM_FOG_MODE_LINEAR = 0x2601, - CELL_GCM_FOG_MODE_EXP = 0x0800, - CELL_GCM_FOG_MODE_EXP2 = 0x0801, - CELL_GCM_FOG_MODE_EXP_ABS = 0x0802, - CELL_GCM_FOG_MODE_EXP2_ABS = 0x0803, - CELL_GCM_FOG_MODE_LINEAR_ABS = 0x0804, - CELL_GCM_POLYGON_MODE_POINT = 0x1B00, CELL_GCM_POLYGON_MODE_LINE = 0x1B01, CELL_GCM_POLYGON_MODE_FILL = 0x1B02, diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index f332ab2175..3764fafe6c 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -29,6 +29,13 @@ std::string GLFragmentDecompilerThread::compareFunction(COMPARE f, const std::st void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS) { OS << "#version 420" << std::endl; + + OS << "layout(std140, binding = 0) uniform ScaleOffsetBuffer\n"; + OS << "{\n"; + OS << " mat4 scaleOffsetMat;\n"; + OS << " float fog_param0;\n"; + OS << " float fog_param1;\n"; + OS << "};\n"; } void GLFragmentDecompilerThread::insertIntputs(std::stringstream & OS) @@ -99,6 +106,37 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << "};" << std::endl; } + +namespace +{ + // Note: It's not clear whether fog is computed per pixel or per vertex. + // But it makes more sense to compute exp of interpoled value than to interpolate exp values. + void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode) + { + switch (mode) + { + case rsx::fog_mode::linear: + OS << " vec4 fogc = fog_param1 * fogc + (fog_param0 - 1.);\n"; + return; + case rsx::fog_mode::exponential: + OS << " vec4 fogc = exp(11.084 * (fog_param1 * fogc + fog_param0 - 1.5));\n"; + return; + case rsx::fog_mode::exponential2: + OS << " vec4 fogc = exp(-pow(4.709 * (fog_param1 * fogc + fog_param0 - 1.5)), 2.);\n"; + return; + case rsx::fog_mode::linear_abs: + OS << " vec4 fogc = fog_param1 * abs(fogc) + (fog_param0 - 1.);\n"; + return; + case rsx::fog_mode::exponential_abs: + OS << " vec4 fogc = exp(11.084 * (fog_param1 * abs(fogc) + fog_param0 - 1.5));\n"; + return; + case rsx::fog_mode::exponential2_abs: + OS << " vec4 fogc = exp(-pow(4.709 * (fog_param1 * abs(fogc) + fog_param0 - 1.5)), 2.);\n"; + return; + } + } +} + void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { insert_glsl_legacy_function(OS); @@ -118,6 +156,19 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) } OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; + + // search if there is fogc in inputs + for (const ParamType& PT : m_parr.params[PF_PARAM_IN]) + { + for (const ParamItem& PI : PT.items) + { + if (PI.name == "fogc") + { + insert_fog_declaration(OS, m_prog.fog_equation); + return; + } + } + } } void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 55b0940adc..7ee1d9b10d 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -729,7 +729,7 @@ void GLGSRender::on_init_thread() m_vao.create(); m_vbo.create(); m_ebo.create(); - m_scale_offset_buffer.create(16 * sizeof(float)); + m_scale_offset_buffer.create(18 * sizeof(float)); m_vertex_constants_buffer.create(512 * 4 * sizeof(float)); m_fragment_constants_buffer.create(); @@ -945,6 +945,8 @@ bool GLGSRender::load_program() std::vector client_side_buf(max_buffer_sz); fill_scale_offset_data(client_side_buf.data(), false); + memcpy(client_side_buf.data() + 16 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS], sizeof(float)); + memcpy(client_side_buf.data() + 17 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS + 1], sizeof(float)); m_scale_offset_buffer.data(m_scale_offset_buffer.size(), nullptr); m_scale_offset_buffer.sub_data(0, m_scale_offset_buffer.size(), client_side_buf.data()); diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index b5e3b31f5f..d36fa5db58 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -31,6 +31,8 @@ void GLVertexDecompilerThread::insertHeader(std::stringstream &OS) OS << "layout(std140, binding = 0) uniform ScaleOffsetBuffer" << std::endl; OS << "{" << std::endl; OS << " mat4 scaleOffsetMat;" << std::endl; + OS << " float fog_param0;\n"; + OS << " float fog_param1;\n"; OS << "};" << std::endl; } diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 5fe8429533..c019f96269 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -227,6 +227,7 @@ struct RSXFragmentProgram u32 texture_dimensions; rsx::window_origin origin_mode; rsx::window_pixel_center pixel_center_mode; + rsx::fog_mode fog_equation; u16 height; texture_dimension get_texture_dimension(u8 id) const diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 2c48036c73..aa3a338490 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -690,6 +690,7 @@ namespace rsx result.back_color_diffuse_output = !!(rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK] & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE); result.back_color_specular_output = !!(rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK] & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR); result.alpha_func = to_comparaison_function(rsx::method_registers[NV4097_SET_ALPHA_FUNC]); + result.fog_equation = rsx::to_fog_mode(rsx::method_registers[NV4097_SET_FOG_MODE]); u32 shader_window = rsx::method_registers[NV4097_SET_SHADER_WINDOW]; result.origin_mode = rsx::to_window_origin((shader_window >> 12) & 0xF); result.pixel_center_mode = rsx::to_window_pixel_center((shader_window >> 16) & 0xF); @@ -767,7 +768,7 @@ namespace rsx method_registers[NV4097_SET_LINE_WIDTH] = 1 << 3; - method_registers[NV4097_SET_FOG_MODE] = CELL_GCM_FOG_MODE_EXP; + method_registers[NV4097_SET_FOG_MODE] = 0x0800; // rsx::fog_mode::exponential; method_registers[NV4097_SET_DEPTH_FUNC] = CELL_GCM_LESS; method_registers[NV4097_SET_DEPTH_MASK] = CELL_GCM_TRUE;