diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index df0c1ac0d1..de45a34168 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -278,10 +278,10 @@ std::string FragmentProgramDecompiler::Format(const std::string& code, bool igno const std::pair> repl_list[] = { { "$$", []() -> std::string { return "$"; } }, - { "$0", [this]() -> std::string {return GetSRC(src0);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), *this, src0) }, - { "$1", [this]() -> std::string {return GetSRC(src1);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), this, src1) }, - { "$2", [this]() -> std::string {return GetSRC(src2);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), this, src2) }, - { "$t", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddTex), this) }, + { "$0", [this]() -> std::string {return GetSRC(src0);} }, + { "$1", [this]() -> std::string {return GetSRC(src1);} }, + { "$2", [this]() -> std::string {return GetSRC(src2);} }, + { "$t", [this]() -> std::string { return "tex" + std::to_string(dst.tex_num);} }, { "$_i", [this]() -> std::string {return std::to_string(dst.tex_num);} }, { "$m", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetMask), this) }, { "$ifcond ", [this]() -> std::string @@ -624,6 +624,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) AddX2d(); AddCode(Format("x2d = $0.xyxy + $1.xxxx * $2.xzxz + $1.yyyy * $2.ywyw;", true)); case RSX_FP_OPCODE_TEX: + AddTex(); switch (m_prog.get_texture_dimension(dst.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: @@ -655,6 +656,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) AddX2d(); AddCode(Format("x2d = $0.xyxy + $1.xxxx * $2.xzxz + $1.yyyy * $2.ywyw;", true)); case RSX_FP_OPCODE_TXP: + AddTex(); switch (m_prog.get_texture_dimension(dst.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: @@ -679,6 +681,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) } return false; case RSX_FP_OPCODE_TXD: + AddTex(); switch (m_prog.get_texture_dimension(dst.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: @@ -697,6 +700,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) } return false; case RSX_FP_OPCODE_TXB: + AddTex(); switch (m_prog.get_texture_dimension(dst.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: @@ -715,6 +719,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) } return false; case RSX_FP_OPCODE_TXL: + AddTex(); switch (m_prog.get_texture_dimension(dst.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: diff --git a/rpcs3/Emu/RSX/Common/GLSLCommon.h b/rpcs3/Emu/RSX/Common/GLSLCommon.h index 95f939f57c..6c9720d2dd 100644 --- a/rpcs3/Emu/RSX/Common/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Common/GLSLCommon.h @@ -481,9 +481,10 @@ namespace glsl " }\n" "}\n\n" - "vec4 texture2DReconstruct(sampler2D tex, vec2 coord, float remap)\n" + "vec4 texture2DReconstruct(sampler2D tex, usampler2D stencil_tex, vec2 coord, float remap)\n" "{\n" " vec4 result = decodeLinearDepth(texture(tex, coord.xy).r);\n" + " result.z = float(texture(stencil_tex, coord.xy).x) / 255.f;\n" " uint remap_vector = floatBitsToUint(remap) & 0xFF;\n" " if (remap_vector == 0xE4) return result;\n\n" " vec4 tmp;\n" @@ -555,27 +556,30 @@ namespace glsl " return rgba;\n" "}\n\n" - "#define TEX1D(index, tex, coord1) process_texel(texture(tex, coord1 * texture_parameters[index].x), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX1D_BIAS(index, tex, coord1, bias) process_texel(texture(tex, coord1 * texture_parameters[index].x, bias), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX1D_LOD(index, tex, coord1, lod) process_texel(textureLod(tex, coord1 * texture_parameters[index].x, lod), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX1D_GRAD(index, tex, coord1, dpdx, dpdy) process_texel(textureGrad(tex, coord1 * texture_parameters[index].x, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX1D_PROJ(index, tex, coord2) process_texel(textureProj(tex, coord2 * vec2(texture_parameters[index].x, 1.)), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX_NAME(index) tex##index\n" + "#define TEX_NAME_STENCIL(index) tex##index##_stencil\n\n" - "#define TEX2D(index, tex, coord2) process_texel(texture(tex, coord2 * texture_parameters[index].xy), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_BIAS(index, tex, coord2, bias) process_texel(texture(tex, coord2 * texture_parameters[index].xy, bias), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_LOD(index, tex, coord2, lod) process_texel(textureLod(tex, coord2 * texture_parameters[index].xy, lod), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_GRAD(index, tex, coord2, dpdx, dpdy) process_texel(textureGrad(tex, coord2 * texture_parameters[index].xy, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_PROJ(index, tex, coord4) process_texel(textureProj(tex, coord4 * vec4(texture_parameters[index].xy, 1., 1.)), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX1D(index, coord1) process_texel(texture(TEX_NAME(index), coord1 * texture_parameters[index].x), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX1D_BIAS(index, coord1, bias) process_texel(texture(TEX_NAME(index), coord1 * texture_parameters[index].x, bias), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX1D_LOD(index, coord1, lod) process_texel(textureLod(TEX_NAME(index), coord1 * texture_parameters[index].x, lod), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX1D_GRAD(index, coord1, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), coord1 * texture_parameters[index].x, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX1D_PROJ(index, coord2) process_texel(textureProj(TEX_NAME(index), coord2 * vec2(texture_parameters[index].x, 1.)), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_DEPTH_RGBA8(index, tex, coord2) process_texel(texture2DReconstruct(tex, coord2 * texture_parameters[index].xy, texture_parameters[index].z), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX2D_SHADOW(index, tex, coord3) texture(tex, coord3 * vec3(texture_parameters[index].xy, 1.))\n" - "#define TEX2D_SHADOWPROJ(index, tex, coord4) textureProj(tex, coord4 * vec4(texture_parameters[index].xy, 1., 1.))\n" + "#define TEX2D(index, coord2) process_texel(texture(TEX_NAME(index), coord2 * texture_parameters[index].xy), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX2D_BIAS(index, coord2, bias) process_texel(texture(TEX_NAME(index), coord2 * texture_parameters[index].xy, bias), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX2D_LOD(index, coord2, lod) process_texel(textureLod(TEX_NAME(index), coord2 * texture_parameters[index].xy, lod), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX2D_GRAD(index, coord2, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), coord2 * texture_parameters[index].xy, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX2D_PROJ(index, coord4) process_texel(textureProj(TEX_NAME(index), coord4 * vec4(texture_parameters[index].xy, 1., 1.)), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX3D(index, tex, coord3) process_texel(texture(tex, coord3), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX3D_BIAS(index, tex, coord3, bias) process_texel(texture(tex, coord3, bias), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX3D_LOD(index, tex, coord3, lod) process_texel(textureLod(tex, coord3, lod), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX3D_GRAD(index, tex, coord3, dpdx, dpdy) process_texel(textureGrad(tex, coord3, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" - "#define TEX3D_PROJ(index, tex, coord4) process_texel(textureProj(tex, coord4), floatBitsToUint(texture_parameters[index].w))\n\n"; + "#define TEX2D_DEPTH_RGBA8(index, coord2) process_texel(texture2DReconstruct(TEX_NAME(index), TEX_NAME_STENCIL(index), coord2 * texture_parameters[index].xy, texture_parameters[index].z), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX2D_SHADOW(index, coord3) texture(TEX_NAME(index), coord3 * vec3(texture_parameters[index].xy, 1.))\n" + "#define TEX2D_SHADOWPROJ(index, coord4) textureProj(TEX_NAME(index), coord4 * vec4(texture_parameters[index].xy, 1., 1.))\n" + + "#define TEX3D(index, coord3) process_texel(texture(TEX_NAME(index), coord3), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX3D_BIAS(index, coord3, bias) process_texel(texture(TEX_NAME(index), coord3, bias), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX3D_LOD(index, coord3, lod) process_texel(textureLod(TEX_NAME(index), coord3, lod), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX3D_GRAD(index, coord3, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), coord3, dpdx, dpdy), floatBitsToUint(texture_parameters[index].w))\n" + "#define TEX3D_PROJ(index, coord4) process_texel(textureProj(TEX_NAME(index), coord4), floatBitsToUint(texture_parameters[index].w))\n\n"; } if (require_wpos) @@ -619,49 +623,49 @@ namespace glsl case FUNCTION::FUNCTION_REFL: return "vec4($0 - 2.0 * (dot($0, $1)) * $1)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D: - return "TEX1D($_i, $t, $0.x)"; + return "TEX1D($_i, $0.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_BIAS: - return "TEX1D_BIAS($_i, $t, $0.x, $1.x)"; + return "TEX1D_BIAS($_i, $0.x, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ: - return "TEX1D_PROJ($_i, $t, $0.xy)"; + return "TEX1D_PROJ($_i, $0.xy)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD: - return "TEX1D_LOD($_i, $t, $0.x, $1.x)"; + return "TEX1D_LOD($_i, $0.x, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD: - return "TEX1D_GRAD($_i, $t, $0.x, $1.x, $2.x)"; + return "TEX1D_GRAD($_i, $0.x, $1.x, $2.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D: - return "TEX2D($_i, $t, $0.xy)"; + return "TEX2D($_i, $0.xy)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_BIAS: - return "TEX2D_BIAS($_i, $t, $0.xy, $1.x)"; + return "TEX2D_BIAS($_i, $0.xy, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ: - return "TEX2D_PROJ($_i, $t, $0)"; + return "TEX2D_PROJ($_i, $0)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD: - return "TEX2D_LOD($_i, $t, $0.xy, $1.x)"; + return "TEX2D_LOD($_i, $0.xy, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD: - return "TEX2D_GRAD($_i, $t, $0.xy, $1.xy, $2.xy)"; + return "TEX2D_GRAD($_i, $0.xy, $1.xy, $2.xy)"; case FUNCTION::FUNCTION_TEXTURE_SHADOW2D: - return "TEX2D_SHADOW($_i, $t, $0.xyz)"; + return "TEX2D_SHADOW($_i, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_SHADOW2D_PROJ: - return "TEX2D_SHADOWPROJ($_i, $t, $0)"; + return "TEX2D_SHADOWPROJ($_i, $0)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE: - return "TEX3D($_i, $t, $0.xyz)"; + return "TEX3D($_i, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_BIAS: - return "TEX3D_BIAS($_i, $t, $0.xyz, $1.x)"; + return "TEX3D_BIAS($_i, $0.xyz, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ: - return "TEX3D($_i, $t, ($0.xyz / $0.w))"; + return "TEX3D($_i, ($0.xyz / $0.w))"; case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD: - return "TEX3D_LOD($_i, $t, $0.xyz, $1.x)"; + return "TEX3D_LOD($_i, $0.xyz, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD: - return "TEX3D_GRAD($_i, $t, $0.xyz, $1.xyz, $2.xyz)"; + return "TEX3D_GRAD($_i, $0.xyz, $1.xyz, $2.xyz)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D: - return "TEX3D($_i, $t, $0.xyz)"; + return "TEX3D($_i, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_BIAS: - return "TEX3D_BIAS($_i, $t, $0.xyz, $1.x)"; + return "TEX3D_BIAS($_i, $0.xyz, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ: - return "TEX3D_PROJ($_i, $t, $0)"; + return "TEX3D_PROJ($_i, $0)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD: - return "TEX3D_LOD($_i, $t, $0.xyz, $1.x)"; + return "TEX3D_LOD($_i, $0.xyz, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD: - return "TEX3D_GRAD($_i, $t, $0.xyz, $1.xyz, $2.xyz)"; + return "TEX3D_GRAD($_i, $0.xyz, $1.xyz, $2.xyz)"; case FUNCTION::FUNCTION_DFDX: return "dFdx($0)"; case FUNCTION::FUNCTION_DFDY: @@ -674,7 +678,7 @@ namespace glsl case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCHCUBE: return "textureLod($t, $0.xyz, 0)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA: - return "TEX2D_DEPTH_RGBA8($_i, $t, $0.xy)"; + return "TEX2D_DEPTH_RGBA8($_i, $0.xy)"; } } } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index dc8bc2f333..a64584e3d5 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -225,7 +225,7 @@ std::string VertexProgramDecompiler::Format(const std::string& code) { "$2", std::bind(std::mem_fn(&VertexProgramDecompiler::GetSRC), this, 2) }, { "$s", std::bind(std::mem_fn(&VertexProgramDecompiler::GetSRC), this, 2) }, { "$a", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrReg), this) }, - { "$t", std::bind(std::mem_fn(&VertexProgramDecompiler::GetTex), this) }, + { "$t", [this]() -> std::string { return "vtex" + std::to_string(d2.tex_num); } }, { "$ifcond ", [this]() -> std::string { const std::string& cond = GetCond(); @@ -582,6 +582,7 @@ std::string VertexProgramDecompiler::Decompile() case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break; case RSX_VEC_OPCODE_TXL: { + GetTex(); switch (m_prog.get_texture_dimension(d2.tex_num)) { case rsx::texture_dimension_extended::texture_dimension_1d: diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 64f006b65a..93a7b1c65e 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -116,7 +116,12 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) const auto mask = (1 << index); - if (m_prog.shadow_textures & mask) + if (m_prog.redirected_textures & mask) + { + // Provide a stencil view of the main resource for the S channel + OS << "uniform u" << samplerType << " " << PI.name << "_stencil;\n"; + } + else if (m_prog.shadow_textures & mask) { if (m_shadow_sampled_textures & mask) { diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 6e9db11391..75b112a711 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -401,40 +401,48 @@ void GLGSRender::end() //Bind textures and resolve external copy operations std::chrono::time_point textures_start = steady_clock::now(); void *unused = nullptr; - gl::texture_view* tmp_view; for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { if (current_fp_metadata.referenced_textures_mask & (1 << i)) { - auto sampler_state = static_cast(fs_sampler_state[i].get()); - auto &tex = rsx::method_registers.fragment_textures[i]; + _SelectTexture(GL_FRAGMENT_TEXTURES_START + i); - glActiveTexture(GL_TEXTURE0 + i); - - if (tex.enabled()) + gl::texture_view* view = nullptr; + if (rsx::method_registers.fragment_textures[i].enabled()) { - if (sampler_state->image_handle) + auto sampler_state = static_cast(fs_sampler_state[i].get()); + view = sampler_state->image_handle; + + if (!view && sampler_state->external_subresource_desc.external_handle) { - sampler_state->image_handle->bind(); + view = m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc); } - else if (sampler_state->external_subresource_desc.external_handle && - (tmp_view = m_gl_texture_cache.create_temporary_subresource(unused, sampler_state->external_subresource_desc))) + } + + if (LIKELY(view)) + { + view->bind(); + + if (current_fragment_program.redirected_textures & (1 << i)) { - tmp_view->bind(); - } - else - { - auto target = gl::get_target(sampler_state->image_type); - glBindTexture(target, m_null_textures[target]->id()); + _SelectTexture(GL_STENCIL_MIRRORS_START + i); + + auto root_texture = static_cast(view->image()); + auto stencil_view = root_texture->get_view(0xAAE4, rsx::default_remap_vector, gl::image_aspect::stencil); + stencil_view->bind(); } } else { - glBindTexture(GL_TEXTURE_1D, m_null_textures[GL_TEXTURE_1D]->id()); - glBindTexture(GL_TEXTURE_2D, m_null_textures[GL_TEXTURE_2D]->id()); - glBindTexture(GL_TEXTURE_3D, m_null_textures[GL_TEXTURE_3D]->id()); - glBindTexture(GL_TEXTURE_CUBE_MAP, m_null_textures[GL_TEXTURE_CUBE_MAP]->id()); + auto target = gl::get_target(current_fragment_program.get_texture_dimension(i)); + glBindTexture(target, m_null_textures[target]->id()); + + if (current_fragment_program.redirected_textures & (1 << i)) + { + _SelectTexture(GL_STENCIL_MIRRORS_START + i); + glBindTexture(target, m_null_textures[target]->id()); + } } } } @@ -444,7 +452,7 @@ void GLGSRender::end() if (current_vp_metadata.referenced_textures_mask & (1 << i)) { auto sampler_state = static_cast(vs_sampler_state[i].get()); - glActiveTexture(GL_TEXTURE0 + rsx::limits::fragment_textures_count + i); + _SelectTexture(GL_VERTEX_TEXTURES_START + i); if (sampler_state->image_handle) { @@ -773,25 +781,23 @@ void GLGSRender::on_init_thread() m_max_texbuffer_size = (16 * 0x100000); } - const u32 texture_index_offset = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count; - //Array stream buffer { m_gl_persistent_stream_buffer = std::make_unique(GL_TEXTURE_BUFFER, 0, 0, 0, 0, GL_R8UI); - glActiveTexture(GL_TEXTURE0 + texture_index_offset); + _SelectTexture(GL_STREAM_BUFFER_START + 0); glBindTexture(GL_TEXTURE_BUFFER, m_gl_persistent_stream_buffer->id()); } //Register stream buffer { m_gl_volatile_stream_buffer = std::make_unique(GL_TEXTURE_BUFFER, 0, 0, 0, 0, GL_R8UI); - glActiveTexture(GL_TEXTURE0 + texture_index_offset + 1); + _SelectTexture(GL_STREAM_BUFFER_START + 1); glBindTexture(GL_TEXTURE_BUFFER, m_gl_volatile_stream_buffer->id()); } //Fallback null texture instead of relying on texture0 { - std::vector pixeldata = {0, 0, 0, 0}; + std::vector pixeldata = { 0, 0, 0, 0 }; //1D auto tex1D = std::make_unique(GL_TEXTURE_1D, 1, 1, 1, 1, GL_RGBA8); @@ -888,16 +894,24 @@ void GLGSRender::on_init_thread() } } - for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) + int image_unit = 0; + for (auto &sampler : m_fs_sampler_states) { - m_fs_sampler_states[i].create(); - m_fs_sampler_states[i].bind(i); + sampler.create(); + sampler.bind(image_unit++); } - for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) + for (auto &sampler : m_fs_sampler_mirror_states) { - m_vs_sampler_states[i].create(); - m_vs_sampler_states[i].bind(rsx::limits::fragment_textures_count + i); + sampler.create(); + sampler.apply_defaults(); + sampler.bind(image_unit++); + } + + for (auto &sampler : m_vs_sampler_states) + { + sampler.create(); + sampler.bind(image_unit++); } //Occlusion query @@ -1037,6 +1051,11 @@ void GLGSRender::on_exit() sampler.remove(); } + for (auto &sampler : m_fs_sampler_mirror_states) + { + sampler.remove(); + } + for (auto &sampler : m_vs_sampler_states) { sampler.remove(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 2b48c78a09..eeb307f10c 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -277,8 +277,9 @@ private: GLFragmentProgram m_fragment_prog; GLVertexProgram m_vertex_prog; - gl::sampler_state m_fs_sampler_states[rsx::limits::fragment_textures_count]; - gl::sampler_state m_vs_sampler_states[rsx::limits::vertex_textures_count]; + gl::sampler_state m_fs_sampler_states[rsx::limits::fragment_textures_count]; // Fragment textures + gl::sampler_state m_fs_sampler_mirror_states[rsx::limits::fragment_textures_count]; // Alternate views of fragment textures with different format (e.g Depth vs Stencil for D24S8) + gl::sampler_state m_vs_sampler_states[rsx::limits::vertex_textures_count]; // Vertex textures gl::glsl::program *m_program; diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index 9e48eeae7f..9ce6f44565 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -13,6 +13,13 @@ #include "Utilities/geometry.h" +#define GL_FRAGMENT_TEXTURES_START 0 +#define GL_VERTEX_TEXTURES_START GL_FRAGMENT_TEXTURES_START + 16 +#define GL_STENCIL_MIRRORS_START GL_VERTEX_TEXTURES_START + 4 +#define GL_STREAM_BUFFER_START GL_STENCIL_MIRRORS_START + 16 + +inline static void _SelectTexture(int unit) { glActiveTexture(GL_TEXTURE0 + unit); } + namespace gl { #ifdef _DEBUG @@ -1609,7 +1616,7 @@ namespace gl m_component_layout = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE }; } - ~texture() + virtual ~texture() { glDeleteTextures(1, &m_id); } @@ -1793,20 +1800,29 @@ namespace gl } }; + enum image_aspect : u32 + { + color = 1, + depth = 2, + stencil = 4 + }; + class texture_view { GLuint m_id = 0; GLenum m_target = 0; GLenum m_format = 0; + GLenum m_aspect_flags = 0; texture *m_image_data = nullptr; GLenum component_swizzle[4]; - void create(texture* data, GLenum target, GLenum sized_format, const GLenum* argb_swizzle = nullptr) + void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr) { m_target = target; m_format = sized_format; m_image_data = data; + m_aspect_flags = aspect_flags; const auto num_levels = data->levels(); const auto num_layers = (target != GL_TEXTURE_CUBE_MAP) ? 1 : 6; @@ -1831,22 +1847,34 @@ namespace gl component_swizzle[2] = GL_BLUE; component_swizzle[3] = GL_ALPHA; } + + if (aspect_flags & image_aspect::stencil) + { + constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil); + verify("Invalid aspect mask combination" HERE), (aspect_flags & depth_stencil_mask) != depth_stencil_mask; + + glBindTexture(m_target, m_id); + glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); + } } public: texture_view(const texture_view&) = delete; texture_view(texture_view&&) = delete; - texture_view(texture* data, GLenum target, GLenum sized_format, const GLenum* argb_swizzle = nullptr) + texture_view(texture* data, GLenum target, GLenum sized_format, + const GLenum* argb_swizzle = nullptr, + GLenum aspect_flags = image_aspect::color | image_aspect::depth) { - create(data, target, sized_format, argb_swizzle); + create(data, target, sized_format, aspect_flags, argb_swizzle); } - texture_view(texture* data, const GLenum* argb_swizzle = nullptr) + texture_view(texture* data, const GLenum* argb_swizzle = nullptr, + GLenum aspect_flags = image_aspect::color | image_aspect::depth) { GLenum target = (GLenum)data->get_target(); GLenum sized_format = (GLenum)data->get_internal_format(); - create(data, target, sized_format, argb_swizzle); + create(data, target, sized_format, aspect_flags, argb_swizzle); } ~texture_view() @@ -1869,6 +1897,11 @@ namespace gl return m_format; } + GLenum aspect() const + { + return m_aspect_flags; + } + bool compare_swizzle(GLenum* argb_swizzle) const { return (argb_swizzle[0] == component_swizzle[3] && @@ -1901,23 +1934,26 @@ namespace gl class viewable_image : public texture { - std::unordered_map> views; + std::unordered_multimap> views; public: using texture::texture; - texture_view* get_view(u32 remap_encoding, const std::pair, std::array>& remap) + texture_view* get_view(u32 remap_encoding, const std::pair, std::array>& remap, GLenum aspect_flags = image_aspect::color | image_aspect::depth) { - auto found = views.find(remap_encoding); - if (found != views.end()) + auto found = views.equal_range(remap_encoding); + for (auto It = found.first; It != found.second; ++It) { - return found->second.get(); + if (It->second->aspect() & aspect_flags) + { + return It->second.get(); + } } auto mapping = apply_swizzle_remap(get_native_component_layout(), remap); - auto view = std::make_unique(this, mapping.data()); + auto view = std::make_unique(this, mapping.data(), aspect_flags); auto result = view.get(); - views[remap_encoding] = std::move(view); + views.emplace(remap_encoding, std::move(view)); return result; } diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index a5d9eb8962..9d3b068c52 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -1,6 +1,7 @@ -#pragma once +#pragma once #include "GLVertexProgram.h" #include "GLFragmentProgram.h" +#include "GLHelpers.h" #include "../Common/ProgramStateCache.h" struct GLTraits @@ -42,27 +43,36 @@ struct GLTraits .bind_fragment_data_location("ocol3", 3) .make(); - //Progam locations are guaranteed to not change after linking - //Texture locations are simply bound to the TIUs so this can be done once + // Progam locations are guaranteed to not change after linking + // Texture locations are simply bound to the TIUs so this can be done once for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { int location; if (result->uniforms.has_location(rsx::constants::fragment_texture_names[i], &location)) - result->uniforms[location] = i; + { + // Assign location to TIU + result->uniforms[location] = GL_FRAGMENT_TEXTURES_START + i; + + // Check for stencil mirror + const std::string mirror_name = std::string(rsx::constants::fragment_texture_names[i]) + "_stencil"; + if (result->uniforms.has_location(mirror_name, &location)) + { + // Assign mirror to TIU + result->uniforms[location] = GL_STENCIL_MIRRORS_START + i; + } + } } for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) { int location; if (result->uniforms.has_location(rsx::constants::vertex_texture_names[i], &location)) - result->uniforms[location] = (i + rsx::limits::fragment_textures_count); + result->uniforms[location] = GL_VERTEX_TEXTURES_START + i; } - const int stream_buffer_start = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count; - - //Bind locations 0 and 1 to the stream buffers - result->uniforms[0] = stream_buffer_start; - result->uniforms[1] = stream_buffer_start + 1; + // Bind locations 0 and 1 to the stream buffers + result->uniforms[0] = GL_STREAM_BUFFER_START + 0; + result->uniforms[1] = GL_STREAM_BUFFER_START + 1; LOG_NOTICE(RSX, "*** prog id = %d", result->id()); LOG_NOTICE(RSX, "*** vp id = %d", vertexProgramData.id); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index f147831f84..3c40b75c68 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "GLTexture.h" #include "../GCM.h" #include "../RSXThread.h" @@ -290,6 +290,19 @@ namespace gl glSamplerParameteri(samplerHandle, GL_TEXTURE_COMPARE_MODE, GL_NONE); } + void sampler_state::apply_defaults() + { + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, GL_REPEAT); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameterf(samplerHandle, GL_TEXTURE_LOD_BIAS, 0.f); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_LOD, 0); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MAX_LOD, 0); + glSamplerParameteri(samplerHandle, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + bool is_compressed_format(u32 texture_format) { switch (texture_format) diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index 3bec84504d..3eae41e5fa 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -1,4 +1,4 @@ -#include "OpenGL.h" +#include "OpenGL.h" #include "../GCM.h" #include "../Common/TextureUtils.h" #include "GLHelpers.h" @@ -56,5 +56,7 @@ namespace gl void apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); void apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); + + void apply_defaults(); }; } diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index cf17abdfca..a2f83e7713 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -758,7 +758,7 @@ namespace gl } } - auto dst = std::make_unique(dst_type, width, height, 1, 1, sized_internal_fmt); + std::unique_ptr dst = std::make_unique(dst_type, width, height, 1, 1, sized_internal_fmt); if (copy) { @@ -855,7 +855,7 @@ namespace gl gl::texture_view* generate_cubemap_from_images(void*&, u32 gcm_format, u16 size, const std::vector& sources, const texture_channel_remap_t& /*remap_vector*/) override { const GLenum ifmt = gl::get_sized_internal_format(gcm_format); - auto dst_image = std::make_unique(GL_TEXTURE_CUBE_MAP, size, size, 1, 1, ifmt); + std::unique_ptr dst_image = std::make_unique(GL_TEXTURE_CUBE_MAP, size, size, 1, 1, ifmt); auto view = std::make_unique(dst_image.get(), GL_TEXTURE_CUBE_MAP, ifmt); //Empty GL_ERROR @@ -884,7 +884,7 @@ namespace gl gl::texture_view* generate_3d_from_2d_images(void*&, u32 gcm_format, u16 width, u16 height, u16 depth, const std::vector& sources, const texture_channel_remap_t& /*remap_vector*/) override { const GLenum ifmt = gl::get_sized_internal_format(gcm_format); - auto dst_image = std::make_unique(GL_TEXTURE_3D, width, height, depth, 1, ifmt); + std::unique_ptr dst_image = std::make_unique(GL_TEXTURE_3D, width, height, depth, 1, ifmt); auto view = std::make_unique(dst_image.get(), GL_TEXTURE_3D, ifmt); //Empty GL_ERROR diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index e962b99687..850e405063 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -141,9 +141,24 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) inputs.push_back(in); OS << "layout(set=0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n"; + + if (m_prog.redirected_textures & mask) + { + // Insert stencil mirror declaration + in.name += "_stencil"; + in.location = location; + + inputs.push_back(in); + + OS << "layout(set=0, binding=" << location++ << ") uniform u" << PT.type << " " << in.name << ";\n"; + } } } + // Some drivers (macOS) do not support more than 16 texture descriptors per stage + // TODO: If any application requires more than this, the layout can be restructured a bit + verify("Too many sampler descriptors!" HERE), location <= VERTEX_TEXTURES_FIRST_BIND_SLOT; + std::string constants_block; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index f42278bfa6..d5dafa29c8 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -805,6 +805,8 @@ VKGSRender::~VKGSRender() for (auto& handle : vs_sampler_handles) handle.reset(); + m_stencil_mirror_sampler.reset(); + //Overlay text handler m_text_writer.reset(); @@ -1585,29 +1587,66 @@ void VKGSRender::end() { if (current_fp_metadata.referenced_textures_mask & (1 << i)) { - if (!rsx::method_registers.fragment_textures[i].enabled()) + vk::image_view* view = nullptr; + if (rsx::method_registers.fragment_textures[i].enabled()) { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, rsx::constants::fragment_texture_names[i], m_current_frame->descriptor_set); - continue; + auto sampler_state = static_cast(fs_sampler_state[i].get()); + view = sampler_state->image_handle; + + if (!view && sampler_state->external_subresource_desc.external_handle) + { + //Requires update, copy subresource + view = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); + } } - auto sampler_state = static_cast(fs_sampler_state[i].get()); - auto image_ptr = sampler_state->image_handle; - - if (!image_ptr && sampler_state->external_subresource_desc.external_handle) + if (LIKELY(view)) { - //Requires update, copy subresource - image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); - } + m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_fragment_program, + m_current_frame->descriptor_set); - if (!image_ptr) + if (current_fragment_program.redirected_textures & (1 << i)) + { + // Stencil mirror required + auto root_image = static_cast(view->image()); + auto stencil_view = root_image->get_view(0xAAE4, rsx::default_remap_vector, VK_IMAGE_ASPECT_STENCIL_BIT); + + if (!m_stencil_mirror_sampler) + { + m_stencil_mirror_sampler = std::make_unique(*m_device, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_FALSE, 0.f, 1.f, 0.f, 0.f, + VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_BORDER_COLOR_INT_OPAQUE_BLACK); + } + + m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_fragment_program, + m_current_frame->descriptor_set, + true); + } + } + else { - LOG_ERROR(RSX, "Texture upload failed to texture index %d. Binding null sampler.", i); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, rsx::constants::fragment_texture_names[i], m_current_frame->descriptor_set); - continue; - } + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_fragment_program, + m_current_frame->descriptor_set); - m_program->bind_uniform({ fs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, rsx::constants::fragment_texture_names[i], m_current_frame->descriptor_set); + if (current_fragment_program.redirected_textures & (1 << i)) + { + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_fragment_program, + m_current_frame->descriptor_set, + true); + } + } } } @@ -1617,7 +1656,11 @@ void VKGSRender::end() { if (!rsx::method_registers.vertex_textures[i].enabled()) { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, rsx::constants::vertex_texture_names[i], m_current_frame->descriptor_set); + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_vertex_program, + m_current_frame->descriptor_set); + continue; } @@ -1637,7 +1680,10 @@ void VKGSRender::end() continue; } - m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, rsx::constants::vertex_texture_names[i], m_current_frame->descriptor_set); + m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + i, + ::glsl::program_domain::glsl_vertex_program, + m_current_frame->descriptor_set); } } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index f5fa8b304e..db7b1f82f5 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -291,6 +291,7 @@ private: shared_mutex m_sampler_mutex; u64 surface_store_tag = 0; std::atomic_bool m_samplers_dirty = { true }; + std::unique_ptr m_stencil_mirror_sampler; std::array, rsx::limits::fragment_textures_count> fs_sampler_state = {}; std::array, rsx::limits::vertex_textures_count> vs_sampler_state = {}; std::array, rsx::limits::fragment_textures_count> fs_sampler_handles; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 779443114f..bea7c0cd69 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -692,7 +692,7 @@ namespace vk // TODO: Ctor that uses a provided memory heap - ~image() + virtual ~image() { vkDestroyImage(m_device, value, nullptr); } @@ -746,7 +746,7 @@ namespace vk image_view(VkDevice dev, vk::image* resource, const VkComponentMapping mapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }, const VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}) - : m_device(dev) + : m_device(dev), m_resource(resource) { info.format = resource->info.format; info.image = resource->value; @@ -792,11 +792,17 @@ namespace vk #endif } + vk::image* image() const + { + return m_resource; + } + image_view(const image_view&) = delete; image_view(image_view&&) = delete; private: VkDevice m_device; + vk::image* m_resource = nullptr; void create_impl() { @@ -2844,6 +2850,11 @@ public: std::array, input_type_max_enum> uniforms; VkDevice m_device; + std::array fs_texture_bindings; + std::array fs_texture_mirror_bindings; + std::array vs_texture_bindings; + bool linked; + public: VkPipeline pipeline; u64 attribute_location_mask; @@ -2855,9 +2866,11 @@ public: ~program(); program& load_uniforms(::glsl::program_domain domain, const std::vector& inputs); + program& link(); bool has_uniform(program_input_type type, const std::string &uniform_name); void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorSet &descriptor_set); + void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, VkDescriptorSet &descriptor_set, bool is_stencil_mirror = false); void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, uint32_t binding_point, VkDescriptorSet &descriptor_set); void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, VkDescriptorSet &descriptor_set); diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 19826f8c00..69aadb7a13 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "VKVertexProgram.h" #include "VKFragmentProgram.h" #include "../Common/ProgramStateCache.h" @@ -165,8 +165,9 @@ struct VKTraits info.renderPass = pipelineProperties.render_pass; CHECK_RESULT(vkCreateGraphicsPipelines(dev, nullptr, 1, &info, NULL, &pipeline)); - pipeline_storage_type result = std::make_unique(dev, pipeline, vertexProgramData.uniforms, fragmentProgramData.uniforms); + pipeline_storage_type result = std::make_unique(dev, pipeline, vertexProgramData.uniforms, fragmentProgramData.uniforms); + result->link(); return result; } }; diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 769c44ed0d..731561e537 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "VKHelpers.h" +#include + namespace vk { namespace glsl @@ -10,10 +12,16 @@ namespace vk program::program(VkDevice dev, VkPipeline p, const std::vector &vertex_input, const std::vector& fragment_inputs) : m_device(dev), pipeline(p) { + linked = false; + load_uniforms(program_domain::glsl_vertex_program, vertex_input); load_uniforms(program_domain::glsl_vertex_program, fragment_inputs); attribute_location_mask = 0; vertex_attributes_mask = 0; + + fs_texture_bindings.fill(~0u); + fs_texture_mirror_bindings.fill(~0u); + vs_texture_bindings.fill(~0u); } program::~program() @@ -23,6 +31,8 @@ namespace vk program& program::load_uniforms(program_domain domain, const std::vector& inputs) { + verify("Cannot change uniforms in already linked program!" HERE), !linked; + for (auto &item : inputs) { uniforms[item.type].push_back(item); @@ -31,6 +41,46 @@ namespace vk return *this; } + program& program::link() + { + // Preprocess texture bindings + // Link step is only useful for rasterizer programs, compute programs do not need this + for (const auto &uniform : uniforms[program_input_type::input_type_texture]) + { + if (const auto name_start = uniform.name.find("tex"); name_start != std::string::npos) + { + const auto name_end = uniform.name.find("_stencil"); + const auto index_start = name_start + 3; // Skip 'tex' part + const auto index_length = (name_end != std::string::npos) ? name_end - index_start : name_end; + const auto index_part = uniform.name.substr(index_start, index_length); + const auto index = std::stoi(index_part); + + if (name_start == 0) + { + // Fragment texture (tex...) + if (name_end == std::string::npos) + { + // Normal texture + fs_texture_bindings[index] = uniform.location; + } + else + { + // Stencil mirror + fs_texture_mirror_bindings[index] = uniform.location; + } + } + else + { + // Vertex texture (vtex...) + vs_texture_bindings[index] = uniform.location; + } + } + } + + linked = true; + return *this; + } + bool program::has_uniform(program_input_type type, const std::string &uniform_name) { for (const auto &uniform : uniforms[type]) @@ -71,6 +121,44 @@ namespace vk LOG_NOTICE(RSX, "texture not found in program: %s", uniform_name.c_str()); } + void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, VkDescriptorSet &descriptor_set, bool is_stencil_mirror) + { + verify("Unsupported program domain" HERE, domain != ::glsl::program_domain::glsl_compute_program); + + u32 binding; + if (domain == ::glsl::program_domain::glsl_fragment_program) + { + binding = (is_stencil_mirror) ? fs_texture_mirror_bindings[texture_unit] : fs_texture_bindings[texture_unit]; + } + else + { + binding = vs_texture_bindings[texture_unit]; + } + + if (binding != ~0u) + { + const VkWriteDescriptorSet descriptor_writer = + { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType + nullptr, // pNext + descriptor_set, // dstSet + binding, // dstBinding + 0, // dstArrayElement + 1, // descriptorCount + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // descriptorType + &image_descriptor, // pImageInfo + nullptr, // pBufferInfo + nullptr // pTexelBufferView + }; + + vkUpdateDescriptorSets(m_device, 1, &descriptor_writer, 0, nullptr); + attribute_location_mask |= (1ull << binding); + return; + } + + LOG_NOTICE(RSX, "texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program)? "v" : "", texture_unit); + } + void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, uint32_t binding_point, VkDescriptorSet &descriptor_set) { bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptor_set); diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index cd8280cf1d..c203483cfa 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "stdafx.h" #include "VKHelpers.h" @@ -21,24 +21,9 @@ namespace vk VkImageAspectFlags attachment_aspect_flag = VK_IMAGE_ASPECT_COLOR_BIT; std::unordered_multimap> views; - u64 frame_tag = 0; //frame id when invalidated, 0 if not invalid + u64 frame_tag = 0; // frame id when invalidated, 0 if not invalid - render_target(vk::render_device &dev, - uint32_t memory_type_index, - uint32_t access_flags, - VkImageType image_type, - VkFormat format, - uint32_t width, uint32_t height, uint32_t depth, - uint32_t mipmaps, uint32_t layers, - VkSampleCountFlagBits samples, - VkImageLayout initial_layout, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags image_flags) - - : viewable_image(dev, memory_type_index, access_flags, image_type, format, width, height, depth, - mipmaps, layers, samples, initial_layout, tiling, usage, image_flags) - {} + using viewable_image::viewable_image; vk::image* get_surface() override { diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index c39139b1c8..92d4b7237d 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -516,7 +516,7 @@ namespace vk image_flags = (view_type == VK_IMAGE_VIEW_TYPE_CUBE)? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; } - image.reset(new vk::image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + image.reset(new vk::viewable_image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image_type, dst_format, w, h, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, @@ -543,7 +543,7 @@ namespace vk view_swizzle = vk::apply_swizzle_remap({view_swizzle.a, view_swizzle.r, view_swizzle.g, view_swizzle.b}, remap_vector); VkImageSubresourceRange view_range = { aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 }; - view.reset(new vk::image_view(*vk::get_current_renderer(), image->value, view_type, dst_format, view_swizzle, view_range)); + view.reset(new vk::image_view(*vk::get_current_renderer(), image.get(), view_swizzle, view_range)); if (copy) { @@ -595,14 +595,14 @@ namespace vk VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format); VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format); - image.reset(new vk::image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + image.reset(new vk::viewable_image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_IMAGE_TYPE_2D, dst_format, size, size, 1, 1, 6, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)); VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 6 }; - view.reset(new vk::image_view(*vk::get_current_renderer(), image->value, VK_IMAGE_VIEW_TYPE_CUBE, image->info.format, image->native_component_map, view_range)); + view.reset(new vk::image_view(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range)); VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 6 }; vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range); @@ -658,14 +658,14 @@ namespace vk VkFormat dst_format = vk::get_compatible_sampler_format(m_formats_support, gcm_format); VkImageAspectFlags dst_aspect = vk::get_aspect_flags(dst_format); - image.reset(new vk::image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + image.reset(new vk::viewable_image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_IMAGE_TYPE_3D, dst_format, width, height, depth, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0)); VkImageSubresourceRange view_range = { dst_aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 }; - view.reset(new vk::image_view(*vk::get_current_renderer(), image->value, VK_IMAGE_VIEW_TYPE_3D, image->info.format, image->native_component_map, view_range)); + view.reset(new vk::image_view(*vk::get_current_renderer(), image.get(), image->native_component_map, view_range)); VkImageSubresourceRange dst_range = { dst_aspect, 0, 1, 0, 1 }; vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_range);