From 083c4fc85522df22de99370ca22e012eba1e5c45 Mon Sep 17 00:00:00 2001 From: O1L Date: Thu, 16 Jun 2016 20:19:45 +0300 Subject: [PATCH] Try to use new shaders decompiler in OpenGL backend --- rpcs3/D3D12GSRender.vcxproj | 25 ++ rpcs3/Emu/RSX/GL/GLGSRender.cpp | 98 +++---- rpcs3/Emu/RSX/GL/GLGSRender.h | 2 - rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp | 417 +++++++++++++++++++++++++++++ rpcs3/Emu/RSX/GL/rsx_gl_cache.h | 11 + rpcs3/Emu/RSX/GL/vertex_buffer.cpp | 4 +- rpcs3/Emu/RSX/RSXThread.cpp | 24 +- rpcs3/Emu/RSX/RSXThread.h | 105 ++++---- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 2 +- rpcs3/Emu/RSX/rsx_cache.cpp | 114 ++++++++ rpcs3/Emu/RSX/rsx_cache.h | 61 +++++ rpcs3/GLGSRender.vcxproj | 27 ++ rpcs3/GLGSRender.vcxproj.filters | 2 + rpcs3/VKGSRender.vcxproj | 2 +- rpcs3/emucore.vcxproj | 17 ++ rpcs3/emucore.vcxproj.filters | 6 + rpcs3/rpcs3.vcxproj | 4 +- 17 files changed, 806 insertions(+), 115 deletions(-) create mode 100644 rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp create mode 100644 rpcs3/Emu/RSX/GL/rsx_gl_cache.h create mode 100644 rpcs3/Emu/RSX/rsx_cache.cpp create mode 100644 rpcs3/Emu/RSX/rsx_cache.h diff --git a/rpcs3/D3D12GSRender.vcxproj b/rpcs3/D3D12GSRender.vcxproj index d1c7dcd40f..8a4c9e9a90 100644 --- a/rpcs3/D3D12GSRender.vcxproj +++ b/rpcs3/D3D12GSRender.vcxproj @@ -61,6 +61,31 @@ + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index fb6a3cb943..a90a58c006 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -3,6 +3,8 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "GLGSRender.h" +#include "rsx_gl_cache.h" +#include "../rsx_utils.h" #include "../rsx_methods.h" #include "../Common/BufferUtils.h" @@ -26,7 +28,7 @@ namespace GLGSRender::GLGSRender() : GSRender(frame_type::OpenGL) { - shaders_cache.load(rsx::shader_language::glsl); + init_glsl_cache_program_context(programs_cache.context); } u32 GLGSRender::enable(u32 condition, u32 cap) @@ -277,24 +279,47 @@ void GLGSRender::end() m_program->use(); //setup textures - for (int i = 0; i < rsx::limits::textures_count; ++i) { - int location; - if (m_program->uniforms.has_location("tex" + std::to_string(i), &location)) + int texture_index = 0; + for (int i = 0; i < rsx::limits::textures_count; ++i) { if (!textures[i].enabled()) { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, 0); - glProgramUniform1i(m_program->id(), location, i); continue; } - m_gl_textures[i].set_target(get_gl_target_for_texture(textures[i])); + int location; + if (m_program->uniforms.has_location("texture" + std::to_string(i), &location)) + { + glProgramUniform1i(m_program->id(), location, texture_index); + m_gl_textures[i].init(texture_index, textures[i]); - __glcheck m_gl_texture_cache.upload_texture(i, textures[i], m_gl_textures[i], m_rtts); - glProgramUniform1i(m_program->id(), location, i); + texture_index++; + + if (m_program->uniforms.has_location("texture" + std::to_string(i) + "_cm", &location)) + { + if (textures[i].format() & CELL_GCM_TEXTURE_UN) + { + //glProgramUniform4f(m_program->id(), location, textures[i].width(), textures[i].height(), textures[i].depth(), 1.0f); + } + } + } } + /* + for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) + { + if (vertex_textures[i].enabled()) + { + int location; + if (m_program->uniforms.has_location("vtexture" + std::to_string(i), &location)) + { + glProgramUniform1i(m_program->id(), location, texture_index); + m_gl_vertex_textures[i].init(texture_index, vertex_textures[i]); + texture_index++; + } + } + } + */ } u32 offset_in_index_buffer = set_vertex_buffer(); @@ -512,52 +537,13 @@ bool GLGSRender::do_method(u32 cmd, u32 arg) bool GLGSRender::load_program() { -#if 1 - RSXVertexProgram vertex_program = get_current_vertex_program(); - RSXFragmentProgram fragment_program = get_current_fragment_program(); + rsx::program_info info = programs_cache.get(get_raw_program(), rsx::decompile_language::glsl); + m_program = (gl::glsl::program*)info.program; + m_program->use(); - __glcheck m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr); - __glcheck m_program->use(); - -#else - std::vector vertex_program; - u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; - vertex_program.reserve((512 - transform_program_start) * 4); - - for (int i = transform_program_start; i < 512; ++i) - { - vertex_program.resize((i - transform_program_start) * 4 + 4); - memcpy(vertex_program.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32)); - - D3 d3; - d3.HEX = transform_program[i * 4 + 3]; - - if (d3.end) - break; - } - - u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM]; - - std::string fp_shader; ParamArray fp_parr; u32 fp_size; - GLFragmentDecompilerThread decompile_fp(fp_shader, fp_parr, - rsx::get_address(shader_program & ~0x3, (shader_program & 0x3) - 1), fp_size, rsx::method_registers[NV4097_SET_SHADER_CONTROL]); - - std::string vp_shader; ParamArray vp_parr; - GLVertexDecompilerThread decompile_vp(vertex_program, vp_shader, vp_parr); - decompile_fp.Task(); - decompile_vp.Task(); - - LOG_NOTICE(RSX, "fp: %s", fp_shader.c_str()); - LOG_NOTICE(RSX, "vp: %s", vp_shader.c_str()); - - static bool first = true; - gl::glsl::shader fp(gl::glsl::shader::type::fragment, fp_shader); - gl::glsl::shader vp(gl::glsl::shader::type::vertex, vp_shader); - - (m_program.recreate() += { fp.compile(), vp.compile() }).make(); -#endif - u32 fragment_constants_sz = m_prog_buffer.get_fragment_constants_buffer_size(fragment_program); - fragment_constants_sz = std::max(32U, fragment_constants_sz); + // u32 fragment_constants_sz = m_prog_buffer.get_fragment_constants_buffer_size(fragment_program); + info.fragment_shader.decompiled->constants.size() * sizeof(f32) * 4; + u32 fragment_constants_sz = fragment_constants_sz = std::max(32U, fragment_constants_sz); u32 max_buffer_sz = 8192 + 512 + fragment_constants_sz; u32 is_alpha_tested = !!(rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE]); @@ -590,7 +576,7 @@ bool GLGSRender::load_program() buf = static_cast(mapping.first); fragment_constants_offset = mapping.second; - m_prog_buffer.fill_fragment_constans_buffer({ reinterpret_cast(buf), gsl::narrow(fragment_constants_sz) }, fragment_program); + //m_prog_buffer.fill_fragment_constans_buffer({ reinterpret_cast(buf), gsl::narrow(fragment_constants_sz) }, fragment_program); m_uniform_ring_buffer->unmap(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 1c64d0b3c6..13900e045a 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -14,8 +14,6 @@ class GLGSRender : public GSRender { private: - GLFragmentProgram m_fragment_prog; - GLVertexProgram m_vertex_prog; rsx::gl::texture m_gl_textures[rsx::limits::textures_count]; rsx::gl::texture m_gl_vertex_textures[rsx::limits::vertex_textures_count]; diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp new file mode 100644 index 0000000000..a93ccb8196 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp @@ -0,0 +1,417 @@ +#include "stdafx.h" +#include "rsx_gl_cache.h" +#include "gl_helpers.h" +#include "../GCM.h" + +rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, rsx::program_state state) +{ + rsx::complete_shader result; + result.decompiled = &shader; + result.code = "#version 420\n\n"; + + if (shader.raw->type == rsx::program_type::vertex) + { + result.code += "layout(std140, binding = 0) uniform MatrixBuffer\n{\n" + "\tmat4 viewport_matrix;\n" + "\tmat4 window_matrix;\n" + "\tmat4 normalize_matrix;\n" + "};\n"; + } + + if (!shader.constants.empty()) + { + if (shader.raw->type == rsx::program_type::vertex) + { + result.code += "layout(std140, binding = 1) uniform VertexConstantsBuffer\n"; + } + else + { + result.code += "layout(std140, binding = 2) uniform FragmentConstantsBuffer\n"; + } + + result.code += "{\n"; + + for (const rsx::constant_info& constant : shader.constants) + { + result.code += "\tvec4 " + constant.name + ";\n"; + } + + result.code += "};\n\n"; + } + + for (const rsx::register_info& temporary : shader.temporary_registers) + { + std::string value; + std::string type; + switch (temporary.type) + { + case rsx::register_type::half_float_point: + case rsx::register_type::single_float_point: + type = "vec4"; + if (temporary.name == "o0") + { + value = "vec4(vec3(0.0), 1.0)"; + } + else + { + value = "vec4(0.0)"; + } + break; + + case rsx::register_type::integer: + type = "ivec4"; + value = "ivec4(0)"; + break; + + default: + throw; + } + + result.code += type + " " + temporary.name + " = " + value + ";\n"; + } + + result.code += "\n"; + + 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"; + } + + std::string prepare; + std::string finalize; + + switch (shader.raw->type) + { + case rsx::program_type::fragment: + result.code += "layout(location = 0) out vec4 ocol;\n"; + + if (state.ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) + { + if (0) + { + finalize += "\tocol = vec4(1.0, 0.0, 1.0, 1.0);\n"; + } + else + { + finalize += "\tocol = r0;\n"; + } + + if (shader.temporary_registers.find({ "r2" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 1) out vec4 ocol1;\n"; + finalize += "\tocol1 = r2;\n"; + } + if (shader.temporary_registers.find({ "r3" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 2) out vec4 ocol2;\n"; + finalize += "\tocol2 = r3;\n"; + } + if (shader.temporary_registers.find({ "r4" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 3) out vec4 ocol3;\n"; + finalize += "\tocol3 = r4;\n"; + } + } + else + { + finalize += "\tocol = h0;\n"; + + if (shader.temporary_registers.find({ "h4" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 1) out vec4 ocol1;\n"; + finalize += "\tocol1 = h4;\n"; + } + if (shader.temporary_registers.find({ "h6" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 2) out vec4 ocol2;\n"; + finalize += "\tocol2 = h6;\n"; + } + if (shader.temporary_registers.find({ "h8" }) != shader.temporary_registers.end()) + { + result.code += "layout(location = 3) out vec4 ocol3;\n"; + finalize += "\tocol3 = h8;\n"; + } + } + + if (state.ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) + { + if (state.ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) + { + if (shader.temporary_registers.find({ "r1" }) != shader.temporary_registers.end()) + { + finalize += "\tgl_FragDepth = r1.z;\n"; + } + } + else + { + if (shader.temporary_registers.find({ "h2" }) != shader.temporary_registers.end()) + { + finalize += "\tgl_FragDepth = h2.z;\n"; + } + } + } + + { + u32 diffuse_color = state.output_attributes & (CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE); + u32 specular_color = state.output_attributes & (CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR); + + if (diffuse_color) + { + result.code += "vec4 col0;\n"; + } + + if (specular_color) + { + result.code += "vec4 col1;\n"; + } + + if (diffuse_color == (CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE) && + specular_color == (CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR)) + { + prepare += "\tif (gl_FrontFacing)\n\t{"; + prepare += "\t\tcol0 = front_diffuse_color;\n"; + prepare += "\t\tcol1 = front_specular_color;\n"; + prepare += "\t}\nelse\n\t{\n"; + prepare += "\t\tcol0 = back_diffuse_color;\n"; + prepare += "\t\tcol1 = back_specular_color;\n"; + prepare += "\t}"; + } + else + { + switch (diffuse_color) + { + case CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE: + prepare += "\tcol0 = gl_FrontFacing ? front_diffuse_color : back_diffuse_color;\n"; + break; + + case CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE: + prepare += "\tcol0 = front_diffuse_color;\n"; + break; + + case CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE: + prepare += "\tcol0 = back_diffuse_color;\n"; + break; + + default: + if (shader.input_attributes & (1 << 1)) + { + result.code += "vec4 col0 = vec4(0.0);\n"; + } + break; + } + + switch (specular_color) + { + case CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR: + prepare += "\tcol1 = gl_FrontFacing ? front_specular_color : back_specular_color;\n"; + break; + + case CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR: + prepare += "\tcol1 = front_specular_color;\n"; + break; + + case CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR: + prepare += "\tcol1 = back_specular_color;\n"; + break; + + default: + if (shader.input_attributes & (1 << 2)) + { + result.code += "vec4 col1 = vec4(0.0);\n"; + + if (diffuse_color) + { + prepare += "\tcol1 = col0;\n"; + } + } + break; + } + } + } + + result.code += "in vec4 " + rsx::fragment_program::input_attrib_names[0] + ";\n"; + + for (std::size_t index = 0; index < 22; ++index) + { + if (state.output_attributes & (1 << index)) + { + result.code += "in vec4 " + rsx::vertex_program::output_attrib_names[index] + ";\n"; + } + } + break; + + case rsx::program_type::vertex: + + result.code += "out vec4 wpos;\n"; + + if (1) + { + finalize += "\tgl_Position = o0;\n"; + } + else + { + finalize += + " wpos = window_matrix * viewport_matrix * vec4(o0.xyz, 1.0);\n" + " gl_Position = normalize_matrix * vec4(wpos.xyz, 1.0);\n" + " gl_Position.w = wpos.w = o0.w;\n"; + } + + for (std::size_t index = 0; index < 16; ++index) + { + if (shader.input_attributes & (1 << index)) + { + result.code += "in vec4 " + rsx::vertex_program::input_attrib_names[index] + ";\n"; + } + } + + { + auto map_register = [&](int to, int from) + { + if (shader.output_attributes & (1 << from)) + { + result.code += "out vec4 " + rsx::vertex_program::output_attrib_names[to] + ";\n"; + finalize += "\t" + rsx::vertex_program::output_attrib_names[to] + " = o" + std::to_string(from) + ";\n"; + } + else if (state.output_attributes & (1 << to)) + { + result.code += "out vec4 " + rsx::vertex_program::output_attrib_names[to] + ";\n"; + + if ((1 << to) == CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE && shader.output_attributes & (1 << 1)) + { + finalize += "\t" + rsx::vertex_program::output_attrib_names[to] + " = o1;\n"; + } + else if ((1 << to) == CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR && shader.output_attributes & (1 << 2)) + { + finalize += "\t" + rsx::vertex_program::output_attrib_names[to] + " = o2;\n"; + } + else + { + finalize += "\t" + rsx::vertex_program::output_attrib_names[to] + " = vec4(0.0);\n"; + } + } + }; + + map_register(0, 1); + map_register(1, 2); + map_register(2, 3); + map_register(3, 4); + map_register(14, 7); + map_register(15, 8); + map_register(16, 9); + map_register(17, 10); + map_register(18, 11); + map_register(19, 12); + map_register(20, 13); + map_register(21, 14); + map_register(12, 15); + + if (shader.output_attributes & (1 << 5)) + { + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC0) + { + result.code += "uniform int uc_m0 = 0;\n"; + finalize += "\tgl_ClipDistance[0] = uc_m0 * o5.y;\n"; + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC1) + { + result.code += "uniform int uc_m1 = 0;\n"; + finalize += "\tgl_ClipDistance[1] = uc_m1 * o5.z;\n"; + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC2) + { + result.code += "uniform int uc_m2 = 0;\n"; + finalize += "\tgl_ClipDistance[2] = uc_m2 * o5.w;\n"; + } + } + + if (shader.output_attributes & (1 << 6)) + { + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_POINTSIZE) + { + finalize += "\tgl_PointSize = o6.x;\n"; + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC3) + { + result.code += "uniform int uc_m3 = 0;\n"; + finalize += "\tgl_ClipDistance[3] = uc_m3 * o6.y;\n"; + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC4) + { + result.code += "uniform int uc_m4 = 0;\n"; + finalize += "\tgl_ClipDistance[4] = uc_m4 * o6.z;\n"; + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_UC4) + { + result.code += "uniform int uc_m5 = 0;\n"; + finalize += "\tgl_ClipDistance[5] = uc_m5 * o6.w;\n"; + } + } + + if (state.output_attributes & CELL_GCM_ATTRIB_OUTPUT_MASK_FOG) + { + //TODO + } + } + break; + + default: + throw; + } + + result.code += "\n"; + result.code += shader.code; + + result.code += "void main()\n{\n" + prepare + "\t" + shader.entry_function + "();\n" + finalize + "}"; + return result; +} + +void* glsl_compile_shader(rsx::program_type type, const std::string &code) +{ + gl::glsl::shader *result = new gl::glsl::shader(); + + result->create(type == rsx::program_type::vertex ? ::gl::glsl::shader::type::vertex : ::gl::glsl::shader::type::fragment); + result->source(code); + result->compile(); + + return result; +} + +void* glsl_make_program(const void *vertex_shader, const void *fragment_shader) +{ + gl::glsl::program *result = new gl::glsl::program(); + + result->create(); + result->attach(*(gl::glsl::shader*)vertex_shader); + result->attach(*(gl::glsl::shader*)fragment_shader); + + result->link(); + result->validate(); + + return result; +} + +void glsl_remove_program(void *buf) +{ + delete (gl::glsl::program*)buf; +} + +void glsl_remove_shader(void *buf) +{ + delete (gl::glsl::shader*)buf; +} + +void init_glsl_cache_program_context(rsx::program_cache_context &ctxt) +{ + ctxt.compile_shader = glsl_compile_shader; + ctxt.complete_shader = glsl_complete_shader; + ctxt.make_program = glsl_make_program; + ctxt.remove_program = glsl_remove_program; + ctxt.remove_shader = glsl_remove_shader; + ctxt.lang = rsx::decompile_language::glsl; +} diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.h b/rpcs3/Emu/RSX/GL/rsx_gl_cache.h new file mode 100644 index 0000000000..8b959ae675 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.h @@ -0,0 +1,11 @@ +#pragma once +#include "../rsx_cache.h" + +struct alignas(4) glsl_shader_matrix_buffer +{ + float viewport_matrix[4 * 4]; + float window_matrix[4 * 4]; + float normalize_matrix[4 * 4]; +}; + +void init_glsl_cache_program_context(rsx::program_cache_context &ctxt); diff --git a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp index 41e6f83b44..3203ed6ffb 100644 --- a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp +++ b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp @@ -235,7 +235,7 @@ u32 GLGSRender::set_vertex_buffer() auto &vertex_info = vertex_arrays_info[index]; int location; - if (!m_program->uniforms.has_location(reg_table[index] + "_buffer", &location)) + if (!m_program->attribs.has_location(rsx::vertex_program::input_attrib_names[index], &location)) continue; if (!vertex_info.size) // disabled, bind a null sampler @@ -303,7 +303,7 @@ u32 GLGSRender::set_vertex_buffer() for (int index = 0; index < rsx::limits::vertex_count; ++index) { int location; - if (!m_program->uniforms.has_location(reg_table[index] + "_buffer", &location)) + if (!m_program->attribs.has_location(rsx::vertex_program::input_attrib_names[index], &location)) continue; bool enabled = !!(input_mask & (1 << index)); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 886179031e..8a7ebf6677 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -35,12 +35,12 @@ namespace rsx { std::function g_access_violation_handler; - std::string shaders_cache::path_to_root() + std::string old_shaders_cache::shaders_cache::path_to_root() { return fs::get_executable_dir() + "data/"; } - void shaders_cache::load(const std::string &path, shader_language lang) + void old_shaders_cache::shaders_cache::load(const std::string &path, shader_language lang) { const std::string lang_name(::unveil::get(lang)); @@ -82,7 +82,7 @@ namespace rsx } } - void shaders_cache::load(shader_language lang) + void old_shaders_cache::shaders_cache::load(shader_language lang) { std::string root = path_to_root(); @@ -745,6 +745,24 @@ namespace rsx return result; } + raw_program thread::get_raw_program() const + { + raw_program result; + + u32 fp_info = rsx::method_registers[NV4097_SET_SHADER_PROGRAM]; + + result.state.output_attributes = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK]; + result.state.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL]; + + result.vertex_shader.ucode_ptr = transform_program; + result.vertex_shader.offset = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; + + result.fragment_shader.ucode_ptr = vm::base(rsx::get_address(fp_info & ~0x3, (fp_info & 0x3) - 1)); + result.fragment_shader.offset = 0; + + return result; + } + void thread::reset() { //setup method registers diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 9b2afa5bb9..2ad12d998d 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -5,6 +5,7 @@ #include #include #include "GCM.h" +#include "rsx_cache.h" #include "RSXTexture.h" #include "RSXVertexProgram.h" #include "RSXFragmentProgram.h" @@ -45,22 +46,25 @@ extern frame_capture_data frame_debug; namespace rsx { - enum class shader_language + namespace old_shaders_cache { - glsl, - hlsl, - }; + enum class shader_language + { + glsl, + hlsl, + }; + } } template<> -struct unveil +struct unveil { - static inline const char* get(rsx::shader_language in) + static inline const char* get(rsx::old_shaders_cache::shader_language in) { switch (in) { - case rsx::shader_language::glsl: return "glsl"; - case rsx::shader_language::hlsl: return "hlsl"; + case rsx::old_shaders_cache::shader_language::glsl: return "glsl"; + case rsx::old_shaders_cache::shader_language::hlsl: return "hlsl"; } return ""; @@ -83,52 +87,55 @@ namespace rsx }; } - struct decompiled_shader + namespace old_shaders_cache { - std::string code; - }; - - struct finalized_shader - { - u64 ucode_hash; - std::string code; - }; - - template> - struct cache - { - private: - std::unordered_map m_entries; - - public: - const Type* find(u64 key) const + struct decompiled_shader { - auto found = m_entries.find(key); + std::string code; + }; - if (found == m_entries.end()) - return nullptr; - - return &found->second; - } - - void insert(KeyType key, const Type &shader) + struct finalized_shader { - m_entries.insert({ key, shader }); - } - }; + u64 ucode_hash; + std::string code; + }; - struct shaders_cache - { - cache decompiled_fragment_shaders; - cache decompiled_vertex_shaders; - cache finailized_fragment_shaders; - cache finailized_vertex_shaders; + template> + struct cache + { + private: + std::unordered_map m_entries; - void load(const std::string &path, shader_language lang); - void load(shader_language lang); + public: + const Type* find(u64 key) const + { + auto found = m_entries.find(key); - static std::string path_to_root(); - }; + if (found == m_entries.end()) + return nullptr; + + return &found->second; + } + + void insert(KeyType key, const Type &shader) + { + m_entries.insert({ key, shader }); + } + }; + + struct shaders_cache + { + cache decompiled_fragment_shaders; + cache decompiled_vertex_shaders; + cache finailized_fragment_shaders; + cache finailized_vertex_shaders; + + void load(const std::string &path, shader_language lang); + void load(shader_language lang); + + static std::string path_to_root(); + }; + } u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size); @@ -201,7 +208,8 @@ namespace rsx std::stack m_call_stack; public: - struct shaders_cache shaders_cache; + old_shaders_cache::shaders_cache shaders_cache; + rsx::programs_cache programs_cache; CellGcmControl* ctrl = nullptr; @@ -376,6 +384,7 @@ namespace rsx virtual std::pair get_programs() const { return std::make_pair("", ""); }; + struct raw_program get_raw_program() const; public: void reset(); void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 699542e17f..a18ffa2909 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -418,7 +418,7 @@ namespace VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) { - shaders_cache.load(rsx::shader_language::glsl); + shaders_cache.load(rsx::old_shaders_cache::shader_language::glsl); m_thread_context.createInstance("RPCS3"); m_thread_context.makeCurrentInstance(1); diff --git a/rpcs3/Emu/RSX/rsx_cache.cpp b/rpcs3/Emu/RSX/rsx_cache.cpp new file mode 100644 index 0000000000..535055114f --- /dev/null +++ b/rpcs3/Emu/RSX/rsx_cache.cpp @@ -0,0 +1,114 @@ +#include "stdafx.h" +#include "rsx_cache.h" +#include "Emu/System.h" + +namespace rsx +{ + shader_info shaders_cache::get(const program_cache_context &ctxt, raw_shader &raw_shader, const program_state& state) + { + auto found_entry = m_entries.find(raw_shader); + + shader_info info; + entry_t *entry; + + static const std::string &path = fs::get_executable_dir() + "data/cache/"; + + if (found_entry != m_entries.end()) + { + entry = &found_entry->second; + } + else + { + //analyze_raw_shader(raw_shader); + + fs::file{ path + fmt::format("%016llx.", raw_shader.hash()) + (raw_shader.type == rsx::program_type::fragment ? "fp" : "vp") + ".ucode", fs::rewrite } + .write(raw_shader.ucode.data(), raw_shader.ucode.size()); + + rsx::decompiled_shader decompiled_shader = decompile(raw_shader, ctxt.lang); + auto &inserted = m_entries.insert({ raw_shader, entry_t{ decompiled_shader } }).first; + inserted->second.decompiled.raw = &inserted->first; + entry = &inserted->second; + } + + info.decompiled = &entry->decompiled; + + auto found_complete = entry->complete.find(state); + + if (found_complete != entry->complete.end()) + { + info.complete = &found_complete->second; + } + else + { + rsx::complete_shader complete_shader = ctxt.complete_shader(entry->decompiled, state); + complete_shader.decompiled = info.decompiled; + info.complete = &entry->complete.insert({ state, complete_shader }).first->second; + info.complete->user_data = nullptr; + + fs::file{ path + fmt::format("%016llx.", raw_shader.hash()) + (raw_shader.type == rsx::program_type::fragment ? "fp" : "vp") + "." + (ctxt.lang == rsx::decompile_language::glsl ? "glsl" : "hlsl"), fs::rewrite }.write(info.complete->code); + } + + if (info.complete->user_data == nullptr) + { + info.complete->user_data = ctxt.compile_shader(raw_shader.type, info.complete->code); + } + + return info; + } + + void shaders_cache::clear(const program_cache_context& context) + { + for (auto &entry : m_entries) + { + for (auto &shader : entry.second.complete) + { + context.remove_shader(shader.second.user_data); + } + } + + m_entries.clear(); + } + + programs_cache::~programs_cache() + { + clear(); + } + + program_info programs_cache::get(raw_program &raw_program, decompile_language lang) + { + raw_program.vertex_shader.type = program_type::vertex; + raw_program.fragment_shader.type = program_type::fragment; + + analyze_raw_shader(raw_program.vertex_shader); + analyze_raw_shader(raw_program.fragment_shader); + + auto found = m_program_cache.find(raw_program); + + if (found != m_program_cache.end()) + { + return found->second; + } + + 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.program = context.make_program(result.vertex_shader.complete->user_data, result.fragment_shader.complete->user_data); + m_program_cache.insert({ raw_program, result }); + + return result; + } + + void programs_cache::clear() + { + for (auto &entry : m_program_cache) + { + context.remove_program(entry.second.program); + } + + m_program_cache.clear(); + + m_vertex_shaders_cache.clear(context); + m_fragment_shader_cache.clear(context); + } +} diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h new file mode 100644 index 0000000000..e69ba9d2ba --- /dev/null +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -0,0 +1,61 @@ +#pragma once +#include + +namespace rsx +{ + struct shader_info + { + decompiled_shader *decompiled; + complete_shader *complete; + }; + + struct program_info + { + shader_info vertex_shader; + shader_info fragment_shader; + + void *program; + }; + + struct program_cache_context + { + decompile_language lang; + + void*(*compile_shader)(program_type type, const std::string &code); + complete_shader(*complete_shader)(const decompiled_shader &shader, program_state state); + void*(*make_program)(const void *vertex_shader, const void *fragment_shader); + void(*remove_program)(void *ptr); + void(*remove_shader)(void *ptr); + }; + + struct shaders_cache + { + struct entry_t + { + decompiled_shader decompiled; + std::unordered_map complete; + }; + + std::unordered_map m_entries; + + public: + shader_info get(const program_cache_context &ctxt, raw_shader &raw_shader, const program_state& state); + void clear(const program_cache_context& context); + }; + + class programs_cache + { + std::unordered_map m_program_cache; + + shaders_cache m_vertex_shaders_cache; + shaders_cache m_fragment_shader_cache; + + public: + program_cache_context context; + + ~programs_cache(); + + program_info get(raw_program &raw_program, decompile_language lang); + void clear(); + }; +} diff --git a/rpcs3/GLGSRender.vcxproj b/rpcs3/GLGSRender.vcxproj index cd1d79c870..9d39419944 100644 --- a/rpcs3/GLGSRender.vcxproj +++ b/rpcs3/GLGSRender.vcxproj @@ -61,6 +61,31 @@ + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + + + + ..\rsx_program_decompiler\rsx_decompiler;%(AdditionalIncludeDirectories) + + {c4a10229-4712-4bd2-b63e-50d93c67a038} @@ -77,6 +102,7 @@ + @@ -87,6 +113,7 @@ + diff --git a/rpcs3/GLGSRender.vcxproj.filters b/rpcs3/GLGSRender.vcxproj.filters index 907cf08e7f..f5119e089b 100644 --- a/rpcs3/GLGSRender.vcxproj.filters +++ b/rpcs3/GLGSRender.vcxproj.filters @@ -10,6 +10,7 @@ + @@ -23,5 +24,6 @@ + \ No newline at end of file diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index 023a74e01b..c4334faa08 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -94,7 +94,7 @@ - ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) + ..\rsx_program_decompiler\rsx_decompiler;..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index e676f88c2b..0e10df8f90 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -277,6 +277,7 @@ + @@ -613,6 +614,7 @@ + @@ -669,6 +671,21 @@ + + ..\rsx_program_decompiler\rsx_decompiler;$(IncludePath) + + + ..\rsx_program_decompiler\rsx_decompiler;$(IncludePath) + + + ..\rsx_program_decompiler\rsx_decompiler;$(IncludePath) + + + ..\rsx_program_decompiler\rsx_decompiler;$(IncludePath) + + + ..\rsx_program_decompiler\rsx_decompiler;$(IncludePath) + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 6cb640edc1..bdc7dfe983 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -860,6 +860,9 @@ Emu\PSP2\Modules + + Emu\GPU\RSX + Utilities @@ -1648,6 +1651,9 @@ Utilities + + Emu\GPU\RSX + Utilities diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 82b7632775..94e84c7b2a 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -90,7 +90,7 @@ - ..\wxWidgets\include\msvc;..\wxWidgets\include;..\3rdparty\XAudio2_7;..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) + ..\rsx_program_decompiler\rsx_decompiler;..\wxWidgets\include\msvc;..\wxWidgets\include;..\3rdparty\XAudio2_7;..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) ..\Vulkan\glslang-build\SPIRV\Debug;..\Vulkan\glslang-build\OGLCompilersDLL\Debug;..\Vulkan\glslang-build\glslang\OSDependent\Windows\Debug;..\Vulkan\Vulkan-build\loader\Debug;..\Vulkan\glslang-build\glslang\Debug;..\3rdparty\OpenAL\libs\Win64;%(AdditionalLibraryDirectories) @@ -104,7 +104,7 @@ wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;%(AdditionalDependencies) wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;%(AdditionalDependencies) wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;%(AdditionalDependencies) - VKstatic.1.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;%(AdditionalDependencies) + VKstatic.1.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;rsx_decompiler.lib;shader_code.lib;%(AdditionalDependencies) Windows true 0x10000