diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index 3fb7689384..ad819b5ef9 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -78,6 +78,7 @@ namespace program_hash_util * - static void recompile_fragment_program(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID); * - static void recompile_vertex_program(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID); * - static PipelineData build_program(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData); +* - static void validate_pipeline_properties(const VertexProgramData &vertexProgramData, const FragmentProgramData &fragmentProgramData, PipelineProperties& props); */ template class program_state_cache @@ -261,7 +262,7 @@ public: pipeline_storage_type& getGraphicPipelineState( const RSXVertexProgram& vertexShader, const RSXFragmentProgram& fragmentShader, - const pipeline_properties& pipelineProperties, + pipeline_properties& pipelineProperties, Args&& ...args ) { @@ -273,6 +274,7 @@ public: bool already_existing_fragment_program = std::get<1>(fp_search); bool already_existing_vertex_program = std::get<1>(vp_search); + backend_traits::validate_pipeline_properties(vertex_program, fragment_program, pipelineProperties); pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties }; if (already_existing_fragment_program && already_existing_vertex_program) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index 0c7f84c04c..52c63cb238 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -145,6 +145,11 @@ struct D3D12Traits vertexProgramData.id = (u32)ID; } + static + void validate_pipeline_properties(const vertex_program_type&, const fragment_program_type&, pipeline_properties&) + { + } + static pipeline_storage_type build_pipeline( const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties, diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index 4499203a80..c8b8477d2e 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -24,6 +24,11 @@ struct GLTraits vertexProgramData.Compile(); } + static + void validate_pipeline_properties(const vertex_program_type&, const fragment_program_type&, pipeline_properties&) + { + } + static pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties&) { diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 92056267bf..2e13b9cac3 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -96,7 +96,10 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS) for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) { if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second)) + { OS << "layout(location=" << std::to_string(output_index++) << ") " << "out vec4 " << table[i].first << ";\n"; + vk_prog->output_color_masks[i] = UINT32_MAX; + } } } diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 5cd521cf36..cde6d7291a 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -52,6 +52,8 @@ public: std::string shader; std::vector FragmentConstantOffsetCache; + std::array output_color_masks{ {} }; + std::vector uniforms; void SetInputs(std::vector& uniforms); /** diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index c037a80c37..8049084e4b 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -95,6 +95,16 @@ struct VKTraits vertexProgramData.Compile(); } + static + void validate_pipeline_properties(const VKVertexProgram&, const VKFragmentProgram &fp, vk::pipeline_props& properties) + { + //Explicitly disable writing to undefined registers + properties.att_state[0].colorWriteMask &= fp.output_color_masks[0]; + properties.att_state[1].colorWriteMask &= fp.output_color_masks[1]; + properties.att_state[2].colorWriteMask &= fp.output_color_masks[2]; + properties.att_state[3].colorWriteMask &= fp.output_color_masks[3]; + } + static pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const vk::pipeline_props &pipelineProperties, VkDevice dev, VkPipelineLayout common_pipeline_layout)