diff options
Diffstat (limited to 'src')
5 files changed, 76 insertions, 2 deletions
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index da5c550ea..1b9611c59 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -60,6 +60,11 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 60 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | 60 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); |
| 61 | topology.Assign(regs.draw.topology); | 61 | topology.Assign(regs.draw.topology); |
| 62 | 62 | ||
| 63 | alpha_raw = 0; | ||
| 64 | alpha_test_enabled.Assign(regs.alpha_test_enabled); | ||
| 65 | alpha_test_func.Assign(PackComparisonOp(regs.alpha_test_func)); | ||
| 66 | std::memcpy(&alpha_test_ref, ®s.alpha_test_ref, sizeof(u32)); // TODO: C++20 std::bit_cast | ||
| 67 | |||
| 63 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast | 68 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast |
| 64 | 69 | ||
| 65 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 70 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 2c18eeaae..9a45ec6b7 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -187,6 +187,14 @@ struct FixedPipelineState { | |||
| 187 | BitField<23, 1, u32> rasterize_enable; | 187 | BitField<23, 1, u32> rasterize_enable; |
| 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; | 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; |
| 189 | }; | 189 | }; |
| 190 | |||
| 191 | u32 alpha_test_ref; /// < Alpha test reference | ||
| 192 | union { | ||
| 193 | u32 alpha_raw; | ||
| 194 | BitField<0, 3, u32> alpha_test_func; | ||
| 195 | BitField<3, 1, u32> alpha_test_enabled; | ||
| 196 | }; | ||
| 197 | |||
| 190 | u32 point_size; | 198 | u32 point_size; |
| 191 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | 199 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; |
| 192 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | 200 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index dedc9c466..9ccf5d011 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -344,6 +344,14 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | |||
| 344 | } | 344 | } |
| 345 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; | 345 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; |
| 346 | 346 | ||
| 347 | // Alpha test | ||
| 348 | if (fixed_state.alpha_test_enabled == 1) { | ||
| 349 | specialization.alpha_test_enabled = true; | ||
| 350 | specialization.alpha_test_func = static_cast<u8>(fixed_state.alpha_test_func); | ||
| 351 | // memcpy from u32 to float TODO: C++20 std::bit_cast | ||
| 352 | std::memcpy(&specialization.alpha_test_ref, &fixed_state.alpha_test_ref, sizeof(float)); | ||
| 353 | } | ||
| 354 | |||
| 347 | SPIRVProgram program; | 355 | SPIRVProgram program; |
| 348 | std::vector<VkDescriptorSetLayoutBinding> bindings; | 356 | std::vector<VkDescriptorSetLayoutBinding> bindings; |
| 349 | 357 | ||
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index a20452b87..356d2ab7a 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -2075,6 +2075,55 @@ private: | |||
| 2075 | return {}; | 2075 | return {}; |
| 2076 | } | 2076 | } |
| 2077 | 2077 | ||
| 2078 | void AlphaTest(const Id& pointer) { | ||
| 2079 | const Id true_label = OpLabel(); | ||
| 2080 | const Id skip_label = OpLabel(); | ||
| 2081 | Id condition; | ||
| 2082 | switch (specialization.alpha_test_func) { | ||
| 2083 | case VK_COMPARE_OP_NEVER: | ||
| 2084 | condition = Constant(t_float, false); // Never true | ||
| 2085 | break; | ||
| 2086 | case VK_COMPARE_OP_LESS: | ||
| 2087 | condition = OpFOrdLessThan(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||
| 2088 | OpLoad(t_float, pointer)); | ||
| 2089 | break; | ||
| 2090 | case VK_COMPARE_OP_EQUAL: | ||
| 2091 | condition = OpFOrdEqual(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||
| 2092 | OpLoad(t_float, pointer)); | ||
| 2093 | break; | ||
| 2094 | case VK_COMPARE_OP_LESS_OR_EQUAL: | ||
| 2095 | condition = OpFOrdLessThanEqual( | ||
| 2096 | t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||
| 2097 | break; | ||
| 2098 | case VK_COMPARE_OP_GREATER: | ||
| 2099 | // Note: requires "Equal" to properly work for ssbu. perhaps a precision issue | ||
| 2100 | condition = OpFOrdGreaterThanEqual( | ||
| 2101 | t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||
| 2102 | break; | ||
| 2103 | case VK_COMPARE_OP_NOT_EQUAL: | ||
| 2104 | // Note: not accurate when tested against a unit test | ||
| 2105 | // TODO: confirm if used by games | ||
| 2106 | condition = OpFOrdNotEqual(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||
| 2107 | OpLoad(t_float, pointer)); | ||
| 2108 | break; | ||
| 2109 | case VK_COMPARE_OP_GREATER_OR_EQUAL: | ||
| 2110 | condition = OpFOrdGreaterThanEqual( | ||
| 2111 | t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||
| 2112 | break; | ||
| 2113 | case VK_COMPARE_OP_ALWAYS: | ||
| 2114 | condition = Constant(t_bool, true); // Always true | ||
| 2115 | break; | ||
| 2116 | default: | ||
| 2117 | LOG_WARNING(Render_Vulkan, "Unimplemented alpha test function"); | ||
| 2118 | condition = Constant(t_bool, true); // Always true | ||
| 2119 | break; | ||
| 2120 | } | ||
| 2121 | OpBranchConditional(condition, true_label, skip_label); | ||
| 2122 | AddLabel(true_label); | ||
| 2123 | OpKill(); | ||
| 2124 | AddLabel(skip_label); | ||
| 2125 | } | ||
| 2126 | |||
| 2078 | void PreExit() { | 2127 | void PreExit() { |
| 2079 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { | 2128 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { |
| 2080 | const u32 position_index = out_indices.position.value(); | 2129 | const u32 position_index = out_indices.position.value(); |
| @@ -2097,8 +2146,6 @@ private: | |||
| 2097 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, | 2146 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, |
| 2098 | "Sample mask write is unimplemented"); | 2147 | "Sample mask write is unimplemented"); |
| 2099 | 2148 | ||
| 2100 | // TODO(Rodrigo): Alpha testing | ||
| 2101 | |||
| 2102 | // Write the color outputs using the data in the shader registers, disabled | 2149 | // Write the color outputs using the data in the shader registers, disabled |
| 2103 | // rendertargets/components are skipped in the register assignment. | 2150 | // rendertargets/components are skipped in the register assignment. |
| 2104 | u32 current_reg = 0; | 2151 | u32 current_reg = 0; |
| @@ -2110,6 +2157,9 @@ private: | |||
| 2110 | } | 2157 | } |
| 2111 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); | 2158 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); |
| 2112 | OpStore(pointer, SafeGetRegister(current_reg)); | 2159 | OpStore(pointer, SafeGetRegister(current_reg)); |
| 2160 | if (specialization.alpha_test_enabled && component == 3) { | ||
| 2161 | AlphaTest(pointer); | ||
| 2162 | } | ||
| 2113 | ++current_reg; | 2163 | ++current_reg; |
| 2114 | } | 2164 | } |
| 2115 | } | 2165 | } |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 2b0e90396..ddbcb0b41 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -95,6 +95,9 @@ struct Specialization final { | |||
| 95 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; | 95 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; |
| 96 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; | 96 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; |
| 97 | bool ndc_minus_one_to_one{}; | 97 | bool ndc_minus_one_to_one{}; |
| 98 | bool alpha_test_enabled{}; | ||
| 99 | float alpha_test_ref{}; | ||
| 100 | u8 alpha_test_func{}; | ||
| 98 | }; | 101 | }; |
| 99 | // Old gcc versions don't consider this trivially copyable. | 102 | // Old gcc versions don't consider this trivially copyable. |
| 100 | // static_assert(std::is_trivially_copyable_v<Specialization>); | 103 | // static_assert(std::is_trivially_copyable_v<Specialization>); |