From 2337bf204cd60a85f8d349c34b189b6ef06d0821 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 17 Jul 2016 19:57:50 +0300 Subject: [PATCH] vk/dx12: Enable/fix separate back and front lighting (#1927) * vk: separate specular color rsx: separate front color output from back color output re-enable front-back diffuse lighting vk: fix front face selection and actually enable face culling * dx12: Hide constant-key blended visuals (by common use of factor, 1-factor) * dx12: Fix 2 sided lighting when the shader does not compute both outputs * vk/dx12: confirm that src register exists before copying for 2-sided lighting --- rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp | 8 +-- .../D3D12/D3D12VertexProgramDecompiler.cpp | 25 +++++++ rpcs3/Emu/RSX/RSXFragmentProgram.h | 2 + rpcs3/Emu/RSX/RSXThread.cpp | 2 + rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp | 28 ++++---- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 67 ++++++++++++++++++- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 22 ++++-- rpcs3/Emu/RSX/VK/VKProgramBuffer.h | 13 +--- rpcs3/Emu/RSX/VK/VKVertexProgram.cpp | 50 ++++++++++++-- 9 files changed, 177 insertions(+), 40 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp index 35549795a2..d4c1ff9e23 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp @@ -41,14 +41,14 @@ D3D12_BLEND get_blend_factor(rsx::blend_factor factor) case rsx::blend_factor::constant_color: case rsx::blend_factor::constant_alpha: { - LOG_ERROR(RSX, "Constant blend factor not supported. Using ONE instead"); - return D3D12_BLEND_ONE; + LOG_ERROR(RSX, "Constant blend factor not supported. Using ZERO instead"); + return D3D12_BLEND_ZERO; } case rsx::blend_factor::one_minus_constant_color: case rsx::blend_factor::one_minus_constant_alpha: { - LOG_ERROR(RSX, "Inv Constant blend factor not supported. Using ZERO instead"); - return D3D12_BLEND_ZERO; + LOG_ERROR(RSX, "Inv Constant blend factor not supported. Using ONE instead"); + return D3D12_BLEND_ONE; } } throw EXCEPTION("Invalid blend factor (0x%x)", factor); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp index f49a409e40..4cd4aabad0 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp @@ -210,12 +210,37 @@ void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS) void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS) { OS << " PixelInput Out = (PixelInput)0;" << std::endl; + + bool insert_front_diffuse = (rsx_vertex_program.output_mask & 1); + bool insert_front_specular = (rsx_vertex_program.output_mask & 2); + + bool insert_back_diffuse = (rsx_vertex_program.output_mask & 4); + bool insert_back_specular = (rsx_vertex_program.output_mask & 8); + // Declare inside main function for (auto &i : reg_table) { if (m_parr.HasParam(PF_PARAM_NONE, "float4", i.src_reg)) + { + if (i.name == "front_diff_color") + insert_front_diffuse = false; + + if (i.name == "front_spec_color") + insert_front_specular = false; + OS << " Out." << i.src_reg << " = " << i.src_reg << ";" << std::endl; + } } + + //If 2 sided lighting is active and only back is written, copy the value to the front side (Outrun online arcade) + if (insert_front_diffuse && insert_back_diffuse) + if (m_parr.HasParam(PF_PARAM_NONE, "float4", "dst_reg1")) + OS << " Out.dst_reg3 = dst_reg1;\n"; + + if (insert_front_specular && insert_back_specular) + if (m_parr.HasParam(PF_PARAM_NONE, "float4", "dst_reg2")) + OS << " Out.dst_reg4 = dst_reg2;\n"; + OS << " Out.dst_reg0 = mul(Out.dst_reg0, scaleOffsetMat);" << std::endl; OS << " return Out;" << std::endl; OS << "}" << std::endl; diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 437b4c95bf..5c88a3c414 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -225,6 +225,8 @@ struct RSXFragmentProgram bool front_back_color_enabled : 1; bool back_color_diffuse_output : 1; bool back_color_specular_output : 1; + bool front_color_diffuse_output : 1; + bool front_color_specular_output : 1; u32 texture_dimensions; rsx::window_origin origin_mode; rsx::window_pixel_center pixel_center_mode; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index e5f8cbf4e6..b0da9c5a0c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -738,6 +738,8 @@ namespace rsx result.front_back_color_enabled = !rsx::method_registers.two_side_light_en(); result.back_color_diffuse_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE); result.back_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR); + result.front_color_diffuse_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE); + result.front_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR); result.alpha_func = rsx::method_registers.alpha_func(); result.fog_equation = rsx::method_registers.fog_equation(); result.origin_mode = rsx::method_registers.shader_window_origin(); diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index d5c6c166ef..04f8f2ffd0 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -231,20 +231,22 @@ namespace vk static const varying_register_t varying_regs[] = { - { "diff_color", 0 }, - { "tc0", 1 }, - { "tc1", 2 }, - { "tc2", 3 }, - { "tc3", 4 }, - { "tc4", 5 }, - { "tc5", 6 }, - { "tc6", 7 }, - { "tc7", 8 }, - { "tc8", 9 }, - { "tc9", 10 }, + { "tc0", 0 }, + { "tc1", 1 }, + { "tc2", 2 }, + { "tc3", 3 }, + { "tc4", 4 }, + { "tc5", 5 }, + { "tc6", 6 }, + { "tc7", 7 }, + { "tc8", 8 }, + { "tc9", 9 }, + { "diff_color", 10 }, + { "back_diff_color", 10 }, { "front_diff_color", 11 }, - { "front_spec_color", 12 }, - { "spec_color", 13 }, + { "spec_color", 12 }, + { "back_spec_color", 12 }, + { "front_spec_color", 13 }, { "fog_c", 14 }, { "fogc", 14 } }; diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 85e60d9582..1a1c6f098e 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -60,14 +60,38 @@ void VKFragmentDecompilerThread::insertIntputs(std::stringstream & OS) if (PI.name == "ssa") continue; const vk::varying_register_t ® = vk::get_varying_register(PI.name); - std::string var_name = PI.name; + + if (m_prog.front_back_color_enabled) + { + if (m_prog.back_color_diffuse_output && var_name == "diff_color") + var_name = "back_diff_color"; + + if (m_prog.back_color_specular_output && var_name == "spec_color") + var_name = "back_spec_color"; + } + if (var_name == "fogc") var_name = "fog_c"; OS << "layout(location=" << reg.reg_location << ") in " << PT.type << " " << var_name << ";" << std::endl; } } + + if (m_prog.front_back_color_enabled) + { + if (m_prog.front_color_diffuse_output) + { + const vk::varying_register_t ® = vk::get_varying_register("front_diff_color"); + OS << "layout(location=" << reg.reg_location << ") in vec4 front_diff_color;" << std::endl; + } + + if (m_prog.front_color_specular_output) + { + const vk::varying_register_t ® = vk::get_varying_register("front_spec_color"); + OS << "layout(location=" << reg.reg_location << ") in vec4 front_spec_color;" << std::endl; + } + } } void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS) @@ -202,6 +226,47 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { for (const ParamItem& PI : PT.items) { + if (m_prog.front_back_color_enabled) + { + if (PI.name == "spec_color") + { + if (m_prog.back_color_specular_output || m_prog.front_color_specular_output) + { + if (m_prog.back_color_specular_output && m_prog.front_color_specular_output) + { + OS << " vec4 spec_color = gl_FrontFacing ? front_spec_color : back_spec_color;\n"; + } + else if (m_prog.back_color_specular_output) + { + OS << " vec4 spec_color = back_spec_color;\n"; + } + else + OS << " vec4 spec_color = front_spec_color;\n"; + } + + continue; + } + + else if (PI.name == "diff_color") + { + if (m_prog.back_color_diffuse_output || m_prog.front_color_diffuse_output) + { + if (m_prog.back_color_diffuse_output && m_prog.front_color_diffuse_output) + { + OS << " vec4 diff_color = gl_FrontFacing ? front_diff_color : back_diff_color;\n"; + } + else if (m_prog.back_color_diffuse_output) + { + OS << " vec4 diff_color = back_diff_color;\n"; + } + else + OS << " vec4 diff_color = front_diff_color;\n"; + } + + continue; + } + } + if (PI.name == "fogc") { vk::insert_fog_declaration(OS, m_prog.fog_equation); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 10983b9bef..96cbf86610 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -262,12 +262,17 @@ namespace vk } } - VkFrontFace get_front_face_ccw(rsx::front_face ffv) + VkFrontFace get_front_face(rsx::front_face ffv) { + u32 mask = 1; + + if (rsx::to_window_origin((rsx::method_registers[NV4097_SET_SHADER_WINDOW] >> 12) & 0xf) == rsx::window_origin::bottom) + mask = 0; + switch (ffv) { - case rsx::front_face::cw: return VK_FRONT_FACE_CLOCKWISE; - case rsx::front_face::ccw: return VK_FRONT_FACE_COUNTER_CLOCKWISE; + case rsx::front_face::cw: return (VkFrontFace)(VK_FRONT_FACE_CLOCKWISE ^ mask); + case rsx::front_face::ccw: return (VkFrontFace)(VK_FRONT_FACE_COUNTER_CLOCKWISE ^ mask); default: throw EXCEPTION("Unknown front face value: 0x%X", ffv); } @@ -307,6 +312,7 @@ namespace color_attachement_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; color_attachement_description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; color_attachement_description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + for (u32 i = 0; i < number_of_color_surface; ++i) { attachments.push_back(color_attachement_description); @@ -867,7 +873,6 @@ bool VKGSRender::load_program() vk::pipeline_props properties = {}; - properties.ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; bool unused; properties.ia.topology = vk::get_appropriate_topology(draw_mode, unused); @@ -986,6 +991,12 @@ bool VKGSRender::load_program() else properties.ds.depthTestEnable = VK_FALSE; + properties.rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + properties.rs.polygonMode = VK_POLYGON_MODE_FILL; + properties.rs.depthClampEnable = VK_FALSE; + properties.rs.rasterizerDiscardEnable = VK_FALSE; + properties.rs.depthBiasEnable = VK_FALSE; + if (rsx::method_registers.cull_face_enabled()) { switch (rsx::method_registers.cull_face_mode()) @@ -1007,12 +1018,13 @@ bool VKGSRender::load_program() else properties.rs.cullMode = VK_CULL_MODE_NONE; - properties.rs.frontFace = vk::get_front_face_ccw(rsx::method_registers.front_face_mode()); + properties.rs.frontFace = vk::get_front_face(rsx::method_registers.front_face_mode()); size_t idx = vk::get_render_pass_location( vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first, vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()), (u8)vk::get_draw_buffers(rsx::method_registers.surface_color_target()).size()); + properties.render_pass = m_render_passes[idx]; properties.num_targets = m_draw_buffers_count; diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 3fad946336..3cacf6cee3 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -29,6 +29,7 @@ namespace vk return false; if (memcmp(&rs, &other.rs, sizeof(VkPipelineRasterizationStateCreateInfo))) return false; + return num_targets == other.num_targets; } }; @@ -55,6 +56,7 @@ namespace std size_t seed = hash()(pipelineProperties.num_targets); seed ^= hash_struct(pipelineProperties.ia); seed ^= hash_struct(pipelineProperties.ds); + seed ^= hash_struct(pipelineProperties.rs); seed ^= hash_struct(pipelineProperties.att_state[0]); return hash()(seed); } @@ -125,21 +127,12 @@ struct VKTraits cb.attachmentCount = 1; cb.pAttachments = pipelineProperties.att_state; - VkPipelineRasterizationStateCreateInfo rs = {}; - rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rs.polygonMode = VK_POLYGON_MODE_FILL; - rs.cullMode = VK_CULL_MODE_NONE; - rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rs.depthClampEnable = VK_FALSE; - rs.rasterizerDiscardEnable = VK_FALSE; - rs.depthBiasEnable = VK_FALSE; - VkPipeline pipeline; VkGraphicsPipelineCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.pVertexInputState = &vi; info.pInputAssemblyState = &pipelineProperties.ia; - info.pRasterizationState = &rs; + info.pRasterizationState = &pipelineProperties.rs; info.pColorBlendState = &cb; info.pMultisampleState = &ms; info.pViewportState = &vp; diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index 513a99b5ff..34b03f6601 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -129,8 +129,8 @@ struct reg_info static const reg_info reg_table[] = { { "gl_Position", false, "dst_reg0", "", false }, - { "diff_color", true, "dst_reg1", "", false }, - { "spec_color", true, "dst_reg2", "", false }, + { "back_diff_color", true, "dst_reg1", "", false }, + { "back_spec_color", true, "dst_reg2", "", false }, { "front_diff_color", true, "dst_reg3", "", false }, { "front_spec_color", true, "dst_reg4", "", false }, { "fog_c", true, "dst_reg5", ".xxxx", true }, @@ -159,18 +159,32 @@ static const reg_info reg_table[] = void VKVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::vector & outputs) { + bool insert_front_diffuse = (rsx_vertex_program.output_mask & 1); + bool insert_back_diffuse = (rsx_vertex_program.output_mask & 4); + + bool insert_front_specular = (rsx_vertex_program.output_mask & 2); + bool insert_back_specular = (rsx_vertex_program.output_mask & 8); + for (auto &i : reg_table) { if (m_parr.HasParam(PF_PARAM_NONE, "vec4", i.src_reg) && i.need_declare) { + if (i.name == "front_diff_color") + insert_front_diffuse = false; + + if (i.name == "front_spec_color") + insert_front_specular = false; + const vk::varying_register_t ® = vk::get_varying_register(i.name); - - // if (i.name == "fogc") - // OS << "layout(location=" << reg.reg_location << ") out vec4 fog_c;" << std::endl; - // else - OS << "layout(location=" << reg.reg_location << ") out vec4 " << i.name << ";" << std::endl; + OS << "layout(location=" << reg.reg_location << ") out vec4 " << i.name << ";" << std::endl; } } + + if (insert_back_diffuse && insert_front_diffuse) + OS << "layout(location=" << vk::get_varying_register("front_diff_color").reg_location << ") out vec4 front_diff_color;" << std::endl; + + if (insert_back_specular && insert_front_specular) + OS << "layout(location=" << vk::get_varying_register("front_spec_color").reg_location << ") out vec4 front_spec_color;" << std::endl; } namespace vk @@ -240,12 +254,34 @@ void VKVertexDecompilerThread::insertMainStart(std::stringstream & OS) void VKVertexDecompilerThread::insertMainEnd(std::stringstream & OS) { + bool insert_front_diffuse = (rsx_vertex_program.output_mask & 1); + bool insert_front_specular = (rsx_vertex_program.output_mask & 2); + + bool insert_back_diffuse = (rsx_vertex_program.output_mask & 4); + bool insert_back_specular = (rsx_vertex_program.output_mask & 8); + for (auto &i : reg_table) { if (m_parr.HasParam(PF_PARAM_NONE, "vec4", i.src_reg)) + { + if (i.name == "front_spec_color") + insert_front_diffuse = false; + + if (i.name == "front_spec_color") + insert_front_specular = false; + OS << " " << i.name << " = " << i.src_reg << i.src_reg_mask << ";" << std::endl; + } } + if (insert_back_diffuse && insert_front_diffuse) + if (m_parr.HasParam(PF_PARAM_NONE, "vec4", "dst_reg1")) + OS << " front_diff_color = dst_reg1;\n"; + + if (insert_back_specular && insert_front_specular) + if (m_parr.HasParam(PF_PARAM_NONE, "vec4", "dst_reg2")) + OS << " front_spec_color = dst_reg2;\n"; + OS << " gl_Position = gl_Position * scaleOffsetMat;" << std::endl; OS << "}" << std::endl; }