From 083c4fc85522df22de99370ca22e012eba1e5c45 Mon Sep 17 00:00:00 2001 From: O1L Date: Thu, 16 Jun 2016 20:19:45 +0300 Subject: [PATCH 01/11] 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 From 8637754d6a90f8b3bc628ef2c36234d7c304793e Mon Sep 17 00:00:00 2001 From: O1L Date: Thu, 16 Jun 2016 20:50:33 +0300 Subject: [PATCH 02/11] Missed changes --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 6 +++--- rpcs3/Emu/RSX/GL/GLGSRender.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index a90a58c006..83dde91c8a 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -427,7 +427,7 @@ void GLGSRender::on_exit() { glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - m_prog_buffer.clear(); + programs_cache.clear(); if (draw_fbo) draw_fbo.remove(); @@ -542,8 +542,8 @@ bool GLGSRender::load_program() m_program->use(); // 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 fragment_constants_sz = info.fragment_shader.decompiled->constants.size() * sizeof(f32) * 4; + 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]); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 13900e045a..00151259ab 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -41,7 +41,6 @@ public: gl::fbo draw_fbo; private: - GLProgramBuffer m_prog_buffer; //buffer gl::fbo m_flip_fbo; From 1778113b717ab2b5883773cfb34fd7254b4a9b27 Mon Sep 17 00:00:00 2001 From: O1L Date: Sat, 18 Jun 2016 00:36:20 +0300 Subject: [PATCH 03/11] Use sampler buffers in vertex shaders --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 2 +- rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp | 14 +++++++++++--- rpcs3/Emu/RSX/GL/vertex_buffer.cpp | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 83dde91c8a..e794f43a21 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -582,7 +582,7 @@ bool GLGSRender::load_program() glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_ring_buffer->get_buffer().id(), scale_offset_offset, 512); glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_ring_buffer->get_buffer().id(), vertex_constants_offset, 512 * 16); - glBindBufferRange(GL_UNIFORM_BUFFER, 2, m_uniform_ring_buffer->get_buffer().id(), fragment_constants_offset, fragment_constants_sz); + //glBindBufferRange(GL_UNIFORM_BUFFER, 2, m_uniform_ring_buffer->get_buffer().id(), fragment_constants_offset, fragment_constants_sz); return true; } diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp index a93ccb8196..db290e3580 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp @@ -7,7 +7,7 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, { rsx::complete_shader result; result.decompiled = &shader; - result.code = "#version 420\n\n"; + result.code = "#version 430\n\n"; if (shader.raw->type == rsx::program_type::vertex) { @@ -80,6 +80,7 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, std::string prepare; std::string finalize; + int location = 1; switch (shader.raw->type) { @@ -244,10 +245,12 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, case rsx::program_type::vertex: result.code += "out vec4 wpos;\n"; - + + // TODO if (1) { finalize += "\tgl_Position = o0;\n"; + finalize += "\tgl_Position = gl_Position * viewport_matrix;\n"; } else { @@ -261,7 +264,12 @@ 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"; + // result.code += "in vec4 " + rsx::vertex_program::input_attrib_names[index] + ";\n"; + + // TODO: use actual information about vertex inputs + result.code += "layout(location=" + std::to_string(location++) + ") uniform samplerBuffer " + rsx::vertex_program::input_attrib_names[index] + "_buffer" + ";\n"; + result.code += "vec4 " + rsx::vertex_program::input_attrib_names[index] + + " = texelFetch(" + rsx::vertex_program::input_attrib_names[index] + "_buffer, gl_VertexID).rgba;\n"; } } diff --git a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp index 3203ed6ffb..602b158c86 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->attribs.has_location(rsx::vertex_program::input_attrib_names[index], &location)) + if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &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->attribs.has_location(rsx::vertex_program::input_attrib_names[index], &location)) + if (!m_program->uniforms.has_location(rsx::vertex_program::input_attrib_names[index] + "_buffer", &location)) continue; bool enabled = !!(input_mask & (1 << index)); From 67fe5e110729e53f5a7c2793ea9fe0e38020eb13 Mon Sep 17 00:00:00 2001 From: O1L Date: Sat, 18 Jun 2016 11:50:45 +0300 Subject: [PATCH 04/11] Fill fragment constants --- bin/data/.gitignore | 4 ++++ bin/data/cache/.gitignore | 4 ++++ rpcs3/Emu/RSX/GL/GLGSRender.cpp | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 bin/data/.gitignore create mode 100644 bin/data/cache/.gitignore diff --git a/bin/data/.gitignore b/bin/data/.gitignore new file mode 100644 index 0000000000..5e7d2734cf --- /dev/null +++ b/bin/data/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/bin/data/cache/.gitignore b/bin/data/cache/.gitignore new file mode 100644 index 0000000000..5e7d2734cf --- /dev/null +++ b/bin/data/cache/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index e794f43a21..ea543967d9 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -576,13 +576,41 @@ 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); + // fill fragment constants + if (!info.fragment_shader.decompiled->constants.empty()) + { + u32 buffer_offset = 0; + + static const __m128i mask = _mm_set_epi8( + 0xE, 0xF, 0xC, 0xD, + 0xA, 0xB, 0x8, 0x9, + 0x6, 0x7, 0x4, 0x5, + 0x2, 0x3, 0x0, 0x1); + + auto ucode = (const rsx::fragment_program::ucode_instr*)info.fragment_shader.decompiled->raw->ucode_ptr; + + for (const auto& constant : info.fragment_shader.decompiled->constants) + { + const void *data = ucode + (u32)(constant.id / (sizeof(f32) * 4)); + const __m128i &vector = _mm_loadu_si128((const __m128i*)data); + const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask); + _mm_stream_si128((__m128i*)((char*)buf + buffer_offset), shuffled_vector); + + //float x = ((float*)((char*)buf + buffer_offset))[0]; + //float y = ((float*)((char*)buf + buffer_offset))[1]; + //float z = ((float*)((char*)buf + buffer_offset))[2]; + //float w = ((float*)((char*)buf + buffer_offset))[3]; + + //LOG_WARNING(RSX, "fc%u = {%g, %g, %g, %g}", constant.id, x, y, z, w); + buffer_offset += 4 * sizeof(f32); + } + } m_uniform_ring_buffer->unmap(); glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_ring_buffer->get_buffer().id(), scale_offset_offset, 512); glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_ring_buffer->get_buffer().id(), vertex_constants_offset, 512 * 16); - //glBindBufferRange(GL_UNIFORM_BUFFER, 2, m_uniform_ring_buffer->get_buffer().id(), fragment_constants_offset, fragment_constants_sz); + glBindBufferRange(GL_UNIFORM_BUFFER, 2, m_uniform_ring_buffer->get_buffer().id(), fragment_constants_offset, fragment_constants_sz); return true; } From 62a9c38754f61b08f4cf9ddbd4f86ae22fa6c911 Mon Sep 17 00:00:00 2001 From: O1L Date: Sat, 18 Jun 2016 18:18:56 +0300 Subject: [PATCH 05/11] Try to fix appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 9661ab661a..f687156104 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ test: off before_build: # until git for win 2.5 release with commit checkout - - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp + - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp rsx_program_decompiler - 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null - 7z x zlib.7z -aos -oC:\rpcs3\ > null - if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/) From c299a65aabd2d4b7f8a1f8397c6914177f3fa362 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Sat, 18 Jun 2016 19:48:39 +0300 Subject: [PATCH 06/11] Updated rsx_program_decompiler --- rsx_program_decompiler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsx_program_decompiler b/rsx_program_decompiler index b4d0986764..0d3807d2ab 160000 --- a/rsx_program_decompiler +++ b/rsx_program_decompiler @@ -1 +1 @@ -Subproject commit b4d09867643df26e503ec09119c8048832676780 +Subproject commit 0d3807d2ab18b13617dd01981355a64144ecdc29 From c0487a634e38871b2d5c86d6e56359bca84ecae3 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Sat, 18 Jun 2016 21:41:17 +0300 Subject: [PATCH 07/11] Added rsx_program_decompiler to the CMakeLists --- .travis.yml | 2 +- CMakeLists.txt | 2 +- rpcs3.sln | 2 ++ rpcs3/CMakeLists.txt | 4 ++++ rpcs3/Emu/RSX/rsx_cache.cpp | 20 ++++++++++---------- rpcs3/Emu/RSX/rsx_cache.h | 4 ++-- rsx_program_decompiler | 2 +- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index d05e2b979d..9b8c3de021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ before_install: fi; before_script: - - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp + - git submodule update --init rsx_program_decompiler asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp - mkdir build - cd build - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index e9694ce636..ca5fb6699d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,4 +23,4 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin") add_subdirectory( Vulkan ) add_subdirectory( rpcs3 ) - +add_subdirectory( rsx_program_decompiler ) diff --git a/rpcs3.sln b/rpcs3.sln index 89f3bf4ee3..a8cb1bdaeb 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -18,6 +18,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro {A1A8355B-0988-528E-9CC2-B971D6266669} = {A1A8355B-0988-528E-9CC2-B971D6266669} {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D} = {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D} {D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {D6973076-9317-4EF2-A0B8-B7A18AC0713E} + {97E17077-A21F-45EF-9C3A-73A0BC092D7E} = {97E17077-A21F-45EF-9C3A-73A0BC092D7E} + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F} = {7D73447B-3D2D-4DFE-BF62-57E644C1D09F} {8B867186-A0B5-5479-B824-E176EDD27C40} = {8B867186-A0B5-5479-B824-E176EDD27C40} {87B42A9C-3F5C-53D7-9017-2B1CAE39457D} = {87B42A9C-3F5C-53D7-9017-2B1CAE39457D} {8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672} diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 3a2d74af8d..8812204613 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -128,6 +128,8 @@ ${LLVM_INCLUDE_DIRS} # Includes 3rdparty stuff that isn't included yet "${RPCS3_SRC_DIR}/../3rdparty/GL" "${RPCS3_SRC_DIR}/../3rdparty/stblib" +"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler" +"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code" ) if(WIN32) include_directories(BEFORE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2_7") # Slimmed down version of minidx9 for XAudio2_7 only @@ -205,5 +207,7 @@ if(LLVM_FOUND) target_link_libraries(rpcs3 ${LLVM_LIBS}) endif() +target_link_libraries(rpcs3 rsx_decompiler shader_code) + set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h") cotire(rpcs3) diff --git a/rpcs3/Emu/RSX/rsx_cache.cpp b/rpcs3/Emu/RSX/rsx_cache.cpp index 535055114f..86108992ea 100644 --- a/rpcs3/Emu/RSX/rsx_cache.cpp +++ b/rpcs3/Emu/RSX/rsx_cache.cpp @@ -25,7 +25,7 @@ namespace rsx .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; + auto inserted = m_entries.insert({ raw_shader, entry_t{ decompiled_shader } }).first; inserted->second.decompiled.raw = &inserted->first; entry = &inserted->second; } @@ -74,15 +74,15 @@ namespace rsx clear(); } - program_info programs_cache::get(raw_program &raw_program, decompile_language lang) + 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; + 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); + analyze_raw_shader(raw_program_.vertex_shader); + analyze_raw_shader(raw_program_.fragment_shader); - auto found = m_program_cache.find(raw_program); + auto found = m_program_cache.find(raw_program_); if (found != m_program_cache.end()) { @@ -91,10 +91,10 @@ 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.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 }); + m_program_cache.insert({ raw_program_, result }); return result; } diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index e69ba9d2ba..306130b384 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -22,7 +22,7 @@ namespace rsx decompile_language lang; void*(*compile_shader)(program_type type, const std::string &code); - complete_shader(*complete_shader)(const decompiled_shader &shader, program_state state); + rsx::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); @@ -55,7 +55,7 @@ namespace rsx ~programs_cache(); - program_info get(raw_program &raw_program, decompile_language lang); + program_info get(raw_program raw_program_, decompile_language lang); void clear(); }; } diff --git a/rsx_program_decompiler b/rsx_program_decompiler index 0d3807d2ab..e4d938c768 160000 --- a/rsx_program_decompiler +++ b/rsx_program_decompiler @@ -1 +1 @@ -Subproject commit 0d3807d2ab18b13617dd01981355a64144ecdc29 +Subproject commit e4d938c76850549acd837326e2fe0890d5b4be03 From 3b5cd4845e6885160649d11214e7a98b5b9b34fc Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Tue, 21 Jun 2016 00:38:38 +0300 Subject: [PATCH 08/11] OpenGL renderer: use correct MVP matrix. Cleanup Simplified gl::ring_buffer helper --- rpcs3/Emu/RSX/Common/BufferUtils.cpp | 4 + rpcs3/Emu/RSX/Common/BufferUtils.h | 1 + rpcs3/Emu/RSX/GL/GLGSRender.cpp | 247 +++++++++++++++++++-------- rpcs3/Emu/RSX/GL/GLGSRender.h | 7 +- rpcs3/Emu/RSX/GL/gl_helpers.h | 60 +++---- rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp | 5 +- rpcs3/Emu/RSX/GL/vertex_buffer.cpp | 28 +-- rpcs3/Emu/RSX/rsx_utils.cpp | 65 +++++++ rpcs3/Emu/RSX/rsx_utils.h | 6 + 9 files changed, 299 insertions(+), 124 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index 9e8f338f48..b278851f41 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -453,6 +453,10 @@ void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w) _mm_stream_si128((__m128i*)dst, vector); } +void stream_vector(void *dst, f32 x, f32 y, f32 z, f32 w) +{ + stream_vector(dst, (u32&)x, (u32&)y, (u32&)z, (u32&)w); +} void stream_vector_from_memory(void *dst, void *src) { const __m128i &vector = _mm_loadu_si128((__m128i*)src); diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.h b/rpcs3/Emu/RSX/Common/BufferUtils.h index db825d0827..f8213ec27a 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.h +++ b/rpcs3/Emu/RSX/Common/BufferUtils.h @@ -49,6 +49,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, /** * Stream a 128 bits vector to dst. */ +void stream_vector(void *dst, f32 x, f32 y, f32 z, f32 w); void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w); /** diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index ea543967d9..fd36f906e2 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" #include "Utilities/Config.h" #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" +#include "../rsx_utils.h" extern cfg::bool_entry g_cfg_rsx_debug_output; extern cfg::bool_entry g_cfg_rsx_overlay; @@ -153,7 +152,8 @@ void GLGSRender::begin() __glcheck glStencilOp(rsx::method_registers[NV4097_SET_STENCIL_OP_FAIL], rsx::method_registers[NV4097_SET_STENCIL_OP_ZFAIL], rsx::method_registers[NV4097_SET_STENCIL_OP_ZPASS]); - if (rsx::method_registers[NV4097_SET_TWO_SIDED_STENCIL_TEST_ENABLE]) { + if (rsx::method_registers[NV4097_SET_TWO_SIDED_STENCIL_TEST_ENABLE]) + { __glcheck glStencilMaskSeparate(GL_BACK, rsx::method_registers[NV4097_SET_BACK_STENCIL_MASK]); __glcheck glStencilFuncSeparate(GL_BACK, rsx::method_registers[NV4097_SET_BACK_STENCIL_FUNC], rsx::method_registers[NV4097_SET_BACK_STENCIL_FUNC_REF], rsx::method_registers[NV4097_SET_BACK_STENCIL_FUNC_MASK]); @@ -230,8 +230,6 @@ void GLGSRender::begin() __glcheck glCullFace(rsx::method_registers[NV4097_SET_CULL_FACE]); } - glDisable(GL_CULL_FACE); - __glcheck glFrontFace(rsx::method_registers[NV4097_SET_FRONT_FACE] ^ 1); __glcheck enable(rsx::method_registers[NV4097_SET_POLY_SMOOTH_ENABLE], GL_POLYGON_SMOOTH); @@ -248,7 +246,7 @@ void GLGSRender::begin() } std::chrono::time_point now = std::chrono::system_clock::now(); - m_begin_time += std::chrono::duration_cast(now - then).count(); + m_begin_time += (u32)std::chrono::duration_cast(now - then).count(); m_draw_calls++; } @@ -291,8 +289,8 @@ void GLGSRender::end() 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 glProgramUniform1i(m_program->id(), location, texture_index); + __glcheck m_gl_textures[i].init(texture_index, textures[i]); texture_index++; @@ -322,26 +320,38 @@ void GLGSRender::end() */ } + __glcheck 0; + u32 offset_in_index_buffer = set_vertex_buffer(); m_vao.bind(); std::chrono::time_point then = std::chrono::system_clock::now(); if (g_cfg_rsx_debug_output) + { m_program->validate(); + } if (draw_command == rsx::draw_command::indexed) { rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); if (indexed_type == rsx::index_array_type::u32) - __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_INT, (GLvoid *)(offset_in_index_buffer)); - if (indexed_type == rsx::index_array_type::u16) - __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(offset_in_index_buffer)); + { + __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_INT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer); + } + else if (indexed_type == rsx::index_array_type::u16) + { + __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer); + } + else + { + throw std::logic_error("bad index array type"); + } } else if (!is_primitive_native(draw_mode)) { - __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(offset_in_index_buffer)); + __glcheck glDrawElements(gl::draw_mode(draw_mode), vertex_draw_count, GL_UNSIGNED_SHORT, (GLvoid *)(std::ptrdiff_t)offset_in_index_buffer); } else { @@ -349,7 +359,7 @@ void GLGSRender::end() } std::chrono::time_point now = std::chrono::system_clock::now(); - m_draw_time += std::chrono::duration_cast(now - then).count(); + m_draw_time += (u32)std::chrono::duration_cast(now - then).count(); write_buffers(); @@ -377,8 +387,7 @@ void GLGSRender::set_viewport() rsx::window_origin shader_window_origin = rsx::to_window_origin((shader_window >> 12) & 0xf); - //TODO - if (true || shader_window_origin == rsx::window_origin::bottom) + if (shader_window_origin == rsx::window_origin::bottom) { __glcheck glViewport(viewport_x, viewport_y, viewport_w, viewport_h); __glcheck glScissor(scissor_x, scissor_y, scissor_w, scissor_h); @@ -387,11 +396,13 @@ void GLGSRender::set_viewport() { u16 shader_window_height = shader_window & 0xfff; - __glcheck glViewport(viewport_x, shader_window_height - viewport_y - viewport_h - 1, viewport_w, viewport_h); - __glcheck glScissor(scissor_x, shader_window_height - scissor_y - scissor_h - 1, scissor_w, scissor_h); + __glcheck glViewport(viewport_x, shader_window_height - viewport_y - viewport_h + 1, viewport_w, viewport_h); + __glcheck glScissor(scissor_x, shader_window_height - scissor_y - scissor_h + 1, scissor_w, scissor_h); } glEnable(GL_SCISSOR_TEST); + + __glcheck 0; } void GLGSRender::on_init_thread() @@ -406,6 +417,7 @@ void GLGSRender::on_init_thread() LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VENDOR)); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_uniform_buffer_offset_align); glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &m_min_texbuffer_alignment); m_vao.create(); @@ -415,11 +427,11 @@ void GLGSRender::on_init_thread() tex.set_target(gl::texture::target::textureBuffer); } - m_attrib_ring_buffer.reset(new gl::ring_buffer(16 * 0x100000, gl::buffer::target::texture)); - m_uniform_ring_buffer.reset(new gl::ring_buffer(16 * 0x100000, gl::buffer::target::uniform)); - m_index_ring_buffer.reset(new gl::ring_buffer(0x100000, gl::buffer::target::element_array)); + m_attrib_ring_buffer.create(gl::buffer::target::texture, 16 * 0x100000); + m_uniform_ring_buffer.create(gl::buffer::target::uniform, 16 * 0x100000); + m_index_ring_buffer.create(gl::buffer::target::element_array, 0x100000); - m_vao.element_array_buffer = m_index_ring_buffer->get_buffer(); + m_vao.element_array_buffer = m_index_ring_buffer; m_gl_texture_cache.initialize_rtt_cache(); } @@ -446,15 +458,18 @@ void GLGSRender::on_exit() tex.remove(); } - m_attrib_ring_buffer->destroy(); - m_uniform_ring_buffer->destroy(); - m_index_ring_buffer->destroy(); + m_attrib_ring_buffer.remove(); + m_uniform_ring_buffer.remove(); + m_index_ring_buffer.remove(); } void nv4097_clear_surface(u32 arg, GLGSRender* renderer) { //LOG_NOTICE(Log::RSX, "nv4097_clear_surface(0x%x)", arg); - if (!rsx::method_registers[NV4097_SET_SURFACE_FORMAT]) return; + if (!rsx::method_registers[NV4097_SET_SURFACE_FORMAT]) + { + return; + } if ((arg & 0xf3) == 0) { @@ -475,9 +490,10 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer) GLbitfield mask = 0; + rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7); + if (arg & 0x1) { - rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7); u32 max_depth_value = get_max_depth_value(surface_depth_format); u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8; @@ -487,7 +503,7 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer) mask |= GLenum(gl::buffers::depth); } - if (arg & 0x2) + if (surface_depth_format == rsx::surface_depth_format::z24s8 && arg & 0x2) { u8 clear_stencil = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] & 0xff; @@ -535,50 +551,111 @@ bool GLGSRender::do_method(u32 cmd, u32 arg) return true; } +//binding 0 +struct alignas(4) glsl_matrix_buffer +{ + float viewport_matrix[4][4]; + float window_matrix[4][4]; + float normalize_matrix[4][4]; +}; + +//binding 1 +struct alignas(4) glsl_vertex_constants_buffer +{ + float vc[468][4]; +}; + +//binding 2 +struct alignas(4) glsl_fragment_constants_buffer +{ + float fc[2048][4]; +}; + +static void fill_matrix_buffer(glsl_matrix_buffer *buffer) +{ + rsx::fill_viewport_matrix(buffer->viewport_matrix, true); + rsx::fill_window_matrix(buffer->window_matrix, true); + + u32 viewport_horizontal = rsx::method_registers[NV4097_SET_VIEWPORT_HORIZONTAL]; + u32 viewport_vertical = rsx::method_registers[NV4097_SET_VIEWPORT_VERTICAL]; + + f32 viewport_x = f32(viewport_horizontal & 0xffff); + f32 viewport_y = f32(viewport_vertical & 0xffff); + f32 viewport_w = f32(viewport_horizontal >> 16); + f32 viewport_h = f32(viewport_vertical >> 16); + + u32 shader_window = rsx::method_registers[NV4097_SET_SHADER_WINDOW]; + + rsx::window_origin shader_window_origin = rsx::to_window_origin((shader_window >> 12) & 0xf); + u16 shader_window_height = shader_window & 0xfff; + + f32 left = viewport_x; + f32 right = viewport_x + viewport_w; + f32 top = viewport_y; + f32 bottom = viewport_y + viewport_h; + //f32 far_ = (f32&)rsx::method_registers[NV4097_SET_CLIP_MAX]; + //f32 near_ = (f32&)rsx::method_registers[NV4097_SET_CLIP_MIN]; + + if (shader_window_origin == rsx::window_origin::bottom) + { + top = shader_window_height - (viewport_y + viewport_h) + 1; + bottom = shader_window_height - viewport_y + 1; + } + + f32 scale_x = 2.0f / (right - left); + f32 scale_y = 2.0f / (top - bottom); + f32 scale_z = 2.0f; + + f32 offset_x = -(right + left) / (right - left); + f32 offset_y = -(top + bottom) / (top - bottom); + f32 offset_z = -1.0; + + if (shader_window_origin == rsx::window_origin::top) + { + scale_y = -scale_y; + offset_y = -offset_y; + } + + rsx::fill_scale_offset_matrix(buffer->normalize_matrix, true, offset_x, offset_y, offset_z, scale_x, scale_y, scale_z); +} + bool GLGSRender::load_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(); - // u32 fragment_constants_sz = m_prog_buffer.get_fragment_constants_buffer_size(fragment_program); - u32 fragment_constants_sz = info.fragment_shader.decompiled->constants.size() * sizeof(f32) * 4; - fragment_constants_sz = std::max(32U, fragment_constants_sz); - u32 max_buffer_sz = 8192 + 512 + fragment_constants_sz; + u32 fragment_constants_count = info.fragment_shader.decompiled->constants.size(); + u32 fragment_constants_size = fragment_constants_count * sizeof(rsx::fragment_program::ucode_instr); - u32 is_alpha_tested = !!(rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE]); - u8 alpha_ref_raw = (u8)(rsx::method_registers[NV4097_SET_ALPHA_REF] & 0xFF); - float alpha_ref = alpha_ref_raw / 255.f; + u32 max_buffer_sz = + align(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align) + + align(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align) + + align(fragment_constants_size, m_uniform_buffer_offset_align); + + m_uniform_ring_buffer.reserve_and_map(max_buffer_sz); - u8 *buf; u32 scale_offset_offset; u32 vertex_constants_offset; u32 fragment_constants_offset; - m_uniform_ring_buffer->reserve_and_map(max_buffer_sz); - auto mapping = m_uniform_ring_buffer->alloc_from_reserve(512); - buf = static_cast(mapping.first); - scale_offset_offset = mapping.second; - - fill_scale_offset_data(buf, false); - memcpy(buf + 16 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS], sizeof(float)); - memcpy(buf + 17 * sizeof(float), &rsx::method_registers[NV4097_SET_FOG_PARAMS + 1], sizeof(float)); - memcpy(buf + 18 * sizeof(float), &is_alpha_tested, sizeof(u32)); - memcpy(buf + 19 * sizeof(float), &alpha_ref, sizeof(float)); - - mapping = m_uniform_ring_buffer->alloc_from_reserve(512 * 16); - buf = static_cast(mapping.first); - vertex_constants_offset = mapping.second; - - fill_vertex_program_constants_data(buf); - - mapping = m_uniform_ring_buffer->alloc_from_reserve(fragment_constants_sz); - buf = static_cast(mapping.first); - fragment_constants_offset = mapping.second; - - // fill fragment constants - if (!info.fragment_shader.decompiled->constants.empty()) { + auto mapping = m_uniform_ring_buffer.alloc_from_reserve(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align); + fill_matrix_buffer((glsl_matrix_buffer *)mapping.first); + scale_offset_offset = mapping.second; + } + + { + auto mapping = m_uniform_ring_buffer.alloc_from_reserve(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align); + fill_vertex_program_constants_data(mapping.first); + vertex_constants_offset = mapping.second; + } + + if (fragment_constants_size) + { + auto mapping = m_uniform_ring_buffer.alloc_from_reserve(fragment_constants_size, m_uniform_buffer_offset_align); + fragment_constants_offset = mapping.second; + u32 buffer_offset = 0; static const __m128i mask = _mm_set_epi8( @@ -587,31 +664,63 @@ bool GLGSRender::load_program() 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1); - auto ucode = (const rsx::fragment_program::ucode_instr*)info.fragment_shader.decompiled->raw->ucode_ptr; + auto ucode = (const rsx::fragment_program::ucode_instr *)info.fragment_shader.decompiled->raw->ucode_ptr; for (const auto& constant : info.fragment_shader.decompiled->constants) { - const void *data = ucode + (u32)(constant.id / (sizeof(f32) * 4)); + const void *data = ucode + u32(constant.id / sizeof(rsx::fragment_program::ucode_instr)); const __m128i &vector = _mm_loadu_si128((const __m128i*)data); const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask); - _mm_stream_si128((__m128i*)((char*)buf + buffer_offset), shuffled_vector); + _mm_stream_si128((__m128i*)((char*)mapping.first + buffer_offset), shuffled_vector); - //float x = ((float*)((char*)buf + buffer_offset))[0]; - //float y = ((float*)((char*)buf + buffer_offset))[1]; - //float z = ((float*)((char*)buf + buffer_offset))[2]; - //float w = ((float*)((char*)buf + buffer_offset))[3]; + //float x = ((float*)((char*)mapping.first + buffer_offset))[0]; + //float y = ((float*)((char*)mapping.first + buffer_offset))[1]; + //float z = ((float*)((char*)mapping.first + buffer_offset))[2]; + //float w = ((float*)((char*)mapping.first + buffer_offset))[3]; //LOG_WARNING(RSX, "fc%u = {%g, %g, %g, %g}", constant.id, x, y, z, w); buffer_offset += 4 * sizeof(f32); } } - m_uniform_ring_buffer->unmap(); + m_uniform_ring_buffer.unmap(); - glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_ring_buffer->get_buffer().id(), scale_offset_offset, 512); - glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_ring_buffer->get_buffer().id(), vertex_constants_offset, 512 * 16); - glBindBufferRange(GL_UNIFORM_BUFFER, 2, m_uniform_ring_buffer->get_buffer().id(), fragment_constants_offset, fragment_constants_sz); + /* + { + + m_uniform_ring_buffer.bind(); + auto buffer_range = m_uniform_ring_buffer.allocate( + align(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align) + + align(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align)); + + gl::allocator allocator{ m_uniform_ring_buffer, buffer_range }; + + matrix_buffer_range = allocator.allocate(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align); + vertex_constants_buffer_range = allocator.allocate(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align); + + glsl_matrix_buffer *buffer = allocator.get(matrix_buffer_range); + fill_scale_offset_data(buffer, false); + fill_matrix_buffer(buffer); + fill_vertex_program_constants_data(allocator.get(vertex_constants_buffer_range)); + + if (contains_fragment_constants) + { + //fragment_constants_buffer_range = allocator.allocate(info.fragment_shader.decompiled->constants.size() * sizeof(f32) * 4); + } + } + + if (contains_fragment_constants) + { + //m_uniform_ring_buffer.bind_range(2, fragment_constants_buffer_range); + } + */ + + m_uniform_ring_buffer.bind_range(0, scale_offset_offset, sizeof(glsl_matrix_buffer)); + m_uniform_ring_buffer.bind_range(1, vertex_constants_offset, sizeof(glsl_vertex_constants_buffer)); + m_uniform_ring_buffer.bind_range(2, fragment_constants_offset, fragment_constants_size); + + __glcheck 0; return true; } diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 00151259ab..a3620c93ff 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -26,9 +26,9 @@ private: gl::gl_texture_cache m_gl_texture_cache; gl::texture m_gl_attrib_buffers[rsx::limits::vertex_count]; - std::unique_ptr m_attrib_ring_buffer; - std::unique_ptr m_uniform_ring_buffer; - std::unique_ptr m_index_ring_buffer; + gl::ring_buffer m_attrib_ring_buffer; + gl::ring_buffer m_uniform_ring_buffer; + gl::ring_buffer m_index_ring_buffer; u32 m_draw_calls = 0; u32 m_begin_time = 0; @@ -36,6 +36,7 @@ private: u32 m_vertex_upload_time = 0; GLint m_min_texbuffer_alignment = 256; + GLint m_uniform_buffer_offset_align = 256; public: gl::fbo draw_fbo; diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.h b/rpcs3/Emu/RSX/GL/gl_helpers.h index 0f8ada9369..201d7e99bb 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.h +++ b/rpcs3/Emu/RSX/GL/gl_helpers.h @@ -47,7 +47,7 @@ namespace gl } } }; -#define __glcheck gl::__glcheck_impl_t{ __FILE__, __FUNCTION__, __LINE__ }, +#define __glcheck ::gl::__glcheck_impl_t{ __FILE__, __FUNCTION__, __LINE__ }, #else #define __glcheck #endif @@ -496,6 +496,11 @@ namespace gl glBindBuffer((GLenum)target_, m_id); } + void bind() const + { + bind(current_target()); + } + target current_target() const { return m_target; @@ -580,12 +585,9 @@ namespace gl } }; - class ring_buffer + class ring_buffer : public buffer { - buffer storage_buffer; - buffer::target m_target; u32 m_data_loc = 0; - u32 m_size; u32 m_mapped_block_size = 0; u32 m_mapped_block_offset; @@ -594,50 +596,39 @@ namespace gl void *m_mapped_base = nullptr; public: - ring_buffer(u32 initial_size, buffer::target target) + std::pair alloc_and_map(u32 alloc_size) { - storage_buffer.create(); - storage_buffer.data(initial_size); - m_size = initial_size; - m_target = target; - } + alloc_size = align(alloc_size, 0x100); - void destroy() - { - storage_buffer.remove(); - } - - std::pair alloc_and_map(u32 size) - { - size = (size + 255) & ~255; - - glBindBuffer((GLenum)m_target, storage_buffer.id()); - u32 limit = m_data_loc + size; - if (limit > m_size) + buffer::bind(); + u32 limit = m_data_loc + alloc_size; + if (limit > buffer::size()) { - if (size > m_size) - m_size = size; + if (alloc_size > buffer::size()) + { + buffer::data(alloc_size); + } - storage_buffer.data(m_size, nullptr); m_data_loc = 0; } - void *ptr = glMapBufferRange((GLenum)m_target, m_data_loc, size, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); + void *ptr = glMapBufferRange((GLenum)buffer::current_target(), m_data_loc, alloc_size, + GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); u32 offset = m_data_loc; - m_data_loc += size; + m_data_loc += alloc_size; return std::make_pair(ptr, offset); } void unmap() { - glUnmapBuffer((GLenum)m_target); + buffer::unmap(); m_mapped_block_size = 0; m_mapped_base = 0; } void reserve_and_map(u32 max_size) { - max_size = (max_size + 4095) & ~4095; + max_size = align(max_size, 0x1000); auto mapping = alloc_and_map(max_size); m_mapped_base = mapping.first; m_mapped_block_offset = mapping.second; @@ -647,8 +638,7 @@ namespace gl std::pair alloc_from_reserve(u32 size, u32 alignment = 16) { - alignment -= 1; - size = (size + alignment) & ~alignment; + size = align(size, alignment); if (m_mapped_bytes_available < size || !m_mapped_base) { @@ -670,13 +660,13 @@ namespace gl m_mapped_reserve_offset += size; m_mapped_bytes_available -= size; - EXPECTS((offset & alignment) == 0); + EXPECTS((offset & (alignment - 1)) == 0); return std::make_pair(ptr, offset); } - buffer& get_buffer() + void bind_range(u32 index, u32 offset, u32 size) const { - return storage_buffer; + glBindBufferRange((GLenum)current_target(), index, id(), offset, size); } }; diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp index db290e3580..aefc243bab 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp @@ -247,17 +247,16 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, result.code += "out vec4 wpos;\n"; // TODO - if (1) + if (0) { finalize += "\tgl_Position = o0;\n"; - finalize += "\tgl_Position = gl_Position * viewport_matrix;\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"; + " gl_Position.w = o0.w;\n"; } for (std::size_t index = 0; index < 16; ++index) diff --git a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp index 602b158c86..4b1208ee4b 100644 --- a/rpcs3/Emu/RSX/GL/vertex_buffer.cpp +++ b/rpcs3/Emu/RSX/GL/vertex_buffer.cpp @@ -203,14 +203,14 @@ u32 GLGSRender::set_vertex_buffer() vertex_draw_count = (u32)get_index_count(draw_mode, gsl::narrow(vertex_draw_count)); u32 block_sz = vertex_draw_count * type_size; - auto mapping = m_index_ring_buffer->alloc_and_map(block_sz); + auto mapping = m_index_ring_buffer.alloc_and_map(block_sz); void *ptr = mapping.first; offset_in_index_buffer = mapping.second; gsl::span dst{ reinterpret_cast(ptr), gsl::narrow(block_sz) }; std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, type, draw_mode, first_count_commands); - m_index_ring_buffer->unmap(); + m_index_ring_buffer.unmap(); } if (draw_command == rsx::draw_command::inlined_array) @@ -228,7 +228,7 @@ u32 GLGSRender::set_vertex_buffer() } vertex_draw_count = (u32)(inline_vertex_array.size() * sizeof(u32)) / stride; - m_attrib_ring_buffer->reserve_and_map(vertex_draw_count * max_vertex_attrib_size); + m_attrib_ring_buffer.reserve_and_map(vertex_draw_count * max_vertex_attrib_size); for (int index = 0; index < rsx::limits::vertex_count; ++index) { @@ -253,7 +253,7 @@ u32 GLGSRender::set_vertex_buffer() auto &texture = m_gl_attrib_buffers[index]; u8 *src = reinterpret_cast(inline_vertex_array.data()); - auto mapping = m_attrib_ring_buffer->alloc_from_reserve(data_size, m_min_texbuffer_alignment); + auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment); u8 *dst = static_cast(mapping.first); src += offsets[index]; @@ -276,13 +276,13 @@ u32 GLGSRender::set_vertex_buffer() dst += element_size; } - texture.copy_from(m_attrib_ring_buffer->get_buffer(), gl_type, mapping.second, data_size); + texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size); //Link texture to uniform m_program->uniforms.texture(location, index + rsx::limits::textures_count, texture); if (!is_primitive_native(draw_mode)) { - std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw({ { 0, vertex_draw_count } }, draw_mode, *m_index_ring_buffer); + std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw({ { 0, vertex_draw_count } }, draw_mode, m_index_ring_buffer); } } } @@ -298,7 +298,7 @@ u32 GLGSRender::set_vertex_buffer() if (draw_command == rsx::draw_command::array || draw_command == rsx::draw_command::indexed) { u32 verts_allocated = std::max(vertex_draw_count, max_index + 1); - m_attrib_ring_buffer->reserve_and_map(verts_allocated * max_vertex_attrib_size); + m_attrib_ring_buffer.reserve_and_map(verts_allocated * max_vertex_attrib_size); for (int index = 0; index < rsx::limits::vertex_count; ++index) { @@ -337,7 +337,7 @@ u32 GLGSRender::set_vertex_buffer() if (draw_command == rsx::draw_command::array) { - auto mapping = m_attrib_ring_buffer->alloc_from_reserve(data_size, m_min_texbuffer_alignment); + auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment); gsl::byte *dst = static_cast(mapping.first); buffer_offset = mapping.second; @@ -354,7 +354,7 @@ u32 GLGSRender::set_vertex_buffer() if (draw_command == rsx::draw_command::indexed) { data_size = (max_index + 1) * element_size; - auto mapping = m_attrib_ring_buffer->alloc_from_reserve(data_size, m_min_texbuffer_alignment); + auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment); gsl::byte *dst = static_cast(mapping.first); buffer_offset = mapping.second; @@ -364,7 +364,7 @@ u32 GLGSRender::set_vertex_buffer() write_vertex_array_data_to_buffer(dest_span, src_ptr, 0, max_index + 1, vertex_info.type, vertex_info.size, vertex_info.stride, rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size)); } - texture.copy_from(m_attrib_ring_buffer->get_buffer(), gl_type, buffer_offset, data_size); + texture.copy_from(m_attrib_ring_buffer, gl_type, buffer_offset, data_size); //Link texture to uniform m_program->uniforms.texture(location, index + rsx::limits::textures_count, texture); @@ -385,11 +385,11 @@ u32 GLGSRender::set_vertex_buffer() auto &texture = m_gl_attrib_buffers[index]; - auto mapping = m_attrib_ring_buffer->alloc_from_reserve(data_size, m_min_texbuffer_alignment); + auto mapping = m_attrib_ring_buffer.alloc_from_reserve(data_size, m_min_texbuffer_alignment); u8 *dst = static_cast(mapping.first); memcpy(dst, vertex_data.data(), data_size); - texture.copy_from(m_attrib_ring_buffer->get_buffer(), gl_type, mapping.second, data_size); + texture.copy_from(m_attrib_ring_buffer, gl_type, mapping.second, data_size); //Link texture to uniform m_program->uniforms.texture(location, index + rsx::limits::textures_count, texture); @@ -411,11 +411,11 @@ u32 GLGSRender::set_vertex_buffer() if (draw_command == rsx::draw_command::array && !is_primitive_native(draw_mode)) { - std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(first_count_commands, draw_mode, *m_index_ring_buffer); + std::tie(vertex_draw_count, offset_in_index_buffer) = get_index_array_for_emulated_non_indexed_draw(first_count_commands, draw_mode, m_index_ring_buffer); } } - m_attrib_ring_buffer->unmap(); + m_attrib_ring_buffer.unmap(); std::chrono::time_point now = std::chrono::system_clock::now(); m_vertex_upload_time += std::chrono::duration_cast(now - then).count(); diff --git a/rpcs3/Emu/RSX/rsx_utils.cpp b/rpcs3/Emu/RSX/rsx_utils.cpp index 25a9b5ecf2..bd52dfc60b 100644 --- a/rpcs3/Emu/RSX/rsx_utils.cpp +++ b/rpcs3/Emu/RSX/rsx_utils.cpp @@ -1,5 +1,8 @@ #include "stdafx.h" #include "rsx_utils.h" +#include "rsx_methods.h" +#include "Emu/RSX/GCM.h" +#include "Common/BufferUtils.h" extern "C" { @@ -42,4 +45,66 @@ namespace rsx dst.reset(new u8[clip_h * dst_pitch]); clip_image(dst.get(), src, clip_x, clip_y, clip_w, clip_h, bpp, src_pitch, dst_pitch); } + + void fill_scale_offset_matrix(void *dest_, bool transpose, + float offset_x, float offset_y, float offset_z, + float scale_x, float scale_y, float scale_z) + { + char *dest = (char*)dest_; + + if (transpose) + { + stream_vector(dest + 4 * sizeof(f32) * 0, scale_x, 0, 0, 0); + stream_vector(dest + 4 * sizeof(f32) * 1, 0, scale_y, 0, 0); + stream_vector(dest + 4 * sizeof(f32) * 2, 0, 0, scale_z, 0); + stream_vector(dest + 4 * sizeof(f32) * 3, offset_x, offset_y, offset_z, 1); + } + else + { + stream_vector(dest + 4 * sizeof(f32) * 0, scale_x, 0, 0, offset_x); + stream_vector(dest + 4 * sizeof(f32) * 1, 0, scale_y, 0, offset_y); + stream_vector(dest + 4 * sizeof(f32) * 2, 0, 0, scale_z, offset_z); + stream_vector(dest + 4 * sizeof(f32) * 3, 0.f, 0.f, 0.f, 1.f); + } + } + + void fill_window_matrix(void *dest, bool transpose) + { + u32 shader_window = method_registers[NV4097_SET_SHADER_WINDOW]; + + u16 height = shader_window & 0xfff; + window_origin origin = to_window_origin((shader_window >> 12) & 0xf); + window_pixel_center pixelCenter = to_window_pixel_center(shader_window >> 16); + + f32 offset_x = f32(method_registers[NV4097_SET_WINDOW_OFFSET] & 0xffff); + f32 offset_y = f32(method_registers[NV4097_SET_WINDOW_OFFSET] >> 16); + f32 scale_y = 1.0; + + if (origin == window_origin::bottom) + { + offset_y = height - offset_y + 1; + scale_y = -1.0f; + } + + if (false && pixelCenter == window_pixel_center::half) + { + offset_x += 0.5f; + offset_y += 0.5f; + } + + fill_scale_offset_matrix(dest, transpose, offset_x, offset_y, 0.0f, 1.0f, scale_y, 1.0f); + } + + void fill_viewport_matrix(void *buffer, bool transpose) + { + f32 offset_x = (f32&)method_registers[NV4097_SET_VIEWPORT_OFFSET + 0]; + f32 offset_y = (f32&)method_registers[NV4097_SET_VIEWPORT_OFFSET + 1]; + f32 offset_z = (f32&)method_registers[NV4097_SET_VIEWPORT_OFFSET + 2]; + + f32 scale_x = (f32&)method_registers[NV4097_SET_VIEWPORT_SCALE + 0]; + f32 scale_y = (f32&)method_registers[NV4097_SET_VIEWPORT_SCALE + 1]; + f32 scale_z = (f32&)method_registers[NV4097_SET_VIEWPORT_SCALE + 2]; + + fill_scale_offset_matrix(buffer, transpose, offset_x, offset_y, offset_z, scale_x, scale_y, scale_z); + } } diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index d02b63218c..587efc24f4 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -114,4 +114,10 @@ namespace rsx void clip_image(u8 *dst, const u8 *src, int clip_x, int clip_y, int clip_w, int clip_h, int bpp, int src_pitch, int dst_pitch); void clip_image(std::unique_ptr& dst, const u8 *src, int clip_x, int clip_y, int clip_w, int clip_h, int bpp, int src_pitch, int dst_pitch); + + void fill_scale_offset_matrix(void *dest_, bool transpose, + float offset_x, float offset_y, float offset_z, + float scale_x, float scale_y, float scale_z); + void fill_window_matrix(void *dest, bool transpose); + void fill_viewport_matrix(void *buffer, bool transpose); } From e83c387ebe3d22333ceef766b882651c18a252ee Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Tue, 21 Jun 2016 00:39:44 +0300 Subject: [PATCH 09/11] OpenGL renderer: Fixed texture bias setup. --- rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp | 54 +++++++++++++++-------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index 8c811ea9f1..3c5928df48 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -409,10 +409,13 @@ namespace rsx const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); //We can't re-use texture handles if using immutable storage - if (m_id) remove(); - create(); + if (m_id) + { + __glcheck remove(); + } + __glcheck create(); - glActiveTexture(GL_TEXTURE0 + index); + __glcheck glActiveTexture(GL_TEXTURE0 + index); bind(); u32 full_format = tex.format(); @@ -420,8 +423,8 @@ namespace rsx u32 format = full_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); bool is_swizzled = !!(~full_format & CELL_GCM_TEXTURE_LN); - ::gl::pixel_pack_settings().apply(); - ::gl::pixel_unpack_settings().apply(); + __glcheck ::gl::pixel_pack_settings().apply(); + __glcheck ::gl::pixel_unpack_settings().apply(); u32 aligned_pitch = tex.pitch(); @@ -429,8 +432,8 @@ namespace rsx std::vector data_upload_buf(texture_data_sz); u32 block_sz = get_pitch_modifier(format); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - create_and_fill_texture(tex.get_extended_texture_dimension(), tex.get_exact_mipmap_count(), format, tex.width(), tex.height(), tex.depth(), get_subresources_layout(tex), is_swizzled, data_upload_buf); + __glcheck glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + __glcheck create_and_fill_texture(tex.get_extended_texture_dimension(), tex.get_exact_mipmap_count(), format, tex.width(), tex.height(), tex.depth(), get_subresources_layout(tex), is_swizzled, data_upload_buf); const std::array& glRemap = get_swizzle_remap(format); @@ -443,29 +446,28 @@ namespace rsx u8 remap_g = (tex.remap() >> 4) & 0x3; u8 remap_b = (tex.remap() >> 6) & 0x3; - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]); } else { - - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[0]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[1]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[2]); - glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[3]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[0]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[1]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[2]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[3]); } - glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s())); - glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t())); - glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r())); - glTexParameteri(m_target, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.zfunc()]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.zfunc()]); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, tex.bias()); - glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8)); - glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8)); + __glcheck glTexParameterf(m_target, GL_TEXTURE_LOD_BIAS, tex.bias()); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8)); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8)); int min_filter = gl_tex_min_filter(tex.min_filter()); @@ -478,9 +480,9 @@ namespace rsx } } - glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter); - glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter(tex.mag_filter())); - glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter(tex.mag_filter())); + __glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); } void texture::bind() From 8fd306490594e5e58743b84cb9e067dc92ff135e Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Tue, 21 Jun 2016 01:27:14 +0300 Subject: [PATCH 10/11] OpenGL renderer: check for gl errors in release builds. Ignore null-sized textures Cleanup --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 38 +++----------------- rpcs3/Emu/RSX/GL/gl_helpers.h | 2 +- rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp | 54 +++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index fd36f906e2..f9f14ed3fe 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -685,42 +685,14 @@ bool GLGSRender::load_program() m_uniform_ring_buffer.unmap(); - /* - { - - m_uniform_ring_buffer.bind(); - - auto buffer_range = m_uniform_ring_buffer.allocate( - align(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align) + - align(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align)); - - gl::allocator allocator{ m_uniform_ring_buffer, buffer_range }; - - matrix_buffer_range = allocator.allocate(sizeof(glsl_matrix_buffer), m_uniform_buffer_offset_align); - vertex_constants_buffer_range = allocator.allocate(sizeof(glsl_vertex_constants_buffer), m_uniform_buffer_offset_align); - - glsl_matrix_buffer *buffer = allocator.get(matrix_buffer_range); - fill_scale_offset_data(buffer, false); - fill_matrix_buffer(buffer); - fill_vertex_program_constants_data(allocator.get(vertex_constants_buffer_range)); - - if (contains_fragment_constants) - { - //fragment_constants_buffer_range = allocator.allocate(info.fragment_shader.decompiled->constants.size() * sizeof(f32) * 4); - } - } - - if (contains_fragment_constants) - { - //m_uniform_ring_buffer.bind_range(2, fragment_constants_buffer_range); - } - */ - m_uniform_ring_buffer.bind_range(0, scale_offset_offset, sizeof(glsl_matrix_buffer)); m_uniform_ring_buffer.bind_range(1, vertex_constants_offset, sizeof(glsl_vertex_constants_buffer)); - m_uniform_ring_buffer.bind_range(2, fragment_constants_offset, fragment_constants_size); - __glcheck 0; + if (fragment_constants_size) + { + m_uniform_ring_buffer.bind_range(2, fragment_constants_offset, fragment_constants_size); + } + return true; } diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.h b/rpcs3/Emu/RSX/GL/gl_helpers.h index 201d7e99bb..1eecb3a1f2 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.h +++ b/rpcs3/Emu/RSX/GL/gl_helpers.h @@ -14,7 +14,7 @@ namespace gl { -#ifdef _DEBUG +#if 1//def _DEBUG struct __glcheck_impl_t { const char* file; diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index 3c5928df48..2edab403ee 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -296,14 +296,14 @@ namespace rsx int mip_level = 0; if (dim == rsx::texture_dimension_extended::texture_dimension_1d) { - glTexStorage1D(GL_TEXTURE_1D, mipmap_count, get_sized_internal_format(format), width); + __glcheck glTexStorage1D(GL_TEXTURE_1D, mipmap_count, get_sized_internal_format(format), width); if (!is_compressed_format(format)) { const auto &format_type = get_format_type(format); for (const rsx_subresource_layout &layout : input_layouts) { - upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); - glTexSubImage1D(GL_TEXTURE_1D, mip_level++, 0, layout.width_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); + __glcheck upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); + __glcheck glTexSubImage1D(GL_TEXTURE_1D, mip_level++, 0, layout.width_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); } } else @@ -311,7 +311,7 @@ namespace rsx for (const rsx_subresource_layout &layout : input_layouts) { u32 size = layout.width_in_block * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16); - glCompressedTexSubImage1D(GL_TEXTURE_1D, mip_level++, 0, layout.width_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); + __glcheck glCompressedTexSubImage1D(GL_TEXTURE_1D, mip_level++, 0, layout.width_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); } } return; @@ -319,14 +319,14 @@ namespace rsx if (dim == rsx::texture_dimension_extended::texture_dimension_2d) { - glTexStorage2D(GL_TEXTURE_2D, mipmap_count, get_sized_internal_format(format), width, height); + __glcheck glTexStorage2D(GL_TEXTURE_2D, mipmap_count, get_sized_internal_format(format), width, height); if (!is_compressed_format(format)) { const auto &format_type = get_format_type(format); for (const rsx_subresource_layout &layout : input_layouts) { - upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); - glTexSubImage2D(GL_TEXTURE_2D, mip_level++, 0, 0, layout.width_in_block, layout.height_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); + __glcheck upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); + __glcheck glTexSubImage2D(GL_TEXTURE_2D, mip_level++, 0, 0, layout.width_in_block, layout.height_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); } } else @@ -334,7 +334,7 @@ namespace rsx for (const rsx_subresource_layout &layout : input_layouts) { u32 size = layout.width_in_block * layout.height_in_block * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16); - glCompressedTexSubImage2D(GL_TEXTURE_2D, mip_level++, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); + __glcheck glCompressedTexSubImage2D(GL_TEXTURE_2D, mip_level++, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); } } return; @@ -342,7 +342,7 @@ namespace rsx if (dim == rsx::texture_dimension_extended::texture_dimension_cubemap) { - glTexStorage2D(GL_TEXTURE_CUBE_MAP, mipmap_count, get_sized_internal_format(format), width, height); + __glcheck glTexStorage2D(GL_TEXTURE_CUBE_MAP, mipmap_count, get_sized_internal_format(format), width, height); // Note : input_layouts size is get_exact_mipmap_count() for non cubemap texture, and 6 * get_exact_mipmap_count() for cubemap // Thus for non cubemap texture, mip_level / mipmap_per_layer will always be rounded to 0. // mip_level % mipmap_per_layer will always be equal to mip_level @@ -352,7 +352,7 @@ namespace rsx for (const rsx_subresource_layout &layout : input_layouts) { upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); - glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + mip_level / mipmap_count, mip_level % mipmap_count, 0, 0, layout.width_in_block, layout.height_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); + __glcheck glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + mip_level / mipmap_count, mip_level % mipmap_count, 0, 0, layout.width_in_block, layout.height_in_block, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); mip_level++; } } @@ -361,7 +361,7 @@ namespace rsx for (const rsx_subresource_layout &layout : input_layouts) { u32 size = layout.width_in_block * layout.height_in_block * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16); - glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + mip_level / mipmap_count, mip_level % mipmap_count, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); + __glcheck glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + mip_level / mipmap_count, mip_level % mipmap_count, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); mip_level++; } } @@ -370,14 +370,14 @@ namespace rsx if (dim == rsx::texture_dimension_extended::texture_dimension_3d) { - glTexStorage3D(GL_TEXTURE_3D, mipmap_count, get_sized_internal_format(format), width, height, depth); + __glcheck glTexStorage3D(GL_TEXTURE_3D, mipmap_count, get_sized_internal_format(format), width, height, depth); if (!is_compressed_format(format)) { const auto &format_type = get_format_type(format); for (const rsx_subresource_layout &layout : input_layouts) { - upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); - glTexSubImage3D(GL_TEXTURE_3D, mip_level++, 0, 0, 0, layout.width_in_block, layout.height_in_block, depth, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); + __glcheck upload_texture_subresource(staging_buffer, layout, format, is_swizzled, 4); + __glcheck glTexSubImage3D(GL_TEXTURE_3D, mip_level++, 0, 0, 0, layout.width_in_block, layout.height_in_block, depth, std::get<0>(format_type), std::get<1>(format_type), staging_buffer.data()); } } else @@ -385,7 +385,7 @@ namespace rsx for (const rsx_subresource_layout &layout : input_layouts) { u32 size = layout.width_in_block * layout.height_in_block * layout.depth * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16); - glCompressedTexSubImage3D(GL_TEXTURE_3D, mip_level++, 0, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, layout.depth, get_sized_internal_format(format), size, layout.data.data()); + __glcheck glCompressedTexSubImage3D(GL_TEXTURE_3D, mip_level++, 0, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, layout.depth, get_sized_internal_format(format), size, layout.data.data()); } } return; @@ -406,6 +406,29 @@ namespace rsx void texture::init(int index, rsx::texture& tex) { + switch (tex.dimension()) + { + case rsx::texture_dimension::dimension3d: + if (!tex.depth()) + { + return; + } + + case rsx::texture_dimension::dimension2d: + if (!tex.height()) + { + return; + } + + case rsx::texture_dimension::dimension1d: + if (!tex.width()) + { + return; + } + + break; + } + const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); //We can't re-use texture handles if using immutable storage @@ -433,6 +456,7 @@ namespace rsx u32 block_sz = get_pitch_modifier(format); __glcheck glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + __glcheck create_and_fill_texture(tex.get_extended_texture_dimension(), tex.get_exact_mipmap_count(), format, tex.width(), tex.height(), tex.depth(), get_subresources_layout(tex), is_swizzled, data_upload_buf); const std::array& glRemap = get_swizzle_remap(format); From cbf880fb711310d6335945bd4b79625e18b163d5 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Tue, 21 Jun 2016 01:31:50 +0300 Subject: [PATCH 11/11] OpenGL renderer: Proper clipping implementation --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 43 +++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index f9f14ed3fe..54e4e41772 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -215,13 +215,42 @@ void GLGSRender::begin() u8 clip_plane_4 = (clip_plane_control >> 16) & 0xf; u8 clip_plane_5 = (clip_plane_control >> 20) & 0xf; - //TODO - if (__glcheck enable(clip_plane_0, GL_CLIP_DISTANCE0)) {} - if (__glcheck enable(clip_plane_1, GL_CLIP_DISTANCE1)) {} - if (__glcheck enable(clip_plane_2, GL_CLIP_DISTANCE2)) {} - if (__glcheck enable(clip_plane_3, GL_CLIP_DISTANCE3)) {} - if (__glcheck enable(clip_plane_4, GL_CLIP_DISTANCE4)) {} - if (__glcheck enable(clip_plane_5, GL_CLIP_DISTANCE5)) {} + auto set_clip_plane_control = [&](int index, u8 control) + { + int value = 0; + int location; + if (m_program->uniforms.has_location("uc_m" + std::to_string(index), &location)) + { + switch (control) + { + default: + LOG_ERROR(RSX, "bad clip plane control (0x%x)", control); + + case CELL_GCM_USER_CLIP_PLANE_DISABLE: + value = 0; + break; + + case CELL_GCM_USER_CLIP_PLANE_ENABLE_GE: + value = 1; + break; + + case CELL_GCM_USER_CLIP_PLANE_ENABLE_LT: + value = -1; + break; + } + + __glcheck m_program->uniforms[location] = value; + } + + __glcheck enable(value, GL_CLIP_DISTANCE0 + index); + }; + + set_clip_plane_control(0, clip_plane_0); + set_clip_plane_control(1, clip_plane_1); + set_clip_plane_control(2, clip_plane_2); + set_clip_plane_control(3, clip_plane_3); + set_clip_plane_control(4, clip_plane_4); + set_clip_plane_control(5, clip_plane_5); __glcheck enable(rsx::method_registers[NV4097_SET_POLY_OFFSET_FILL_ENABLE], GL_POLYGON_OFFSET_FILL);