spirv: Implement alpha test
This commit is contained in:
		| @@ -37,6 +37,48 @@ Id DefaultVarying(EmitContext& ctx, u32 num_components, u32 element, Id zero, Id | |||||||
|     } |     } | ||||||
|     throw InvalidArgument("Bad element"); |     throw InvalidArgument("Bad element"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | Id ComparisonFunction(EmitContext& ctx, CompareFunction comparison, Id operand_1, Id operand_2) { | ||||||
|  |     switch (comparison) { | ||||||
|  |     case CompareFunction::Never: | ||||||
|  |         return ctx.false_value; | ||||||
|  |     case CompareFunction::Less: | ||||||
|  |         return ctx.OpFOrdLessThan(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::Equal: | ||||||
|  |         return ctx.OpFOrdEqual(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::LessThanEqual: | ||||||
|  |         return ctx.OpFOrdLessThanEqual(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::Greater: | ||||||
|  |         return ctx.OpFOrdGreaterThan(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::NotEqual: | ||||||
|  |         return ctx.OpFOrdNotEqual(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::GreaterThanEqual: | ||||||
|  |         return ctx.OpFOrdGreaterThanEqual(ctx.U1, operand_1, operand_2); | ||||||
|  |     case CompareFunction::Always: | ||||||
|  |         return ctx.true_value; | ||||||
|  |     } | ||||||
|  |     throw InvalidArgument("Comparison function {}", comparison); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AlphaTest(EmitContext& ctx) { | ||||||
|  |     const auto comparison{*ctx.profile.alpha_test_func}; | ||||||
|  |     if (comparison == CompareFunction::Always) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     const Id type{ctx.F32[1]}; | ||||||
|  |     const Id rt0_color{ctx.OpLoad(ctx.F32[4], ctx.frag_color[0])}; | ||||||
|  |     const Id alpha{ctx.OpCompositeExtract(type, rt0_color, 3u)}; | ||||||
|  |  | ||||||
|  |     const Id true_label{ctx.OpLabel()}; | ||||||
|  |     const Id discard_label{ctx.OpLabel()}; | ||||||
|  |     const Id alpha_reference{ctx.Constant(ctx.F32[1], ctx.profile.alpha_test_reference)}; | ||||||
|  |     const Id condition{ComparisonFunction(ctx, comparison, alpha, alpha_reference)}; | ||||||
|  |  | ||||||
|  |     ctx.OpBranchConditional(condition, true_label, discard_label); | ||||||
|  |     ctx.AddLabel(discard_label); | ||||||
|  |     ctx.OpKill(); | ||||||
|  |     ctx.AddLabel(true_label); | ||||||
|  | } | ||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
|  |  | ||||||
| void EmitPrologue(EmitContext& ctx) { | void EmitPrologue(EmitContext& ctx) { | ||||||
| @@ -68,6 +110,9 @@ void EmitEpilogue(EmitContext& ctx) { | |||||||
|     if (ctx.stage == Stage::VertexB && ctx.profile.convert_depth_mode) { |     if (ctx.stage == Stage::VertexB && ctx.profile.convert_depth_mode) { | ||||||
|         ConvertDepthMode(ctx); |         ConvertDepthMode(ctx); | ||||||
|     } |     } | ||||||
|  |     if (ctx.stage == Stage::Fragment) { | ||||||
|  |         AlphaTest(ctx); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { | void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <vector> |  | ||||||
| #include <optional> | #include <optional> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  |  | ||||||
| @@ -27,6 +27,17 @@ enum class InputTopology { | |||||||
|     TrianglesAdjacency, |     TrianglesAdjacency, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum class CompareFunction { | ||||||
|  |     Never, | ||||||
|  |     Less, | ||||||
|  |     Equal, | ||||||
|  |     LessThanEqual, | ||||||
|  |     Greater, | ||||||
|  |     NotEqual, | ||||||
|  |     GreaterThanEqual, | ||||||
|  |     Always, | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct TransformFeedbackVarying { | struct TransformFeedbackVarying { | ||||||
|     u32 buffer{}; |     u32 buffer{}; | ||||||
|     u32 stride{}; |     u32 stride{}; | ||||||
| @@ -66,6 +77,8 @@ struct Profile { | |||||||
|     InputTopology input_topology{}; |     InputTopology input_topology{}; | ||||||
|  |  | ||||||
|     std::optional<float> fixed_state_point_size; |     std::optional<float> fixed_state_point_size; | ||||||
|  |     std::optional<CompareFunction> alpha_test_func; | ||||||
|  |     float alpha_test_reference{}; | ||||||
|  |  | ||||||
|     std::vector<TransformFeedbackVarying> xfb_varyings; |     std::vector<TransformFeedbackVarying> xfb_varyings; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -492,6 +492,37 @@ private: | |||||||
|     u32 read_lowest{}; |     u32 read_lowest{}; | ||||||
|     u32 read_highest{}; |     u32 read_highest{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) { | ||||||
|  |     switch (comparison) { | ||||||
|  |     case Maxwell::ComparisonOp::Never: | ||||||
|  |     case Maxwell::ComparisonOp::NeverOld: | ||||||
|  |         return Shader::CompareFunction::Never; | ||||||
|  |     case Maxwell::ComparisonOp::Less: | ||||||
|  |     case Maxwell::ComparisonOp::LessOld: | ||||||
|  |         return Shader::CompareFunction::Less; | ||||||
|  |     case Maxwell::ComparisonOp::Equal: | ||||||
|  |     case Maxwell::ComparisonOp::EqualOld: | ||||||
|  |         return Shader::CompareFunction::Equal; | ||||||
|  |     case Maxwell::ComparisonOp::LessEqual: | ||||||
|  |     case Maxwell::ComparisonOp::LessEqualOld: | ||||||
|  |         return Shader::CompareFunction::LessThanEqual; | ||||||
|  |     case Maxwell::ComparisonOp::Greater: | ||||||
|  |     case Maxwell::ComparisonOp::GreaterOld: | ||||||
|  |         return Shader::CompareFunction::Greater; | ||||||
|  |     case Maxwell::ComparisonOp::NotEqual: | ||||||
|  |     case Maxwell::ComparisonOp::NotEqualOld: | ||||||
|  |         return Shader::CompareFunction::NotEqual; | ||||||
|  |     case Maxwell::ComparisonOp::GreaterEqual: | ||||||
|  |     case Maxwell::ComparisonOp::GreaterEqualOld: | ||||||
|  |         return Shader::CompareFunction::GreaterThanEqual; | ||||||
|  |     case Maxwell::ComparisonOp::Always: | ||||||
|  |     case Maxwell::ComparisonOp::AlwaysOld: | ||||||
|  |         return Shader::CompareFunction::Always; | ||||||
|  |     } | ||||||
|  |     UNIMPLEMENTED_MSG("Unimplemented comparison op={}", comparison); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
|  |  | ||||||
| void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||||
| @@ -1016,6 +1047,11 @@ Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key, | |||||||
|         } |         } | ||||||
|         profile.convert_depth_mode = gl_ndc; |         profile.convert_depth_mode = gl_ndc; | ||||||
|         break; |         break; | ||||||
|  |     case Shader::Stage::Fragment: | ||||||
|  |         profile.alpha_test_func = MaxwellToCompareFunction( | ||||||
|  |             key.state.UnpackComparisonOp(key.state.alpha_test_func.Value())); | ||||||
|  |         profile.alpha_test_reference = Common::BitCast<float>(key.state.alpha_test_ref); | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user