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