diff --git a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h index 5503a2870c..f89c058dec 100644 --- a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h +++ b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h @@ -20,8 +20,9 @@ namespace program_common COMPILER_OPT_ENABLE_KIL = (1 << 11), COMPILER_OPT_ENABLE_STIPPLING = (1 << 12), COMPILER_OPT_ENABLE_INSTANCING = (1 << 13), + COMPILER_OPT_ENABLE_VTX_TEXTURES = (1 << 14), - COMPILER_OPT_MAX = COMPILER_OPT_ENABLE_INSTANCING + COMPILER_OPT_MAX = COMPILER_OPT_ENABLE_VTX_TEXTURES }; static std::string get_vertex_interpreter() diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp index 602d855d76..76cda4d253 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp @@ -8,157 +8,6 @@ namespace vk { - rsx::simple_array get_common_binding_table() - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - rsx::simple_array bindings(binding_table.instancing_constants_buffer_slot + 1); - - u32 idx = 0; - - // Vertex stream, one stream for cacheable data, one stream for transient data - for (int i = 0; i < 3; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_buffers_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_constant_buffers_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_state_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_texture_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; - bindings[idx].binding = binding_table.vertex_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.conditional_render_predicate_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.rasterizer_env_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.instancing_lookup_table_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.instancing_constants_buffer_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - return bindings; - } - - std::tuple> - get_common_pipeline_layout(VkDevice dev) - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - auto bindings = get_common_binding_table(); - u32 idx = ::size32(bindings); - - bindings.resize(binding_table.total_descriptor_bindings); - - for (auto binding = binding_table.textures_first_bind_slot; - binding < binding_table.vertex_textures_first_bind_slot; - binding++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - for (int i = 0; i < rsx::limits::vertex_textures_count; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_textures_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - ensure(idx == binding_table.total_descriptor_bindings); - - std::array push_constants; - push_constants[0].offset = 0; - push_constants[0].size = 20; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - if (vk::emulate_conditional_rendering()) - { - // Conditional render toggle - push_constants[0].size = 24; - } - - const auto set_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants.data(); - - VkPipelineLayout result; - CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); - return std::make_tuple(result, set_layout, bindings); - } - rsx::simple_array get_descriptor_pool_sizes(const rsx::simple_array& bindings) { // Compile descriptor pool sizes diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h index 371d0ebf76..e5ada45bf8 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h @@ -5,13 +5,6 @@ namespace vk { - // Grab standard layout for decompiled RSX programs. Also used by the interpreter. - // FIXME: This generates a bloated monstrosity that needs to die. - std::tuple> get_common_pipeline_layout(VkDevice dev); - - // Returns the standard binding layout without texture slots. Those have special handling depending on the consumer. - rsx::simple_array get_common_binding_table(); - // Returns an array of pool sizes that can be used to generate a proper descriptor pool rsx::simple_array get_descriptor_pool_sizes(const rsx::simple_array& bindings); } diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 1e96087694..008d51f4bb 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -555,7 +555,7 @@ bool VKGSRender::bind_texture_env() { m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_location[i]); + m_fs_binding_table->ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { @@ -576,7 +576,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_stencil_location[i]); + m_fs_binding_table->ftex_stencil_location[i]); } } else @@ -584,13 +584,13 @@ bool VKGSRender::bind_texture_env() const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_location[i]); + m_fs_binding_table->ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_stencil_location[i]); + m_fs_binding_table->ftex_stencil_location[i]); } } } @@ -605,7 +605,7 @@ bool VKGSRender::bind_texture_env() const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); continue; } @@ -628,7 +628,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); continue; } @@ -637,7 +637,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); } return out_of_memory; @@ -874,10 +874,9 @@ void VKGSRender::emit_geometry(u32 sub_index) ensure(m_vertex_layout_storage); if (update_descriptors) { - const auto& binding_table = m_vertex_prog->binding_table; - m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location); - m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 1); - m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 2); + m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location); + m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location + 1); + m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location + 2); } bool reload_state = (!m_current_draw.subdraw_id++); diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 049455a866..c51b81b8fc 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -10,7 +10,7 @@ namespace vk class shader_interpreter; } -struct VKFragmentDecompilerThread : public FragmentProgramDecompiler +class VKFragmentDecompilerThread : public FragmentProgramDecompiler { friend class vk::shader_interpreter; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 4506c870ec..b2003f645c 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1780,8 +1780,11 @@ bool VKGSRender::load_program() m_program = m_shader_interpreter.get( m_pipeline_properties, current_fp_metadata, + current_vp_metadata, current_vertex_program.ctrl, current_fragment_program.ctrl); + + std::tie(m_vs_binding_table, m_fs_binding_table) = get_binding_table(); return true; } } @@ -1879,6 +1882,7 @@ bool VKGSRender::load_program() m_program = m_shader_interpreter.get( m_pipeline_properties, current_fp_metadata, + current_vp_metadata, current_vertex_program.ctrl, current_fragment_program.ctrl); @@ -1900,6 +1904,16 @@ bool VKGSRender::load_program() } } + if (m_program) + { + std::tie(m_vs_binding_table, m_fs_binding_table) = get_binding_table(); + } + else + { + m_vs_binding_table = nullptr; + m_fs_binding_table = nullptr; + } + return m_program != nullptr; } @@ -1911,13 +1925,14 @@ void VKGSRender::load_program_env() } const u32 fragment_constants_size = current_fp_metadata.program_constants_buffer_length; + const bool is_interpreter = m_shader_interpreter.is_interpreter(m_program); const bool update_transform_constants = !!(m_graphics_state & rsx::pipeline_state::transform_constants_dirty); const bool update_fragment_constants = !!(m_graphics_state & rsx::pipeline_state::fragment_constants_dirty); const bool update_vertex_env = !!(m_graphics_state & rsx::pipeline_state::vertex_state_dirty); const bool update_fragment_env = !!(m_graphics_state & rsx::pipeline_state::fragment_state_dirty); const bool update_fragment_texture_env = !!(m_graphics_state & rsx::pipeline_state::fragment_texture_state_dirty); - const bool update_instruction_buffers = (!!m_interpreter_state && m_shader_interpreter.is_interpreter(m_program)); + const bool update_instruction_buffers = (!!m_interpreter_state && is_interpreter); const bool update_raster_env = (rsx::method_registers.polygon_stipple_enabled() && !!(m_graphics_state & rsx::pipeline_state::polygon_stipple_pattern_dirty)); const bool update_instancing_data = rsx::method_registers.current_draw_clause.is_trivial_instanced_draw; @@ -2078,17 +2093,14 @@ void VKGSRender::load_program_env() } } - const auto& vs_binding_table = m_vertex_prog->binding_table; - const auto& fs_binding_table = m_fragment_prog->binding_table; + m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->context_buffer_location); + m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->context_buffer_location); + m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->tex_param_location); + m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->polygon_stipple_params_location); - m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location); - m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location); - m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location); - m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location); - - if (vs_binding_table.cbuf_location != umax) + if (m_vs_binding_table->cbuf_location != umax) { - m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); + m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->cbuf_location); } if (m_shader_interpreter.is_interpreter(m_program)) @@ -2096,21 +2108,21 @@ void VKGSRender::load_program_env() m_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location()); m_program->bind_uniform(m_fragment_instructions_buffer_info, vk::glsl::binding_set_index_fragment, m_shader_interpreter.get_fragment_instruction_location()); } - else if (fs_binding_table.cbuf_location != umax) + else if (m_fs_binding_table->cbuf_location != umax) { - m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.cbuf_location); + m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->cbuf_location); } if (vk::emulate_conditional_rendering()) { auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value; - m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, vs_binding_table.cr_pred_buffer_location); + m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->cr_pred_buffer_location); } if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) { - m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_lut_buffer_location); - m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_cbuf_location); + m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->instanced_lut_buffer_location); + m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->instanced_cbuf_location); } // Clear flags @@ -2137,6 +2149,19 @@ void VKGSRender::load_program_env() m_graphics_state.clear(handled_flags); } +std::pair VKGSRender::get_binding_table() const +{ + ensure(m_program); + + if (!m_shader_interpreter.is_interpreter(m_program)) + { + return { &m_vertex_prog->binding_table, &m_fragment_prog->binding_table }; + } + + const auto& [vs, fs] = m_shader_interpreter.get_shaders(); + return { &vs->binding_table, &fs->binding_table }; +} + bool VKGSRender::is_current_program_interpreted() const { return m_program && m_shader_interpreter.is_interpreter(m_program); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 61dc496402..107da8ebf2 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -26,6 +26,9 @@ using namespace vk::vmm_allocation_pool_; // clang workaround. using namespace vk::upscaling_flags_; // ditto +using vs_binding_table_t = decltype(VKVertexProgram::binding_table); +using fs_binding_table_t = decltype(VKFragmentProgram::binding_table); + namespace vk { using host_data_t = rsx::host_gpu_context_t; @@ -53,6 +56,9 @@ private: vk::glsl::program *m_prev_program = nullptr; vk::pipeline_props m_pipeline_properties; + const vs_binding_table_t* m_vs_binding_table = nullptr; + const fs_binding_table_t* m_fs_binding_table = nullptr; + vk::texture_cache m_texture_cache; vk::surface_cache m_rtts; @@ -78,6 +84,8 @@ private: VkDependencyInfoKHR m_async_compute_dependency_info {}; VkMemoryBarrier2KHR m_async_compute_memory_barrier {}; + std::pair get_binding_table() const; + public: //vk::fbo draw_fbo; std::unique_ptr m_vertex_cache; diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index e7c4862dbc..4ab6a0fa3d 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -12,23 +12,70 @@ namespace vk { - glsl::shader* shader_interpreter::build_vs(u64 compiler_options) + u32 shader_interpreter::init(VKVertexProgram* vk_prog, u64 compiler_options) const + { + std::memset(&vk_prog->binding_table, 0xff, sizeof(vk_prog->binding_table)); + + u32 location = 0; + vk_prog->binding_table.vertex_buffers_location = location; + location += 3; + + vk_prog->binding_table.context_buffer_location = location++; + + if (vk::emulate_conditional_rendering()) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) + { + vk_prog->binding_table.instanced_lut_buffer_location = location++; + vk_prog->binding_table.instanced_cbuf_location = location++; + } + else + { + vk_prog->binding_table.cbuf_location = location++; + } + + if (vk::emulate_conditional_rendering()) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + // Return next index + return location; + } + + u32 shader_interpreter::init(VKFragmentProgram* vk_prog, u64 compiler_opt) const + { + std::memset(&vk_prog->binding_table, 0xff, sizeof(vk_prog->binding_table)); + + vk_prog->binding_table.context_buffer_location = 0; + vk_prog->binding_table.tex_param_location = 1; + vk_prog->binding_table.polygon_stipple_params_location = 2; + + // Return next index + return 3; + } + + VKVertexProgram* shader_interpreter::build_vs(u64 compiler_options) { ::glsl::shader_properties properties{}; properties.domain = ::glsl::program_domain::glsl_vertex_program; properties.require_lit_emulation = true; - // TODO: Extend decompiler thread - // TODO: Rename decompiler thread, it no longer spawns a thread RSXVertexProgram null_prog; std::string shader_str; ParamArray arr; - VKVertexProgram vk_prog; + + // Initialize binding layout + auto vk_prog = std::make_unique(); + m_vertex_instruction_start = init(vk_prog.get(), compiler_options); null_prog.ctrl = (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) ? RSX_SHADER_CONTROL_INSTANCED_CONSTANTS : 0; - VKVertexDecompilerThread comp(null_prog, shader_str, arr, vk_prog); + VKVertexDecompilerThread comp(null_prog, shader_str, arr, *vk_prog); // Initialize compiler properties comp.properties.has_indexed_constants = true; @@ -52,6 +99,12 @@ namespace vk " uvec4 vp_instructions[];\n" "};\n\n"; + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_VTX_TEXTURES) + { + // FIXME: Unimplemented + rsx_log.todo("Vertex textures are currently not implemented for the shader interpreter."); + } + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) { builder << "#define _ENABLE_INSTANCED_CONSTANTS\n"; @@ -68,48 +121,29 @@ namespace vk builder << program_common::interpreter::get_vertex_interpreter(); const std::string s = builder.str(); - auto vs = std::make_unique(); + auto vs = &vk_prog->shader; vs->create(::glsl::program_domain::glsl_vertex_program, s); vs->compile(); - // Prepare input table - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + // Declare local inputs + auto vs_inputs = comp.get_inputs(); + vk::glsl::program_input in; - - in.location = binding_table.vertex_params_bind_slot; + in.set = 0; in.domain = ::glsl::glsl_vertex_program; - in.name = "VertexContextBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_vs_inputs.push_back(in); + in.location = m_vertex_instruction_start; + in.type = glsl::input_type_storage_buffer; + in.name = "VertexInstructionBlock"; + vs_inputs.push_back(in); - in.location = binding_table.vertex_buffers_first_bind_slot; - in.name = "persistent_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); + vk_prog->SetInputs(vs_inputs); - in.location = binding_table.vertex_buffers_first_bind_slot + 1; - in.name = "volatile_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); - - in.location = binding_table.vertex_buffers_first_bind_slot + 2; - in.name = "vertex_layout_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); - - in.location = binding_table.vertex_constant_buffers_bind_slot; - in.name = "VertexConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_vs_inputs.push_back(in); - - // TODO: Bind textures if needed - - auto ret = vs.get(); - m_shader_cache[compiler_options].m_vs = std::move(vs); + auto ret = vk_prog.get(); + m_shader_cache[compiler_options].m_vs = std::move(vk_prog); return ret; } - glsl::shader* shader_interpreter::build_fs(u64 compiler_options) + VKFragmentProgram* shader_interpreter::build_fs(u64 compiler_options) { [[maybe_unused]] ::glsl::shader_properties properties{}; properties.domain = ::glsl::program_domain::glsl_fragment_program; @@ -120,10 +154,13 @@ namespace vk ParamArray arr; std::string shader_str; RSXFragmentProgram frag; - VKFragmentProgram vk_prog; - VKFragmentDecompilerThread comp(shader_str, arr, frag, len, vk_prog); - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + auto vk_prog = std::make_unique(); + m_fragment_instruction_start = init(vk_prog.get(), compiler_options); + m_fragment_textures_start = m_fragment_instruction_start + 1; + + VKFragmentDecompilerThread comp(shader_str, arr, frag, len, *vk_prog); + std::stringstream builder; builder << "#version 450\n" @@ -199,7 +236,7 @@ namespace vk for (int i = 0, bind_location = m_fragment_textures_start; i < 4; ++i) { - builder << "layout(set=0, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n"; + builder << "layout(set=1, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n"; } builder << "\n" @@ -211,7 +248,7 @@ namespace vk } builder << - "layout(std430, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n" + "layout(std430, set=1, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n" "{\n" " uint shader_control;\n" " uint texture_control;\n" @@ -223,140 +260,35 @@ namespace vk builder << program_common::interpreter::get_fragment_interpreter(); const std::string s = builder.str(); - auto fs = std::make_unique(); + auto fs = &vk_prog->shader; fs->create(::glsl::program_domain::glsl_fragment_program, s); fs->compile(); - // Prepare input table + // Declare local inputs + auto inputs = comp.get_inputs(); + vk::glsl::program_input in; - in.location = binding_table.fragment_constant_buffers_bind_slot; + in.set = 1; in.domain = ::glsl::glsl_fragment_program; - in.name = "FragmentConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_fs_inputs.push_back(in); - - in.location = binding_table.fragment_state_bind_slot; - in.name = "FragmentStateBuffer"; - m_fs_inputs.push_back(in); - - in.location = binding_table.fragment_texture_params_bind_slot; - in.name = "TextureParametersBuffer"; - m_fs_inputs.push_back(in); + in.location = m_fragment_instruction_start; + in.type = glsl::input_type_storage_buffer; + in.name = "FragmentInstructionBlock"; + inputs.push_back(in); for (int i = 0, location = m_fragment_textures_start; i < 4; ++i, ++location) { in.location = location; in.name = std::string(type_names[i]) + "_array[16]"; - m_fs_inputs.push_back(in); + in.type = glsl::input_type_texture; + inputs.push_back(in); } - auto ret = fs.get(); - m_shader_cache[compiler_options].m_fs = std::move(fs); + vk_prog->SetInputs(inputs); + + auto ret = vk_prog.get(); + m_shader_cache[compiler_options].m_fs = std::move(vk_prog); return ret; } -/* - std::pair shader_interpreter::create_layout(VkDevice dev) - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - auto bindings = get_common_binding_table(); - u32 idx = ::size32(bindings); - - bindings.resize(binding_table.total_descriptor_bindings); - - // Texture 1D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - m_fragment_textures_start = bindings[idx].binding; - idx++; - - // Texture 2D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 1; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Texture 3D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 2; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Texture CUBE array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 3; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Vertex texture array (2D only) - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 4; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 4; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Vertex program ucode block - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 5; - bindings[idx].pImmutableSamplers = nullptr; - - m_vertex_instruction_start = bindings[idx].binding; - idx++; - - // Fragment program ucode block - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 6; - bindings[idx].pImmutableSamplers = nullptr; - - m_fragment_instruction_start = bindings[idx].binding; - idx++; - bindings.resize(idx); - - m_descriptor_pool_sizes = get_descriptor_pool_sizes(bindings); - - std::array push_constants; - push_constants[0].offset = 0; - push_constants[0].size = 16; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - if (vk::emulate_conditional_rendering()) - { - // Conditional render toggle - push_constants[0].size = 20; - } - - const auto set_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants.data(); - - VkPipelineLayout result; - CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); - return { set_layout, result }; - } -*/ void shader_interpreter::init(const vk::render_device& dev) { @@ -366,19 +298,14 @@ namespace vk void shader_interpreter::destroy() { m_program_cache.clear(); - - for (auto &fs : m_shader_cache) - { - fs.second.m_vs->destroy(); - fs.second.m_fs->destroy(); - } - m_shader_cache.clear(); } glsl::program* shader_interpreter::link(const vk::pipeline_props& properties, u64 compiler_opt) { - glsl::shader *fs, *vs; + VKVertexProgram* vs; + VKFragmentProgram* fs; + if (auto found = m_shader_cache.find(compiler_opt); found != m_shader_cache.end()) { fs = found->second.m_fs.get(); @@ -393,12 +320,12 @@ namespace vk VkPipelineShaderStageCreateInfo shader_stages[2] = {}; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shader_stages[0].module = vs->get_handle(); + shader_stages[0].module = vs->shader.get_handle(); shader_stages[0].pName = "main"; shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].module = fs->get_handle(); + shader_stages[1].module = fs->shader.get_handle(); shader_stages[1].pName = "main"; std::vector dynamic_state_descriptors = @@ -464,7 +391,13 @@ namespace vk info.renderPass = vk::get_renderpass(m_device, properties.renderpass_key); auto compiler = vk::get_pipe_compiler(); - auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs); + auto program = compiler->compile( + info, + vk::pipe_compiler::COMPILE_INLINE | vk::pipe_compiler::SEPARATE_SHADER_OBJECTS, + {}, + vs->uniforms, + fs->uniforms); + return program.release(); } @@ -486,7 +419,8 @@ namespace vk glsl::program* shader_interpreter::get( const vk::pipeline_props& properties, - const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata, + const program_hash_util::fragment_program_utils::fragment_program_metadata& fp_metadata, + const program_hash_util::vertex_program_utils::vertex_program_metadata& vp_metadata, u32 vp_ctrl, u32 fp_ctrl) { @@ -526,11 +460,12 @@ namespace vk if (fp_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT; if (fp_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT; if (fp_ctrl & RSX_SHADER_CONTROL_USES_KIL) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_KIL; - if (metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES; - if (metadata.has_branch_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_FLOW_CTRL; - if (metadata.has_pack_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_PACKING; + if (fp_metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES; + if (fp_metadata.has_branch_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_FLOW_CTRL; + if (fp_metadata.has_pack_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_PACKING; if (rsx::method_registers.polygon_stipple_enabled()) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_STIPPLING; if (vp_ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING; + if (vp_metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_VTX_TEXTURES; if (m_current_key == key) [[likely]] { @@ -567,4 +502,16 @@ namespace vk { return m_fragment_instruction_start; } + + std::pair shader_interpreter::get_shaders() const + { + if (auto found = m_shader_cache.find(m_current_key.compiler_opt); found != m_shader_cache.end()) + { + auto fs = found->second.m_fs.get(); + auto vs = found->second.m_vs.get(); + return { vs, fs }; + } + + return { nullptr, nullptr }; + } }; diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h index aeaad698fb..9d934b3ffa 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h @@ -5,6 +5,9 @@ #include "vkutils/descriptors.h" #include +class VKVertexProgram; +class VKFragmentProgram; + namespace vk { using ::program_hash_util::fragment_program_utils; @@ -12,9 +15,6 @@ namespace vk class shader_interpreter { - std::vector m_vs_inputs; - std::vector m_fs_inputs; - VkDevice m_device = VK_NULL_HANDLE; glsl::program* m_current_interpreter = nullptr; @@ -39,8 +39,8 @@ namespace vk struct shader_cache_entry_t { - std::unique_ptr m_fs; - std::unique_ptr m_vs; + std::unique_ptr m_fs; + std::unique_ptr m_vs; }; std::unordered_map, key_hasher> m_program_cache; @@ -52,20 +52,27 @@ namespace vk pipeline_key m_current_key{}; - glsl::shader* build_vs(u64 compiler_opt); - glsl::shader* build_fs(u64 compiler_opt); + VKVertexProgram* build_vs(u64 compiler_opt); + VKFragmentProgram* build_fs(u64 compiler_opt); glsl::program* link(const vk::pipeline_props& properties, u64 compiler_opt); + u32 init(VKVertexProgram* vk_prog, u64 compiler_opt) const; + u32 init(VKFragmentProgram* vk_prog, u64 compiler_opt) const; + public: void init(const vk::render_device& dev); void destroy(); glsl::program* get( const vk::pipeline_props& properties, - const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata, + const program_hash_util::fragment_program_utils::fragment_program_metadata& fp_metadata, + const program_hash_util::vertex_program_utils::vertex_program_metadata& vp_metadata, u32 vp_ctrl, u32 fp_ctrl); + // Retrieve the shader components that make up the current interpreter + std::pair get_shaders() const; + bool is_interpreter(const glsl::program* prog) const; u32 get_vertex_instruction_location() const; diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index 85d9148834..907d692e85 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -813,7 +813,6 @@ namespace vk memory_map = vk::get_memory_mapping(pdev); m_formats_support = vk::get_optimal_tiling_supported_formats(pdev); - m_pipeline_binding_table = vk::get_pipeline_binding_table(pdev); if (g_cfg.video.disable_vulkan_mem_allocator) { @@ -1148,15 +1147,4 @@ namespace vk return result; } - - pipeline_binding_table get_pipeline_binding_table(const vk::physical_device& dev) - { - pipeline_binding_table result{}; - - // Need to check how many samplers are supported by the driver - const auto usable_samplers = std::min(dev.get_limits().maxPerStageDescriptorSampledImages, 32u); - result.vertex_textures_first_bind_slot = result.textures_first_bind_slot + usable_samplers; - result.total_descriptor_bindings = result.vertex_textures_first_bind_slot + 4; - return result; - } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.h b/rpcs3/Emu/RSX/VK/vkutils/device.h index 63e30d3d42..0511802aac 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.h +++ b/rpcs3/Emu/RSX/VK/vkutils/device.h @@ -137,7 +137,6 @@ namespace vk physical_device* pgpu = nullptr; memory_type_mapping memory_map{}; gpu_formats_support m_formats_support{}; - pipeline_binding_table m_pipeline_binding_table{}; std::unique_ptr m_allocator; VkDevice dev = VK_NULL_HANDLE; @@ -168,7 +167,6 @@ namespace vk const physical_device& gpu() const { return *pgpu; } const memory_type_mapping& get_memory_mapping() const { return memory_map; } const gpu_formats_support& get_formats_support() const { return m_formats_support; } - const pipeline_binding_table& get_pipeline_binding_table() const { return m_pipeline_binding_table; } const gpu_shader_types_support& get_shader_types_support() const { return pgpu->shader_types_support; } const custom_border_color_features& get_custom_border_color_support() const { return pgpu->custom_border_color_support; } const multidraw_features get_multidraw_support() const { return pgpu->multidraw_support; } @@ -206,7 +204,6 @@ namespace vk memory_type_mapping get_memory_mapping(const physical_device& dev); gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev); - pipeline_binding_table get_pipeline_binding_table(const physical_device& dev); extern const render_device* g_render_device; }