From e296f81a378eeb0d11d220759107c03238ebdaa5 Mon Sep 17 00:00:00 2001 From: DH Date: Sat, 25 Jun 2016 22:17:40 +0300 Subject: [PATCH] Shaders decompiler: support non 2D textures Do not validate programs with undefined textures uniforms Minor fix --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 13 ++- rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp | 184 +++++++++++++++++++++++++++++- rpcs3/Emu/RSX/RSXThread.cpp | 25 +++- rpcs3/Emu/RSX/rsx_cache.cpp | 2 +- rsx_program_decompiler | 2 +- 5 files changed, 214 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index d790e76a5f..ea5f25eb7d 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -311,7 +311,7 @@ void GLGSRender::end() for (int i = 0; i < rsx::limits::textures_count; ++i) { int location; - if (m_program->uniforms.has_location("texture" + std::to_string(i), &location)) + if (m_program->uniforms.has_location("ftexture" + std::to_string(i), &location)) { if (!textures[i].enabled()) { @@ -330,7 +330,7 @@ void GLGSRender::end() //texture_index++; - if (m_program->uniforms.has_location("texture" + std::to_string(i) + "_cm", &location)) + if (m_program->uniforms.has_location("ftexture" + std::to_string(i) + "_cm", &location)) { if (textures[i].format() & CELL_GCM_TEXTURE_UN) { @@ -657,6 +657,15 @@ static void fill_matrix_buffer(glsl_matrix_buffer *buffer) bool GLGSRender::load_program() { + if (0) + { + RSXVertexProgram vertex_program = get_current_vertex_program(); + RSXFragmentProgram fragment_program = get_current_fragment_program(); + + GLProgramBuffer prog_buffer; + __glcheck prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr); + } + rsx::program_info info = programs_cache.get(get_raw_program(), rsx::decompile_language::glsl); m_program = (gl::glsl::program*)info.program; m_program->use(); diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp index 8332195f6c..042b186080 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp @@ -3,6 +3,162 @@ #include "gl_helpers.h" #include "../GCM.h" +static void insert_texture_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) +{ + if (shader.textures.empty()) + { + return; + } + + dst += "vec4 texture_fetch(int index, vec4 coord)\n{\n"; + dst += "\tswitch (index)\n\t{\n"; + + for (auto &texture : shader.textures) + { + dst += "\tcase " + std::to_string(texture.id) + ": return "; + + switch (state.textures[texture.id]) + { + case rsx::texture_target::none: dst += "vec4(0.0)"; break; + case rsx::texture_target::_1: dst += "texture(" + texture.name + ", coord.x)"; break; + case rsx::texture_target::_2: dst += "texture(" + texture.name + ", coord.xy)"; break; + + case rsx::texture_target::cube: + case rsx::texture_target::_3: dst += "texture(" + texture.name + ", coord.xyz)"; break; + } + + dst += ";\n"; + } + + dst += "\t}\n"; + dst += "}\n"; +} + +static void insert_texture_bias_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) +{ + if (shader.textures.empty()) + { + return; + } + + dst += "vec4 texture_bias_fetch(int index, vec4 coord, float bias)\n{\n"; + dst += "\tswitch (index)\n\t{\n"; + + for (auto &texture : shader.textures) + { + dst += "\tcase " + std::to_string(texture.id) + ": return "; + + switch (state.textures[texture.id]) + { + case rsx::texture_target::none: dst += "vec4(0.0)"; break; + case rsx::texture_target::_1: dst += "texture(" + texture.name + ", coord.x, bias)"; break; + case rsx::texture_target::_2: dst += "texture(" + texture.name + ", coord.xy, bias)"; break; + + case rsx::texture_target::cube: + case rsx::texture_target::_3: dst += "texture(" + texture.name + ", coord.xyz, bias)"; break; + } + + dst += ";\n"; + } + + dst += "\t}\n"; + dst += "}\n"; +} + +static void insert_texture_grad_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) +{ + if (shader.textures.empty()) + { + return; + } + + dst += "vec4 texture_grad_fetch(int index, vec4 coord, vec4 dPdx, vec4 dPdy)\n{\n"; + dst += "\tswitch (index)\n\t{\n"; + + for (auto &texture : shader.textures) + { + dst += "\tcase " + std::to_string(texture.id) + ": return "; + + switch (state.textures[texture.id]) + { + case rsx::texture_target::none: dst += "vec4(0.0)"; break; + case rsx::texture_target::_1: dst += "textureGrad(" + texture.name + ", coord.x, dPdx.x, dPdy.x)"; break; + case rsx::texture_target::_2: dst += "textureGrad(" + texture.name + ", coord.xy, dPdx.xy, dPdy.xy)"; break; + + case rsx::texture_target::cube: + case rsx::texture_target::_3: dst += "textureGrad(" + texture.name + ", coord.xyz, dPdx.xyz, dPdy.xyz)"; break; + } + + dst += ";\n"; + } + + dst += "\t}\n"; + dst += "}\n"; +} + +static void insert_texture_lod_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) +{ + if (shader.textures.empty()) + { + return; + } + + dst += "vec4 texture_lod_fetch(int index, vec4 coord, float lod)\n{\n"; + dst += "\tswitch (index)\n\t{\n"; + + for (auto &texture : shader.textures) + { + dst += "\tcase " + std::to_string(texture.id) + ": return "; + + switch (state.textures[texture.id]) + { + case rsx::texture_target::none: dst += "vec4(0.0)"; break; + case rsx::texture_target::_1: dst += "textureLod(" + texture.name + ", coord.x, lod)"; break; + case rsx::texture_target::_2: dst += "textureLod(" + texture.name + ", coord.xy, lod)"; break; + + case rsx::texture_target::cube: + case rsx::texture_target::_3: dst += "textureLod(" + texture.name + ", coord.xyz, lod)"; break; + } + + dst += ";\n"; + } + + dst += "\t}\n"; + dst += "}\n"; +} + + +static void insert_texture_proj_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) +{ + if (shader.textures.empty()) + { + return; + } + + dst += "vec4 texture_proj_fetch(int index, vec4 coord, float bias)\n{\n"; + dst += "\tswitch (index)\n\t{\n"; + + for (auto &texture : shader.textures) + { + dst += "\tcase " + std::to_string(texture.id) + ": return "; + + switch (state.textures[texture.id]) + { + case rsx::texture_target::cube: + case rsx::texture_target::none: dst += "vec4(0.0)"; break; + case rsx::texture_target::_1: dst += "textureProj(" + texture.name + ", coord.xy, bias)"; break; + case rsx::texture_target::_2: dst += "textureProj(" + texture.name + ", coord.xyz, bias)"; break; + case rsx::texture_target::_3: dst += "textureProj(" + texture.name + ", coord, bias)"; break; + } + + dst += ";\n"; + } + + dst += "\t}\n"; + dst += "}\n"; +} + + rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, rsx::program_state state) { rsx::complete_shader result; @@ -75,7 +231,21 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, for (const rsx::texture_info& texture : shader.textures) { result.code += "uniform vec4 " + texture.name + "_cm = vec4(1.0);\n"; - result.code += "uniform sampler2D " + texture.name + ";\n"; + + rsx::texture_target target = state.textures[texture.id]; + + + result.code += "uniform sampler"; + + switch (target) + { + default: + case rsx::texture_target::_1: result.code += "1D"; break; + case rsx::texture_target::_2: result.code += "2D"; break; + case rsx::texture_target::_3: result.code += "3D"; break; + case rsx::texture_target::cube: result.code += "Cube"; break; + } + result.code += " " + texture.name + ";\n"; } std::string prepare; @@ -85,6 +255,13 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, switch (shader.raw->type) { case rsx::program_type::fragment: + insert_texture_fetch_function(result.code, shader, state); + insert_texture_bias_fetch_function(result.code, shader, state); + insert_texture_grad_fetch_function(result.code, shader, state); + insert_texture_lod_fetch_function(result.code, shader, state); + insert_texture_proj_fetch_function(result.code, shader, state); + + result.code += "\n"; result.code += "layout(location = 0) out vec4 ocol;\n"; if (state.ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) @@ -243,7 +420,6 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, break; case rsx::program_type::vertex: - result.code += "out vec4 wpos;\n"; // TODO @@ -266,9 +442,6 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, { if (shader.input_attributes & (1 << index)) { - // result.code += "in vec4 " + rsx::vertex_program::input_attrib_names[index] + ";\n"; - - // TODO: use actual information about vertex inputs const std::string &attrib_name = rsx::vertex_program::input_attrib_names[index]; result.code += "uniform "; @@ -446,7 +619,6 @@ void* glsl_make_program(const void *vertex_shader, const void *fragment_shader) result->attach(*(gl::glsl::shader*)fragment_shader); result->link(); - result->validate(); return result; } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index b68980724f..189e64402d 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -747,7 +747,7 @@ namespace rsx raw_program thread::get_raw_program() const { - raw_program result; + raw_program result{}; u32 fp_info = rsx::method_registers[NV4097_SET_SHADER_PROGRAM]; @@ -755,7 +755,7 @@ namespace rsx result.state.output_attributes = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK]; result.state.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL]; result.state.divider_op = rsx::method_registers[NV4097_SET_FREQUENCY_DIVIDER_OPERATION]; - + result.state.is_array = 0; result.state.is_int = 0; @@ -785,6 +785,27 @@ namespace rsx } } + for (u8 index = 0; index < rsx::limits::textures_count; ++index) + { + if (!textures[index].enabled()) + { + result.state.textures[index] = rsx::texture_target::none; + continue; + } + + switch (textures[index].get_extended_texture_dimension()) + { + case rsx::texture_dimension_extended::texture_dimension_1d: result.state.textures[index] = rsx::texture_target::_1; break; + case rsx::texture_dimension_extended::texture_dimension_2d: result.state.textures[index] = rsx::texture_target::_2; break; + case rsx::texture_dimension_extended::texture_dimension_3d: result.state.textures[index] = rsx::texture_target::_3; break; + case rsx::texture_dimension_extended::texture_dimension_cubemap: result.state.textures[index] = rsx::texture_target::cube; break; + + default: + result.state.textures[index] = rsx::texture_target::none; + break; + } + } + result.vertex_shader.ucode_ptr = transform_program; result.vertex_shader.offset = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; diff --git a/rpcs3/Emu/RSX/rsx_cache.cpp b/rpcs3/Emu/RSX/rsx_cache.cpp index 86108992ea..61a5434684 100644 --- a/rpcs3/Emu/RSX/rsx_cache.cpp +++ b/rpcs3/Emu/RSX/rsx_cache.cpp @@ -92,7 +92,7 @@ namespace rsx program_info result; result.vertex_shader = m_vertex_shaders_cache.get(context, raw_program_.vertex_shader, raw_program_.state); - result.fragment_shader = m_vertex_shaders_cache.get(context, raw_program_.fragment_shader, raw_program_.state); + result.fragment_shader = m_fragment_shader_cache.get(context, raw_program_.fragment_shader, raw_program_.state); result.program = context.make_program(result.vertex_shader.complete->user_data, result.fragment_shader.complete->user_data); m_program_cache.insert({ raw_program_, result }); diff --git a/rsx_program_decompiler b/rsx_program_decompiler index 9f8814af57..9f2d4c3c61 160000 --- a/rsx_program_decompiler +++ b/rsx_program_decompiler @@ -1 +1 @@ -Subproject commit 9f8814af57264c82b7e063c1df5d71dc32c7a951 +Subproject commit 9f2d4c3c61b38d24c166398bd4f9c6d2b2e6fcb9