vulkan_renderer: Alpha Test Culling Implementation
Used by various textures in many titles, e.g. SSBU menu.
This commit is contained in:
		
							parent
							
								
									d1da7eb119
								
							
						
					
					
						commit
						9014861858
					
				| @ -60,6 +60,11 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | ||||
|     rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | ||||
|     topology.Assign(regs.draw.topology); | ||||
| 
 | ||||
|     alpha_raw = 0; | ||||
|     alpha_test_enabled.Assign(regs.alpha_test_enabled); | ||||
|     alpha_test_func.Assign(PackComparisonOp(regs.alpha_test_func)); | ||||
|     std::memcpy(&alpha_test_ref, ®s.alpha_test_ref, sizeof(u32)); // TODO: C++20 std::bit_cast
 | ||||
| 
 | ||||
|     std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
 | ||||
| 
 | ||||
|     for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | ||||
|  | ||||
| @ -187,6 +187,14 @@ struct FixedPipelineState { | ||||
|         BitField<23, 1, u32> rasterize_enable; | ||||
|         BitField<24, 4, Maxwell::PrimitiveTopology> topology; | ||||
|     }; | ||||
| 
 | ||||
|     u32 alpha_test_ref; /// < Alpha test reference
 | ||||
|     union { | ||||
|         u32 alpha_raw; | ||||
|         BitField<0, 3, u32> alpha_test_func; | ||||
|         BitField<3, 1, u32> alpha_test_enabled; | ||||
|     }; | ||||
| 
 | ||||
|     u32 point_size; | ||||
|     std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | ||||
|     std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | ||||
|  | ||||
| @ -344,6 +344,14 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | ||||
|     } | ||||
|     specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; | ||||
| 
 | ||||
|     // Alpha test
 | ||||
|     if (fixed_state.alpha_test_enabled == 1) { | ||||
|         specialization.alpha_test_enabled = true; | ||||
|         specialization.alpha_test_func = static_cast<u8>(fixed_state.alpha_test_func); | ||||
|         // memcpy from u32 to float TODO: C++20 std::bit_cast
 | ||||
|         std::memcpy(&specialization.alpha_test_ref, &fixed_state.alpha_test_ref, sizeof(float)); | ||||
|     } | ||||
| 
 | ||||
|     SPIRVProgram program; | ||||
|     std::vector<VkDescriptorSetLayoutBinding> bindings; | ||||
| 
 | ||||
|  | ||||
| @ -2075,6 +2075,55 @@ private: | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     void AlphaTest(const Id& pointer) { | ||||
|         const Id true_label = OpLabel(); | ||||
|         const Id skip_label = OpLabel(); | ||||
|         Id condition; | ||||
|         switch (specialization.alpha_test_func) { | ||||
|         case VK_COMPARE_OP_NEVER: | ||||
|             condition = Constant(t_float, false); // Never true
 | ||||
|             break; | ||||
|         case VK_COMPARE_OP_LESS: | ||||
|             condition = OpFOrdLessThan(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||||
|                                        OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_EQUAL: | ||||
|             condition = OpFOrdEqual(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||||
|                                     OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_LESS_OR_EQUAL: | ||||
|             condition = OpFOrdLessThanEqual( | ||||
|                 t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_GREATER: | ||||
|             // Note: requires "Equal" to properly work for ssbu. perhaps a precision issue
 | ||||
|             condition = OpFOrdGreaterThanEqual( | ||||
|                 t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_NOT_EQUAL: | ||||
|             // Note: not accurate when tested against a unit test
 | ||||
|             // TODO: confirm if used by games
 | ||||
|             condition = OpFOrdNotEqual(t_bool, Constant(t_float, specialization.alpha_test_ref), | ||||
|                                        OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_GREATER_OR_EQUAL: | ||||
|             condition = OpFOrdGreaterThanEqual( | ||||
|                 t_bool, Constant(t_float, specialization.alpha_test_ref), OpLoad(t_float, pointer)); | ||||
|             break; | ||||
|         case VK_COMPARE_OP_ALWAYS: | ||||
|             condition = Constant(t_bool, true); // Always true
 | ||||
|             break; | ||||
|         default: | ||||
|             LOG_WARNING(Render_Vulkan, "Unimplemented alpha test function"); | ||||
|             condition = Constant(t_bool, true); // Always true
 | ||||
|             break; | ||||
|         } | ||||
|         OpBranchConditional(condition, true_label, skip_label); | ||||
|         AddLabel(true_label); | ||||
|         OpKill(); | ||||
|         AddLabel(skip_label); | ||||
|     } | ||||
| 
 | ||||
|     void PreExit() { | ||||
|         if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { | ||||
|             const u32 position_index = out_indices.position.value(); | ||||
| @ -2097,8 +2146,6 @@ private: | ||||
|             UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, | ||||
|                                  "Sample mask write is unimplemented"); | ||||
| 
 | ||||
|             // TODO(Rodrigo): Alpha testing
 | ||||
| 
 | ||||
|             // Write the color outputs using the data in the shader registers, disabled
 | ||||
|             // rendertargets/components are skipped in the register assignment.
 | ||||
|             u32 current_reg = 0; | ||||
| @ -2110,6 +2157,9 @@ private: | ||||
|                     } | ||||
|                     const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); | ||||
|                     OpStore(pointer, SafeGetRegister(current_reg)); | ||||
|                     if (specialization.alpha_test_enabled && component == 3) { | ||||
|                         AlphaTest(pointer); | ||||
|                     } | ||||
|                     ++current_reg; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @ -95,6 +95,9 @@ struct Specialization final { | ||||
|     std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; | ||||
|     std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; | ||||
|     bool ndc_minus_one_to_one{}; | ||||
|     bool alpha_test_enabled{}; | ||||
|     float alpha_test_ref{}; | ||||
|     u8 alpha_test_func{}; | ||||
| }; | ||||
| // Old gcc versions don't consider this trivially copyable.
 | ||||
| // static_assert(std::is_trivially_copyable_v<Specialization>);
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ameerj
						ameerj