diff options
| author | 2021-04-15 22:46:11 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:27 -0400 | |
| commit | 183855e396cc6918d36fbf3e38ea426e934b4e3e (patch) | |
| tree | a665794753520c09a1d34d8a086352894ec1cb72 /src | |
| parent | shader: Mark atomic instructions as writes (diff) | |
| download | yuzu-183855e396cc6918d36fbf3e38ea426e934b4e3e.tar.gz yuzu-183855e396cc6918d36fbf3e38ea426e934b4e3e.tar.xz yuzu-183855e396cc6918d36fbf3e38ea426e934b4e3e.zip | |
shader: Implement tessellation shaders, polygon mode and invocation id
Diffstat (limited to 'src')
28 files changed, 605 insertions, 91 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index bbbfa98a3..7c11d15bf 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -41,6 +41,8 @@ add_library(shader_recompiler STATIC | |||
| 41 | frontend/ir/opcodes.cpp | 41 | frontend/ir/opcodes.cpp |
| 42 | frontend/ir/opcodes.h | 42 | frontend/ir/opcodes.h |
| 43 | frontend/ir/opcodes.inc | 43 | frontend/ir/opcodes.inc |
| 44 | frontend/ir/patch.cpp | ||
| 45 | frontend/ir/patch.h | ||
| 44 | frontend/ir/post_order.cpp | 46 | frontend/ir/post_order.cpp |
| 45 | frontend/ir/post_order.h | 47 | frontend/ir/post_order.h |
| 46 | frontend/ir/pred.h | 48 | frontend/ir/pred.h |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 032cf5e03..067f61613 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -125,19 +125,36 @@ u32 NumVertices(InputTopology input_topology) { | |||
| 125 | throw InvalidArgument("Invalid input topology {}", input_topology); | 125 | throw InvalidArgument("Invalid input topology {}", input_topology); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | Id DefineInput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { | 128 | Id DefineInput(EmitContext& ctx, Id type, bool per_invocation, |
| 129 | if (ctx.stage == Stage::Geometry) { | 129 | std::optional<spv::BuiltIn> builtin = std::nullopt) { |
| 130 | const u32 num_vertices{NumVertices(ctx.profile.input_topology)}; | 130 | switch (ctx.stage) { |
| 131 | type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], num_vertices)); | 131 | case Stage::TessellationControl: |
| 132 | case Stage::TessellationEval: | ||
| 133 | if (per_invocation) { | ||
| 134 | type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], 32u)); | ||
| 135 | } | ||
| 136 | break; | ||
| 137 | case Stage::Geometry: | ||
| 138 | if (per_invocation) { | ||
| 139 | const u32 num_vertices{NumVertices(ctx.profile.input_topology)}; | ||
| 140 | type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], num_vertices)); | ||
| 141 | } | ||
| 142 | break; | ||
| 143 | default: | ||
| 144 | break; | ||
| 132 | } | 145 | } |
| 133 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Input); | 146 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Input); |
| 134 | } | 147 | } |
| 135 | 148 | ||
| 136 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { | 149 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, |
| 150 | std::optional<spv::BuiltIn> builtin = std::nullopt) { | ||
| 151 | if (invocations && ctx.stage == Stage::TessellationControl) { | ||
| 152 | type = ctx.TypeArray(type, ctx.Constant(ctx.U32[1], *invocations)); | ||
| 153 | } | ||
| 137 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); | 154 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); |
| 138 | } | 155 | } |
| 139 | 156 | ||
| 140 | void DefineGenericOutput(EmitContext& ctx, size_t index) { | 157 | void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { |
| 141 | static constexpr std::string_view swizzle{"xyzw"}; | 158 | static constexpr std::string_view swizzle{"xyzw"}; |
| 142 | const size_t base_attr_index{static_cast<size_t>(IR::Attribute::Generic0X) + index * 4}; | 159 | const size_t base_attr_index{static_cast<size_t>(IR::Attribute::Generic0X) + index * 4}; |
| 143 | u32 element{0}; | 160 | u32 element{0}; |
| @@ -150,7 +167,7 @@ void DefineGenericOutput(EmitContext& ctx, size_t index) { | |||
| 150 | } | 167 | } |
| 151 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; | 168 | const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; |
| 152 | 169 | ||
| 153 | const Id id{DefineOutput(ctx, ctx.F32[num_components])}; | 170 | const Id id{DefineOutput(ctx, ctx.F32[num_components], invocations)}; |
| 154 | ctx.Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 171 | ctx.Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| 155 | if (element > 0) { | 172 | if (element > 0) { |
| 156 | ctx.Decorate(id, spv::Decoration::Component, element); | 173 | ctx.Decorate(id, spv::Decoration::Component, element); |
| @@ -161,10 +178,10 @@ void DefineGenericOutput(EmitContext& ctx, size_t index) { | |||
| 161 | ctx.Decorate(id, spv::Decoration::Offset, xfb_varying->offset); | 178 | ctx.Decorate(id, spv::Decoration::Offset, xfb_varying->offset); |
| 162 | } | 179 | } |
| 163 | if (num_components < 4 || element > 0) { | 180 | if (num_components < 4 || element > 0) { |
| 164 | ctx.Name(id, fmt::format("out_attr{}", index)); | ||
| 165 | } else { | ||
| 166 | const std::string_view subswizzle{swizzle.substr(element, num_components)}; | 181 | const std::string_view subswizzle{swizzle.substr(element, num_components)}; |
| 167 | ctx.Name(id, fmt::format("out_attr{}_{}", index, subswizzle)); | 182 | ctx.Name(id, fmt::format("out_attr{}_{}", index, subswizzle)); |
| 183 | } else { | ||
| 184 | ctx.Name(id, fmt::format("out_attr{}", index)); | ||
| 168 | } | 185 | } |
| 169 | const GenericElementInfo info{ | 186 | const GenericElementInfo info{ |
| 170 | .id = id, | 187 | .id = id, |
| @@ -383,7 +400,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
| 383 | AddCapability(spv::Capability::Shader); | 400 | AddCapability(spv::Capability::Shader); |
| 384 | DefineCommonTypes(program.info); | 401 | DefineCommonTypes(program.info); |
| 385 | DefineCommonConstants(); | 402 | DefineCommonConstants(); |
| 386 | DefineInterfaces(program.info); | 403 | DefineInterfaces(program); |
| 387 | DefineLocalMemory(program); | 404 | DefineLocalMemory(program); |
| 388 | DefineSharedMemory(program); | 405 | DefineSharedMemory(program); |
| 389 | DefineSharedMemoryFunctions(program); | 406 | DefineSharedMemoryFunctions(program); |
| @@ -472,9 +489,9 @@ void EmitContext::DefineCommonConstants() { | |||
| 472 | f32_zero_value = Constant(F32[1], 0.0f); | 489 | f32_zero_value = Constant(F32[1], 0.0f); |
| 473 | } | 490 | } |
| 474 | 491 | ||
| 475 | void EmitContext::DefineInterfaces(const Info& info) { | 492 | void EmitContext::DefineInterfaces(const IR::Program& program) { |
| 476 | DefineInputs(info); | 493 | DefineInputs(program.info); |
| 477 | DefineOutputs(info); | 494 | DefineOutputs(program); |
| 478 | } | 495 | } |
| 479 | 496 | ||
| 480 | void EmitContext::DefineLocalMemory(const IR::Program& program) { | 497 | void EmitContext::DefineLocalMemory(const IR::Program& program) { |
| @@ -972,26 +989,29 @@ void EmitContext::DefineLabels(IR::Program& program) { | |||
| 972 | 989 | ||
| 973 | void EmitContext::DefineInputs(const Info& info) { | 990 | void EmitContext::DefineInputs(const Info& info) { |
| 974 | if (info.uses_workgroup_id) { | 991 | if (info.uses_workgroup_id) { |
| 975 | workgroup_id = DefineInput(*this, U32[3], spv::BuiltIn::WorkgroupId); | 992 | workgroup_id = DefineInput(*this, U32[3], false, spv::BuiltIn::WorkgroupId); |
| 976 | } | 993 | } |
| 977 | if (info.uses_local_invocation_id) { | 994 | if (info.uses_local_invocation_id) { |
| 978 | local_invocation_id = DefineInput(*this, U32[3], spv::BuiltIn::LocalInvocationId); | 995 | local_invocation_id = DefineInput(*this, U32[3], false, spv::BuiltIn::LocalInvocationId); |
| 996 | } | ||
| 997 | if (info.uses_invocation_id) { | ||
| 998 | invocation_id = DefineInput(*this, U32[1], false, spv::BuiltIn::InvocationId); | ||
| 979 | } | 999 | } |
| 980 | if (info.uses_is_helper_invocation) { | 1000 | if (info.uses_is_helper_invocation) { |
| 981 | is_helper_invocation = DefineInput(*this, U1, spv::BuiltIn::HelperInvocation); | 1001 | is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation); |
| 982 | } | 1002 | } |
| 983 | if (info.uses_subgroup_mask) { | 1003 | if (info.uses_subgroup_mask) { |
| 984 | subgroup_mask_eq = DefineInput(*this, U32[4], spv::BuiltIn::SubgroupEqMaskKHR); | 1004 | subgroup_mask_eq = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupEqMaskKHR); |
| 985 | subgroup_mask_lt = DefineInput(*this, U32[4], spv::BuiltIn::SubgroupLtMaskKHR); | 1005 | subgroup_mask_lt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLtMaskKHR); |
| 986 | subgroup_mask_le = DefineInput(*this, U32[4], spv::BuiltIn::SubgroupLeMaskKHR); | 1006 | subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR); |
| 987 | subgroup_mask_gt = DefineInput(*this, U32[4], spv::BuiltIn::SubgroupGtMaskKHR); | 1007 | subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR); |
| 988 | subgroup_mask_ge = DefineInput(*this, U32[4], spv::BuiltIn::SubgroupGeMaskKHR); | 1008 | subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR); |
| 989 | } | 1009 | } |
| 990 | if (info.uses_subgroup_invocation_id || | 1010 | if (info.uses_subgroup_invocation_id || |
| 991 | (profile.warp_size_potentially_larger_than_guest && | 1011 | (profile.warp_size_potentially_larger_than_guest && |
| 992 | (info.uses_subgroup_vote || info.uses_subgroup_mask))) { | 1012 | (info.uses_subgroup_vote || info.uses_subgroup_mask))) { |
| 993 | subgroup_local_invocation_id = | 1013 | subgroup_local_invocation_id = |
| 994 | DefineInput(*this, U32[1], spv::BuiltIn::SubgroupLocalInvocationId); | 1014 | DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); |
| 995 | } | 1015 | } |
| 996 | if (info.uses_fswzadd) { | 1016 | if (info.uses_fswzadd) { |
| 997 | const Id f32_one{Constant(F32[1], 1.0f)}; | 1017 | const Id f32_one{Constant(F32[1], 1.0f)}; |
| @@ -1004,29 +1024,32 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1004 | if (info.loads_position) { | 1024 | if (info.loads_position) { |
| 1005 | const bool is_fragment{stage != Stage::Fragment}; | 1025 | const bool is_fragment{stage != Stage::Fragment}; |
| 1006 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; | 1026 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; |
| 1007 | input_position = DefineInput(*this, F32[4], built_in); | 1027 | input_position = DefineInput(*this, F32[4], true, built_in); |
| 1008 | } | 1028 | } |
| 1009 | if (info.loads_instance_id) { | 1029 | if (info.loads_instance_id) { |
| 1010 | if (profile.support_vertex_instance_id) { | 1030 | if (profile.support_vertex_instance_id) { |
| 1011 | instance_id = DefineInput(*this, U32[1], spv::BuiltIn::InstanceId); | 1031 | instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId); |
| 1012 | } else { | 1032 | } else { |
| 1013 | instance_index = DefineInput(*this, U32[1], spv::BuiltIn::InstanceIndex); | 1033 | instance_index = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceIndex); |
| 1014 | base_instance = DefineInput(*this, U32[1], spv::BuiltIn::BaseInstance); | 1034 | base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseInstance); |
| 1015 | } | 1035 | } |
| 1016 | } | 1036 | } |
| 1017 | if (info.loads_vertex_id) { | 1037 | if (info.loads_vertex_id) { |
| 1018 | if (profile.support_vertex_instance_id) { | 1038 | if (profile.support_vertex_instance_id) { |
| 1019 | vertex_id = DefineInput(*this, U32[1], spv::BuiltIn::VertexId); | 1039 | vertex_id = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexId); |
| 1020 | } else { | 1040 | } else { |
| 1021 | vertex_index = DefineInput(*this, U32[1], spv::BuiltIn::VertexIndex); | 1041 | vertex_index = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexIndex); |
| 1022 | base_vertex = DefineInput(*this, U32[1], spv::BuiltIn::BaseVertex); | 1042 | base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex); |
| 1023 | } | 1043 | } |
| 1024 | } | 1044 | } |
| 1025 | if (info.loads_front_face) { | 1045 | if (info.loads_front_face) { |
| 1026 | front_face = DefineInput(*this, U1, spv::BuiltIn::FrontFacing); | 1046 | front_face = DefineInput(*this, U1, true, spv::BuiltIn::FrontFacing); |
| 1027 | } | 1047 | } |
| 1028 | if (info.loads_point_coord) { | 1048 | if (info.loads_point_coord) { |
| 1029 | point_coord = DefineInput(*this, F32[2], spv::BuiltIn::PointCoord); | 1049 | point_coord = DefineInput(*this, F32[2], true, spv::BuiltIn::PointCoord); |
| 1050 | } | ||
| 1051 | if (info.loads_tess_coord) { | ||
| 1052 | tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord); | ||
| 1030 | } | 1053 | } |
| 1031 | for (size_t index = 0; index < info.input_generics.size(); ++index) { | 1054 | for (size_t index = 0; index < info.input_generics.size(); ++index) { |
| 1032 | const InputVarying generic{info.input_generics[index]}; | 1055 | const InputVarying generic{info.input_generics[index]}; |
| @@ -1038,7 +1061,7 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1038 | continue; | 1061 | continue; |
| 1039 | } | 1062 | } |
| 1040 | const Id type{GetAttributeType(*this, input_type)}; | 1063 | const Id type{GetAttributeType(*this, input_type)}; |
| 1041 | const Id id{DefineInput(*this, type)}; | 1064 | const Id id{DefineInput(*this, type, true)}; |
| 1042 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 1065 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| 1043 | Name(id, fmt::format("in_attr{}", index)); | 1066 | Name(id, fmt::format("in_attr{}", index)); |
| 1044 | input_generics[index] = id; | 1067 | input_generics[index] = id; |
| @@ -1059,58 +1082,98 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1059 | break; | 1082 | break; |
| 1060 | } | 1083 | } |
| 1061 | } | 1084 | } |
| 1085 | if (stage == Stage::TessellationEval) { | ||
| 1086 | for (size_t index = 0; index < info.uses_patches.size(); ++index) { | ||
| 1087 | if (!info.uses_patches[index]) { | ||
| 1088 | continue; | ||
| 1089 | } | ||
| 1090 | const Id id{DefineInput(*this, F32[4], false)}; | ||
| 1091 | Decorate(id, spv::Decoration::Patch); | ||
| 1092 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | ||
| 1093 | patches[index] = id; | ||
| 1094 | } | ||
| 1095 | } | ||
| 1062 | } | 1096 | } |
| 1063 | 1097 | ||
| 1064 | void EmitContext::DefineOutputs(const Info& info) { | 1098 | void EmitContext::DefineOutputs(const IR::Program& program) { |
| 1099 | const Info& info{program.info}; | ||
| 1100 | const std::optional<u32> invocations{program.invocations}; | ||
| 1065 | if (info.stores_position || stage == Stage::VertexB) { | 1101 | if (info.stores_position || stage == Stage::VertexB) { |
| 1066 | output_position = DefineOutput(*this, F32[4], spv::BuiltIn::Position); | 1102 | output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position); |
| 1067 | } | 1103 | } |
| 1068 | if (info.stores_point_size || profile.fixed_state_point_size) { | 1104 | if (info.stores_point_size || profile.fixed_state_point_size) { |
| 1069 | if (stage == Stage::Fragment) { | 1105 | if (stage == Stage::Fragment) { |
| 1070 | throw NotImplementedException("Storing PointSize in fragment stage"); | 1106 | throw NotImplementedException("Storing PointSize in fragment stage"); |
| 1071 | } | 1107 | } |
| 1072 | output_point_size = DefineOutput(*this, F32[1], spv::BuiltIn::PointSize); | 1108 | output_point_size = DefineOutput(*this, F32[1], invocations, spv::BuiltIn::PointSize); |
| 1073 | } | 1109 | } |
| 1074 | if (info.stores_clip_distance) { | 1110 | if (info.stores_clip_distance) { |
| 1075 | if (stage == Stage::Fragment) { | 1111 | if (stage == Stage::Fragment) { |
| 1076 | throw NotImplementedException("Storing ClipDistance in fragment stage"); | 1112 | throw NotImplementedException("Storing ClipDistance in fragment stage"); |
| 1077 | } | 1113 | } |
| 1078 | const Id type{TypeArray(F32[1], Constant(U32[1], 8U))}; | 1114 | const Id type{TypeArray(F32[1], Constant(U32[1], 8U))}; |
| 1079 | clip_distances = DefineOutput(*this, type, spv::BuiltIn::ClipDistance); | 1115 | clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); |
| 1080 | } | 1116 | } |
| 1081 | if (info.stores_layer && | 1117 | if (info.stores_layer && |
| 1082 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { | 1118 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { |
| 1083 | if (stage == Stage::Fragment) { | 1119 | if (stage == Stage::Fragment) { |
| 1084 | throw NotImplementedException("Storing Layer in fragment stage"); | 1120 | throw NotImplementedException("Storing Layer in fragment stage"); |
| 1085 | } | 1121 | } |
| 1086 | layer = DefineOutput(*this, U32[1], spv::BuiltIn::Layer); | 1122 | layer = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::Layer); |
| 1087 | } | 1123 | } |
| 1088 | if (info.stores_viewport_index && | 1124 | if (info.stores_viewport_index && |
| 1089 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { | 1125 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { |
| 1090 | if (stage == Stage::Fragment) { | 1126 | if (stage == Stage::Fragment) { |
| 1091 | throw NotImplementedException("Storing ViewportIndex in fragment stage"); | 1127 | throw NotImplementedException("Storing ViewportIndex in fragment stage"); |
| 1092 | } | 1128 | } |
| 1093 | viewport_index = DefineOutput(*this, U32[1], spv::BuiltIn::ViewportIndex); | 1129 | viewport_index = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::ViewportIndex); |
| 1094 | } | 1130 | } |
| 1095 | for (size_t index = 0; index < info.stores_generics.size(); ++index) { | 1131 | for (size_t index = 0; index < info.stores_generics.size(); ++index) { |
| 1096 | if (info.stores_generics[index]) { | 1132 | if (info.stores_generics[index]) { |
| 1097 | DefineGenericOutput(*this, index); | 1133 | DefineGenericOutput(*this, index, invocations); |
| 1098 | } | 1134 | } |
| 1099 | } | 1135 | } |
| 1100 | if (stage == Stage::Fragment) { | 1136 | switch (stage) { |
| 1137 | case Stage::TessellationControl: | ||
| 1138 | if (info.stores_tess_level_outer) { | ||
| 1139 | const Id type{TypeArray(F32[1], Constant(U32[1], 4))}; | ||
| 1140 | output_tess_level_outer = | ||
| 1141 | DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelOuter); | ||
| 1142 | Decorate(output_tess_level_outer, spv::Decoration::Patch); | ||
| 1143 | } | ||
| 1144 | if (info.stores_tess_level_inner) { | ||
| 1145 | const Id type{TypeArray(F32[1], Constant(U32[1], 2))}; | ||
| 1146 | output_tess_level_inner = | ||
| 1147 | DefineOutput(*this, type, std::nullopt, spv::BuiltIn::TessLevelInner); | ||
| 1148 | Decorate(output_tess_level_inner, spv::Decoration::Patch); | ||
| 1149 | } | ||
| 1150 | for (size_t index = 0; index < info.uses_patches.size(); ++index) { | ||
| 1151 | if (!info.uses_patches[index]) { | ||
| 1152 | continue; | ||
| 1153 | } | ||
| 1154 | const Id id{DefineOutput(*this, F32[4], std::nullopt)}; | ||
| 1155 | Decorate(id, spv::Decoration::Patch); | ||
| 1156 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | ||
| 1157 | patches[index] = id; | ||
| 1158 | } | ||
| 1159 | break; | ||
| 1160 | case Stage::Fragment: | ||
| 1101 | for (u32 index = 0; index < 8; ++index) { | 1161 | for (u32 index = 0; index < 8; ++index) { |
| 1102 | if (!info.stores_frag_color[index]) { | 1162 | if (!info.stores_frag_color[index]) { |
| 1103 | continue; | 1163 | continue; |
| 1104 | } | 1164 | } |
| 1105 | frag_color[index] = DefineOutput(*this, F32[4]); | 1165 | frag_color[index] = DefineOutput(*this, F32[4], std::nullopt); |
| 1106 | Decorate(frag_color[index], spv::Decoration::Location, index); | 1166 | Decorate(frag_color[index], spv::Decoration::Location, index); |
| 1107 | Name(frag_color[index], fmt::format("frag_color{}", index)); | 1167 | Name(frag_color[index], fmt::format("frag_color{}", index)); |
| 1108 | } | 1168 | } |
| 1109 | if (info.stores_frag_depth) { | 1169 | if (info.stores_frag_depth) { |
| 1110 | frag_depth = DefineOutput(*this, F32[1]); | 1170 | frag_depth = DefineOutput(*this, F32[1], std::nullopt); |
| 1111 | Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth); | 1171 | Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth); |
| 1112 | Name(frag_depth, "frag_depth"); | 1172 | Name(frag_depth, "frag_depth"); |
| 1113 | } | 1173 | } |
| 1174 | break; | ||
| 1175 | default: | ||
| 1176 | break; | ||
| 1114 | } | 1177 | } |
| 1115 | } | 1178 | } |
| 1116 | 1179 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 0da14d5f8..ba0a253b3 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -147,6 +147,7 @@ public: | |||
| 147 | 147 | ||
| 148 | Id workgroup_id{}; | 148 | Id workgroup_id{}; |
| 149 | Id local_invocation_id{}; | 149 | Id local_invocation_id{}; |
| 150 | Id invocation_id{}; | ||
| 150 | Id is_helper_invocation{}; | 151 | Id is_helper_invocation{}; |
| 151 | Id subgroup_local_invocation_id{}; | 152 | Id subgroup_local_invocation_id{}; |
| 152 | Id subgroup_mask_eq{}; | 153 | Id subgroup_mask_eq{}; |
| @@ -162,6 +163,7 @@ public: | |||
| 162 | Id base_vertex{}; | 163 | Id base_vertex{}; |
| 163 | Id front_face{}; | 164 | Id front_face{}; |
| 164 | Id point_coord{}; | 165 | Id point_coord{}; |
| 166 | Id tess_coord{}; | ||
| 165 | Id clip_distances{}; | 167 | Id clip_distances{}; |
| 166 | Id layer{}; | 168 | Id layer{}; |
| 167 | Id viewport_index{}; | 169 | Id viewport_index{}; |
| @@ -204,6 +206,10 @@ public: | |||
| 204 | Id output_position{}; | 206 | Id output_position{}; |
| 205 | std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; | 207 | std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; |
| 206 | 208 | ||
| 209 | Id output_tess_level_outer{}; | ||
| 210 | Id output_tess_level_inner{}; | ||
| 211 | std::array<Id, 30> patches{}; | ||
| 212 | |||
| 207 | std::array<Id, 8> frag_color{}; | 213 | std::array<Id, 8> frag_color{}; |
| 208 | Id frag_depth{}; | 214 | Id frag_depth{}; |
| 209 | 215 | ||
| @@ -212,7 +218,7 @@ public: | |||
| 212 | private: | 218 | private: |
| 213 | void DefineCommonTypes(const Info& info); | 219 | void DefineCommonTypes(const Info& info); |
| 214 | void DefineCommonConstants(); | 220 | void DefineCommonConstants(); |
| 215 | void DefineInterfaces(const Info& info); | 221 | void DefineInterfaces(const IR::Program& program); |
| 216 | void DefineLocalMemory(const IR::Program& program); | 222 | void DefineLocalMemory(const IR::Program& program); |
| 217 | void DefineSharedMemory(const IR::Program& program); | 223 | void DefineSharedMemory(const IR::Program& program); |
| 218 | void DefineSharedMemoryFunctions(const IR::Program& program); | 224 | void DefineSharedMemoryFunctions(const IR::Program& program); |
| @@ -226,7 +232,7 @@ private: | |||
| 226 | void DefineLabels(IR::Program& program); | 232 | void DefineLabels(IR::Program& program); |
| 227 | 233 | ||
| 228 | void DefineInputs(const Info& info); | 234 | void DefineInputs(const Info& info); |
| 229 | void DefineOutputs(const Info& info); | 235 | void DefineOutputs(const IR::Program& program); |
| 230 | }; | 236 | }; |
| 231 | 237 | ||
| 232 | } // namespace Shader::Backend::SPIRV | 238 | } // namespace Shader::Backend::SPIRV |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 3bf4c6a9e..105602ccf 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -45,6 +45,8 @@ ArgType Arg(EmitContext& ctx, const IR::Value& arg) { | |||
| 45 | return arg.Label(); | 45 | return arg.Label(); |
| 46 | } else if constexpr (std::is_same_v<ArgType, IR::Attribute>) { | 46 | } else if constexpr (std::is_same_v<ArgType, IR::Attribute>) { |
| 47 | return arg.Attribute(); | 47 | return arg.Attribute(); |
| 48 | } else if constexpr (std::is_same_v<ArgType, IR::Patch>) { | ||
| 49 | return arg.Patch(); | ||
| 48 | } else if constexpr (std::is_same_v<ArgType, IR::Reg>) { | 50 | } else if constexpr (std::is_same_v<ArgType, IR::Reg>) { |
| 49 | return arg.Reg(); | 51 | return arg.Reg(); |
| 50 | } | 52 | } |
| @@ -120,6 +122,30 @@ Id DefineMain(EmitContext& ctx, IR::Program& program) { | |||
| 120 | return main; | 122 | return main; |
| 121 | } | 123 | } |
| 122 | 124 | ||
| 125 | spv::ExecutionMode ExecutionMode(TessPrimitive primitive) { | ||
| 126 | switch (primitive) { | ||
| 127 | case TessPrimitive::Isolines: | ||
| 128 | return spv::ExecutionMode::Isolines; | ||
| 129 | case TessPrimitive::Triangles: | ||
| 130 | return spv::ExecutionMode::Triangles; | ||
| 131 | case TessPrimitive::Quads: | ||
| 132 | return spv::ExecutionMode::Quads; | ||
| 133 | } | ||
| 134 | throw InvalidArgument("Tessellation primitive {}", primitive); | ||
| 135 | } | ||
| 136 | |||
| 137 | spv::ExecutionMode ExecutionMode(TessSpacing spacing) { | ||
| 138 | switch (spacing) { | ||
| 139 | case TessSpacing::Equal: | ||
| 140 | return spv::ExecutionMode::SpacingEqual; | ||
| 141 | case TessSpacing::FractionalOdd: | ||
| 142 | return spv::ExecutionMode::SpacingFractionalOdd; | ||
| 143 | case TessSpacing::FractionalEven: | ||
| 144 | return spv::ExecutionMode::SpacingFractionalEven; | ||
| 145 | } | ||
| 146 | throw InvalidArgument("Tessellation spacing {}", spacing); | ||
| 147 | } | ||
| 148 | |||
| 123 | void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { | 149 | void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { |
| 124 | const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); | 150 | const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); |
| 125 | spv::ExecutionModel execution_model{}; | 151 | spv::ExecutionModel execution_model{}; |
| @@ -134,6 +160,19 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { | |||
| 134 | case Stage::VertexB: | 160 | case Stage::VertexB: |
| 135 | execution_model = spv::ExecutionModel::Vertex; | 161 | execution_model = spv::ExecutionModel::Vertex; |
| 136 | break; | 162 | break; |
| 163 | case Stage::TessellationControl: | ||
| 164 | execution_model = spv::ExecutionModel::TessellationControl; | ||
| 165 | ctx.AddCapability(spv::Capability::Tessellation); | ||
| 166 | ctx.AddExecutionMode(main, spv::ExecutionMode::OutputVertices, program.invocations); | ||
| 167 | break; | ||
| 168 | case Stage::TessellationEval: | ||
| 169 | execution_model = spv::ExecutionModel::TessellationEvaluation; | ||
| 170 | ctx.AddCapability(spv::Capability::Tessellation); | ||
| 171 | ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_primitive)); | ||
| 172 | ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_spacing)); | ||
| 173 | ctx.AddExecutionMode(main, ctx.profile.tess_clockwise ? spv::ExecutionMode::VertexOrderCw | ||
| 174 | : spv::ExecutionMode::VertexOrderCcw); | ||
| 175 | break; | ||
| 137 | case Stage::Geometry: | 176 | case Stage::Geometry: |
| 138 | execution_model = spv::ExecutionModel::Geometry; | 177 | execution_model = spv::ExecutionModel::Geometry; |
| 139 | ctx.AddCapability(spv::Capability::Geometry); | 178 | ctx.AddCapability(spv::Capability::Geometry); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 55b2edba0..8caf30f1b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -55,6 +55,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex); | |||
| 55 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex); | 55 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex); |
| 56 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex); | 56 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex); |
| 57 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex); | 57 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex); |
| 58 | Id EmitGetPatch(EmitContext& ctx, IR::Patch patch); | ||
| 59 | void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value); | ||
| 58 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); | 60 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); |
| 59 | void EmitSetFragDepth(EmitContext& ctx, Id value); | 61 | void EmitSetFragDepth(EmitContext& ctx, Id value); |
| 60 | void EmitGetZFlag(EmitContext& ctx); | 62 | void EmitGetZFlag(EmitContext& ctx); |
| @@ -67,6 +69,7 @@ void EmitSetCFlag(EmitContext& ctx); | |||
| 67 | void EmitSetOFlag(EmitContext& ctx); | 69 | void EmitSetOFlag(EmitContext& ctx); |
| 68 | Id EmitWorkgroupId(EmitContext& ctx); | 70 | Id EmitWorkgroupId(EmitContext& ctx); |
| 69 | Id EmitLocalInvocationId(EmitContext& ctx); | 71 | Id EmitLocalInvocationId(EmitContext& ctx); |
| 72 | Id EmitInvocationId(EmitContext& ctx); | ||
| 70 | Id EmitIsHelperInvocation(EmitContext& ctx); | 73 | Id EmitIsHelperInvocation(EmitContext& ctx); |
| 71 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset); | 74 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset); |
| 72 | void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value); | 75 | void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 59c56c5ba..4a1aeece5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -32,13 +32,26 @@ std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | |||
| 32 | 32 | ||
| 33 | template <typename... Args> | 33 | template <typename... Args> |
| 34 | Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) { | 34 | Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) { |
| 35 | if (ctx.stage == Stage::Geometry) { | 35 | switch (ctx.stage) { |
| 36 | case Stage::TessellationControl: | ||
| 37 | case Stage::TessellationEval: | ||
| 38 | case Stage::Geometry: | ||
| 36 | return ctx.OpAccessChain(pointer_type, base, vertex, std::forward<Args>(args)...); | 39 | return ctx.OpAccessChain(pointer_type, base, vertex, std::forward<Args>(args)...); |
| 37 | } else { | 40 | default: |
| 38 | return ctx.OpAccessChain(pointer_type, base, std::forward<Args>(args)...); | 41 | return ctx.OpAccessChain(pointer_type, base, std::forward<Args>(args)...); |
| 39 | } | 42 | } |
| 40 | } | 43 | } |
| 41 | 44 | ||
| 45 | template <typename... Args> | ||
| 46 | Id OutputAccessChain(EmitContext& ctx, Id result_type, Id base, Args&&... args) { | ||
| 47 | if (ctx.stage == Stage::TessellationControl) { | ||
| 48 | const Id invocation_id{ctx.OpLoad(ctx.U32[1], ctx.invocation_id)}; | ||
| 49 | return ctx.OpAccessChain(result_type, base, invocation_id, std::forward<Args>(args)...); | ||
| 50 | } else { | ||
| 51 | return ctx.OpAccessChain(result_type, base, std::forward<Args>(args)...); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 42 | std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | 55 | std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { |
| 43 | if (IR::IsGeneric(attr)) { | 56 | if (IR::IsGeneric(attr)) { |
| 44 | const u32 index{IR::GenericAttributeIndex(attr)}; | 57 | const u32 index{IR::GenericAttributeIndex(attr)}; |
| @@ -49,7 +62,7 @@ std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 49 | } else { | 62 | } else { |
| 50 | const u32 index_element{element - info.first_element}; | 63 | const u32 index_element{element - info.first_element}; |
| 51 | const Id index_id{ctx.Constant(ctx.U32[1], index_element)}; | 64 | const Id index_id{ctx.Constant(ctx.U32[1], index_element)}; |
| 52 | return ctx.OpAccessChain(ctx.output_f32, info.id, index_id); | 65 | return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id); |
| 53 | } | 66 | } |
| 54 | } | 67 | } |
| 55 | switch (attr) { | 68 | switch (attr) { |
| @@ -61,7 +74,7 @@ std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 61 | case IR::Attribute::PositionW: { | 74 | case IR::Attribute::PositionW: { |
| 62 | const u32 element{static_cast<u32>(attr) % 4}; | 75 | const u32 element{static_cast<u32>(attr) % 4}; |
| 63 | const Id element_id{ctx.Constant(ctx.U32[1], element)}; | 76 | const Id element_id{ctx.Constant(ctx.U32[1], element)}; |
| 64 | return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, element_id); | 77 | return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id); |
| 65 | } | 78 | } |
| 66 | case IR::Attribute::ClipDistance0: | 79 | case IR::Attribute::ClipDistance0: |
| 67 | case IR::Attribute::ClipDistance1: | 80 | case IR::Attribute::ClipDistance1: |
| @@ -74,7 +87,7 @@ std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 74 | const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; | 87 | const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; |
| 75 | const u32 index{static_cast<u32>(attr) - base}; | 88 | const u32 index{static_cast<u32>(attr) - base}; |
| 76 | const Id clip_num{ctx.Constant(ctx.U32[1], index)}; | 89 | const Id clip_num{ctx.Constant(ctx.U32[1], index)}; |
| 77 | return ctx.OpAccessChain(ctx.output_f32, ctx.clip_distances, clip_num); | 90 | return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num); |
| 78 | } | 91 | } |
| 79 | case IR::Attribute::Layer: | 92 | case IR::Attribute::Layer: |
| 80 | return ctx.profile.support_viewport_index_layer_non_geometry || | 93 | return ctx.profile.support_viewport_index_layer_non_geometry || |
| @@ -222,11 +235,18 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 222 | ctx.Constant(ctx.U32[1], std::numeric_limits<u32>::max()), | 235 | ctx.Constant(ctx.U32[1], std::numeric_limits<u32>::max()), |
| 223 | ctx.u32_zero_value); | 236 | ctx.u32_zero_value); |
| 224 | case IR::Attribute::PointSpriteS: | 237 | case IR::Attribute::PointSpriteS: |
| 225 | return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.point_coord, | 238 | return ctx.OpLoad(ctx.F32[1], |
| 226 | ctx.u32_zero_value)); | 239 | ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.u32_zero_value)); |
| 227 | case IR::Attribute::PointSpriteT: | 240 | case IR::Attribute::PointSpriteT: |
| 228 | return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.point_coord, | 241 | return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, |
| 229 | ctx.Constant(ctx.U32[1], 1U))); | 242 | ctx.Constant(ctx.U32[1], 1U))); |
| 243 | case IR::Attribute::TessellationEvaluationPointU: | ||
| 244 | return ctx.OpLoad(ctx.F32[1], | ||
| 245 | ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.u32_zero_value)); | ||
| 246 | case IR::Attribute::TessellationEvaluationPointV: | ||
| 247 | return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, | ||
| 248 | ctx.Constant(ctx.U32[1], 1U))); | ||
| 249 | |||
| 230 | default: | 250 | default: |
| 231 | throw NotImplementedException("Read attribute {}", attr); | 251 | throw NotImplementedException("Read attribute {}", attr); |
| 232 | } | 252 | } |
| @@ -240,9 +260,12 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_un | |||
| 240 | } | 260 | } |
| 241 | 261 | ||
| 242 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex) { | 262 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex) { |
| 243 | if (ctx.stage == Stage::Geometry) { | 263 | switch (ctx.stage) { |
| 264 | case Stage::TessellationControl: | ||
| 265 | case Stage::TessellationEval: | ||
| 266 | case Stage::Geometry: | ||
| 244 | return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset, vertex); | 267 | return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset, vertex); |
| 245 | } else { | 268 | default: |
| 246 | return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset); | 269 | return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset); |
| 247 | } | 270 | } |
| 248 | } | 271 | } |
| @@ -251,6 +274,45 @@ void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, [[maybe_unus | |||
| 251 | ctx.OpFunctionCall(ctx.void_id, ctx.indexed_store_func, offset, value); | 274 | ctx.OpFunctionCall(ctx.void_id, ctx.indexed_store_func, offset, value); |
| 252 | } | 275 | } |
| 253 | 276 | ||
| 277 | Id EmitGetPatch(EmitContext& ctx, IR::Patch patch) { | ||
| 278 | if (!IR::IsGeneric(patch)) { | ||
| 279 | throw NotImplementedException("Non-generic patch load"); | ||
| 280 | } | ||
| 281 | const u32 index{IR::GenericPatchIndex(patch)}; | ||
| 282 | const Id element{ctx.Constant(ctx.U32[1], IR::GenericPatchElement(patch))}; | ||
| 283 | const Id pointer{ctx.OpAccessChain(ctx.input_f32, ctx.patches.at(index), element)}; | ||
| 284 | return ctx.OpLoad(ctx.F32[1], pointer); | ||
| 285 | } | ||
| 286 | |||
| 287 | void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) { | ||
| 288 | const Id pointer{[&] { | ||
| 289 | if (IR::IsGeneric(patch)) { | ||
| 290 | const u32 index{IR::GenericPatchIndex(patch)}; | ||
| 291 | const Id element{ctx.Constant(ctx.U32[1], IR::GenericPatchElement(patch))}; | ||
| 292 | return ctx.OpAccessChain(ctx.output_f32, ctx.patches.at(index), element); | ||
| 293 | } | ||
| 294 | switch (patch) { | ||
| 295 | case IR::Patch::TessellationLodLeft: | ||
| 296 | case IR::Patch::TessellationLodRight: | ||
| 297 | case IR::Patch::TessellationLodTop: | ||
| 298 | case IR::Patch::TessellationLodBottom: { | ||
| 299 | const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)}; | ||
| 300 | const Id index_id{ctx.Constant(ctx.U32[1], index)}; | ||
| 301 | return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_outer, index_id); | ||
| 302 | } | ||
| 303 | case IR::Patch::TessellationLodInteriorU: | ||
| 304 | return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner, | ||
| 305 | ctx.u32_zero_value); | ||
| 306 | case IR::Patch::TessellationLodInteriorV: | ||
| 307 | return ctx.OpAccessChain(ctx.output_f32, ctx.output_tess_level_inner, | ||
| 308 | ctx.Constant(ctx.U32[1], 1u)); | ||
| 309 | default: | ||
| 310 | throw NotImplementedException("Patch {}", patch); | ||
| 311 | } | ||
| 312 | }()}; | ||
| 313 | ctx.OpStore(pointer, value); | ||
| 314 | } | ||
| 315 | |||
| 254 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { | 316 | void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { |
| 255 | const Id component_id{ctx.Constant(ctx.U32[1], component)}; | 317 | const Id component_id{ctx.Constant(ctx.U32[1], component)}; |
| 256 | const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)}; | 318 | const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)}; |
| @@ -301,6 +363,10 @@ Id EmitLocalInvocationId(EmitContext& ctx) { | |||
| 301 | return ctx.OpLoad(ctx.U32[3], ctx.local_invocation_id); | 363 | return ctx.OpLoad(ctx.U32[3], ctx.local_invocation_id); |
| 302 | } | 364 | } |
| 303 | 365 | ||
| 366 | Id EmitInvocationId(EmitContext& ctx) { | ||
| 367 | return ctx.OpLoad(ctx.U32[1], ctx.invocation_id); | ||
| 368 | } | ||
| 369 | |||
| 304 | Id EmitIsHelperInvocation(EmitContext& ctx) { | 370 | Id EmitIsHelperInvocation(EmitContext& ctx) { |
| 305 | return ctx.OpLoad(ctx.U1, ctx.is_helper_invocation); | 371 | return ctx.OpLoad(ctx.U1, ctx.is_helper_invocation); |
| 306 | } | 372 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index d66eb17a6..b821d9f47 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -331,6 +331,14 @@ void IREmitter::SetAttributeIndexed(const U32& phys_address, const F32& value, c | |||
| 331 | Inst(Opcode::SetAttributeIndexed, phys_address, value, vertex); | 331 | Inst(Opcode::SetAttributeIndexed, phys_address, value, vertex); |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | F32 IREmitter::GetPatch(Patch patch) { | ||
| 335 | return Inst<F32>(Opcode::GetPatch, patch); | ||
| 336 | } | ||
| 337 | |||
| 338 | void IREmitter::SetPatch(Patch patch, const F32& value) { | ||
| 339 | Inst(Opcode::SetPatch, patch, value); | ||
| 340 | } | ||
| 341 | |||
| 334 | void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) { | 342 | void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) { |
| 335 | Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value); | 343 | Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value); |
| 336 | } | 344 | } |
| @@ -363,6 +371,10 @@ U32 IREmitter::LocalInvocationIdZ() { | |||
| 363 | return U32{CompositeExtract(Inst(Opcode::LocalInvocationId), 2)}; | 371 | return U32{CompositeExtract(Inst(Opcode::LocalInvocationId), 2)}; |
| 364 | } | 372 | } |
| 365 | 373 | ||
| 374 | U32 IREmitter::InvocationId() { | ||
| 375 | return Inst<U32>(Opcode::InvocationId); | ||
| 376 | } | ||
| 377 | |||
| 366 | U1 IREmitter::IsHelperInvocation() { | 378 | U1 IREmitter::IsHelperInvocation() { |
| 367 | return Inst<U1>(Opcode::IsHelperInvocation); | 379 | return Inst<U1>(Opcode::IsHelperInvocation); |
| 368 | } | 380 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index e70359eb1..7f8f1ad42 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -84,6 +84,9 @@ public: | |||
| 84 | [[nodiscard]] F32 GetAttributeIndexed(const U32& phys_address, const U32& vertex); | 84 | [[nodiscard]] F32 GetAttributeIndexed(const U32& phys_address, const U32& vertex); |
| 85 | void SetAttributeIndexed(const U32& phys_address, const F32& value, const U32& vertex); | 85 | void SetAttributeIndexed(const U32& phys_address, const F32& value, const U32& vertex); |
| 86 | 86 | ||
| 87 | [[nodiscard]] F32 GetPatch(Patch patch); | ||
| 88 | void SetPatch(Patch patch, const F32& value); | ||
| 89 | |||
| 87 | void SetFragColor(u32 index, u32 component, const F32& value); | 90 | void SetFragColor(u32 index, u32 component, const F32& value); |
| 88 | void SetFragDepth(const F32& value); | 91 | void SetFragDepth(const F32& value); |
| 89 | 92 | ||
| @@ -95,6 +98,7 @@ public: | |||
| 95 | [[nodiscard]] U32 LocalInvocationIdY(); | 98 | [[nodiscard]] U32 LocalInvocationIdY(); |
| 96 | [[nodiscard]] U32 LocalInvocationIdZ(); | 99 | [[nodiscard]] U32 LocalInvocationIdZ(); |
| 97 | 100 | ||
| 101 | [[nodiscard]] U32 InvocationId(); | ||
| 98 | [[nodiscard]] U1 IsHelperInvocation(); | 102 | [[nodiscard]] U1 IsHelperInvocation(); |
| 99 | 103 | ||
| 100 | [[nodiscard]] U32 LaneId(); | 104 | [[nodiscard]] U32 LaneId(); |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 204c55fa8..b2d7573d9 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -73,6 +73,7 @@ bool Inst::MayHaveSideEffects() const noexcept { | |||
| 73 | case Opcode::EndPrimitive: | 73 | case Opcode::EndPrimitive: |
| 74 | case Opcode::SetAttribute: | 74 | case Opcode::SetAttribute: |
| 75 | case Opcode::SetAttributeIndexed: | 75 | case Opcode::SetAttributeIndexed: |
| 76 | case Opcode::SetPatch: | ||
| 76 | case Opcode::SetFragColor: | 77 | case Opcode::SetFragColor: |
| 77 | case Opcode::SetFragDepth: | 78 | case Opcode::SetFragDepth: |
| 78 | case Opcode::WriteGlobalU8: | 79 | case Opcode::WriteGlobalU8: |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.cpp b/src/shader_recompiler/frontend/ir/opcodes.cpp index 7d3e0b2ab..7f04b647b 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.cpp +++ b/src/shader_recompiler/frontend/ir/opcodes.cpp | |||
| @@ -24,6 +24,7 @@ constexpr Type Label{Type::Label}; | |||
| 24 | constexpr Type Reg{Type::Reg}; | 24 | constexpr Type Reg{Type::Reg}; |
| 25 | constexpr Type Pred{Type::Pred}; | 25 | constexpr Type Pred{Type::Pred}; |
| 26 | constexpr Type Attribute{Type::Attribute}; | 26 | constexpr Type Attribute{Type::Attribute}; |
| 27 | constexpr Type Patch{Type::Patch}; | ||
| 27 | constexpr Type U1{Type::U1}; | 28 | constexpr Type U1{Type::U1}; |
| 28 | constexpr Type U8{Type::U8}; | 29 | constexpr Type U8{Type::U8}; |
| 29 | constexpr Type U16{Type::U16}; | 30 | constexpr Type U16{Type::U16}; |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 7a21fe746..a86542cd8 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -48,6 +48,8 @@ OPCODE(GetAttribute, F32, Attr | |||
| 48 | OPCODE(SetAttribute, Void, Attribute, F32, U32, ) | 48 | OPCODE(SetAttribute, Void, Attribute, F32, U32, ) |
| 49 | OPCODE(GetAttributeIndexed, F32, U32, U32, ) | 49 | OPCODE(GetAttributeIndexed, F32, U32, U32, ) |
| 50 | OPCODE(SetAttributeIndexed, Void, U32, F32, U32, ) | 50 | OPCODE(SetAttributeIndexed, Void, U32, F32, U32, ) |
| 51 | OPCODE(GetPatch, F32, Patch, ) | ||
| 52 | OPCODE(SetPatch, Void, Patch, F32, ) | ||
| 51 | OPCODE(SetFragColor, Void, U32, U32, F32, ) | 53 | OPCODE(SetFragColor, Void, U32, U32, F32, ) |
| 52 | OPCODE(SetFragDepth, Void, F32, ) | 54 | OPCODE(SetFragDepth, Void, F32, ) |
| 53 | OPCODE(GetZFlag, U1, Void, ) | 55 | OPCODE(GetZFlag, U1, Void, ) |
| @@ -60,6 +62,7 @@ OPCODE(SetCFlag, Void, U1, | |||
| 60 | OPCODE(SetOFlag, Void, U1, ) | 62 | OPCODE(SetOFlag, Void, U1, ) |
| 61 | OPCODE(WorkgroupId, U32x3, ) | 63 | OPCODE(WorkgroupId, U32x3, ) |
| 62 | OPCODE(LocalInvocationId, U32x3, ) | 64 | OPCODE(LocalInvocationId, U32x3, ) |
| 65 | OPCODE(InvocationId, U32, ) | ||
| 63 | OPCODE(IsHelperInvocation, U1, ) | 66 | OPCODE(IsHelperInvocation, U1, ) |
| 64 | 67 | ||
| 65 | // Undefined | 68 | // Undefined |
diff --git a/src/shader_recompiler/frontend/ir/patch.cpp b/src/shader_recompiler/frontend/ir/patch.cpp new file mode 100644 index 000000000..1f770bc48 --- /dev/null +++ b/src/shader_recompiler/frontend/ir/patch.cpp | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "shader_recompiler/frontend/ir/patch.h" | ||
| 6 | #include "shader_recompiler/exception.h" | ||
| 7 | |||
| 8 | namespace Shader::IR { | ||
| 9 | |||
| 10 | bool IsGeneric(Patch patch) noexcept { | ||
| 11 | return patch >= Patch::Component0 && patch <= Patch::Component119; | ||
| 12 | } | ||
| 13 | |||
| 14 | u32 GenericPatchIndex(Patch patch) { | ||
| 15 | if (!IsGeneric(patch)) { | ||
| 16 | throw InvalidArgument("Patch {} is not generic", patch); | ||
| 17 | } | ||
| 18 | return (static_cast<u32>(patch) - static_cast<u32>(Patch::Component0)) / 4; | ||
| 19 | } | ||
| 20 | |||
| 21 | u32 GenericPatchElement(Patch patch) { | ||
| 22 | if (!IsGeneric(patch)) { | ||
| 23 | throw InvalidArgument("Patch {} is not generic", patch); | ||
| 24 | } | ||
| 25 | return (static_cast<u32>(patch) - static_cast<u32>(Patch::Component0)) % 4; | ||
| 26 | } | ||
| 27 | |||
| 28 | } // namespace Shader::IR | ||
diff --git a/src/shader_recompiler/frontend/ir/patch.h b/src/shader_recompiler/frontend/ir/patch.h new file mode 100644 index 000000000..6d66ff0d6 --- /dev/null +++ b/src/shader_recompiler/frontend/ir/patch.h | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Shader::IR { | ||
| 10 | |||
| 11 | enum class Patch : u64 { | ||
| 12 | TessellationLodLeft, | ||
| 13 | TessellationLodTop, | ||
| 14 | TessellationLodRight, | ||
| 15 | TessellationLodBottom, | ||
| 16 | TessellationLodInteriorU, | ||
| 17 | TessellationLodInteriorV, | ||
| 18 | ComponentPadding0, | ||
| 19 | ComponentPadding1, | ||
| 20 | Component0, | ||
| 21 | Component1, | ||
| 22 | Component2, | ||
| 23 | Component3, | ||
| 24 | Component4, | ||
| 25 | Component5, | ||
| 26 | Component6, | ||
| 27 | Component7, | ||
| 28 | Component8, | ||
| 29 | Component9, | ||
| 30 | Component10, | ||
| 31 | Component11, | ||
| 32 | Component12, | ||
| 33 | Component13, | ||
| 34 | Component14, | ||
| 35 | Component15, | ||
| 36 | Component16, | ||
| 37 | Component17, | ||
| 38 | Component18, | ||
| 39 | Component19, | ||
| 40 | Component20, | ||
| 41 | Component21, | ||
| 42 | Component22, | ||
| 43 | Component23, | ||
| 44 | Component24, | ||
| 45 | Component25, | ||
| 46 | Component26, | ||
| 47 | Component27, | ||
| 48 | Component28, | ||
| 49 | Component29, | ||
| 50 | Component30, | ||
| 51 | Component31, | ||
| 52 | Component32, | ||
| 53 | Component33, | ||
| 54 | Component34, | ||
| 55 | Component35, | ||
| 56 | Component36, | ||
| 57 | Component37, | ||
| 58 | Component38, | ||
| 59 | Component39, | ||
| 60 | Component40, | ||
| 61 | Component41, | ||
| 62 | Component42, | ||
| 63 | Component43, | ||
| 64 | Component44, | ||
| 65 | Component45, | ||
| 66 | Component46, | ||
| 67 | Component47, | ||
| 68 | Component48, | ||
| 69 | Component49, | ||
| 70 | Component50, | ||
| 71 | Component51, | ||
| 72 | Component52, | ||
| 73 | Component53, | ||
| 74 | Component54, | ||
| 75 | Component55, | ||
| 76 | Component56, | ||
| 77 | Component57, | ||
| 78 | Component58, | ||
| 79 | Component59, | ||
| 80 | Component60, | ||
| 81 | Component61, | ||
| 82 | Component62, | ||
| 83 | Component63, | ||
| 84 | Component64, | ||
| 85 | Component65, | ||
| 86 | Component66, | ||
| 87 | Component67, | ||
| 88 | Component68, | ||
| 89 | Component69, | ||
| 90 | Component70, | ||
| 91 | Component71, | ||
| 92 | Component72, | ||
| 93 | Component73, | ||
| 94 | Component74, | ||
| 95 | Component75, | ||
| 96 | Component76, | ||
| 97 | Component77, | ||
| 98 | Component78, | ||
| 99 | Component79, | ||
| 100 | Component80, | ||
| 101 | Component81, | ||
| 102 | Component82, | ||
| 103 | Component83, | ||
| 104 | Component84, | ||
| 105 | Component85, | ||
| 106 | Component86, | ||
| 107 | Component87, | ||
| 108 | Component88, | ||
| 109 | Component89, | ||
| 110 | Component90, | ||
| 111 | Component91, | ||
| 112 | Component92, | ||
| 113 | Component93, | ||
| 114 | Component94, | ||
| 115 | Component95, | ||
| 116 | Component96, | ||
| 117 | Component97, | ||
| 118 | Component98, | ||
| 119 | Component99, | ||
| 120 | Component100, | ||
| 121 | Component101, | ||
| 122 | Component102, | ||
| 123 | Component103, | ||
| 124 | Component104, | ||
| 125 | Component105, | ||
| 126 | Component106, | ||
| 127 | Component107, | ||
| 128 | Component108, | ||
| 129 | Component109, | ||
| 130 | Component110, | ||
| 131 | Component111, | ||
| 132 | Component112, | ||
| 133 | Component113, | ||
| 134 | Component114, | ||
| 135 | Component115, | ||
| 136 | Component116, | ||
| 137 | Component117, | ||
| 138 | Component118, | ||
| 139 | Component119, | ||
| 140 | }; | ||
| 141 | static_assert(static_cast<u64>(Patch::Component119) == 127); | ||
| 142 | |||
| 143 | [[nodiscard]] bool IsGeneric(Patch patch) noexcept; | ||
| 144 | |||
| 145 | [[nodiscard]] u32 GenericPatchIndex(Patch patch); | ||
| 146 | |||
| 147 | [[nodiscard]] u32 GenericPatchElement(Patch patch); | ||
| 148 | |||
| 149 | } // namespace Shader::IR | ||
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h index 9a32ca1e8..8b3b33852 100644 --- a/src/shader_recompiler/frontend/ir/type.h +++ b/src/shader_recompiler/frontend/ir/type.h | |||
| @@ -20,26 +20,27 @@ enum class Type { | |||
| 20 | Reg = 1 << 2, | 20 | Reg = 1 << 2, |
| 21 | Pred = 1 << 3, | 21 | Pred = 1 << 3, |
| 22 | Attribute = 1 << 4, | 22 | Attribute = 1 << 4, |
| 23 | U1 = 1 << 5, | 23 | Patch = 1 << 5, |
| 24 | U8 = 1 << 6, | 24 | U1 = 1 << 6, |
| 25 | U16 = 1 << 7, | 25 | U8 = 1 << 7, |
| 26 | U32 = 1 << 8, | 26 | U16 = 1 << 8, |
| 27 | U64 = 1 << 9, | 27 | U32 = 1 << 9, |
| 28 | F16 = 1 << 10, | 28 | U64 = 1 << 10, |
| 29 | F32 = 1 << 11, | 29 | F16 = 1 << 11, |
| 30 | F64 = 1 << 12, | 30 | F32 = 1 << 12, |
| 31 | U32x2 = 1 << 13, | 31 | F64 = 1 << 13, |
| 32 | U32x3 = 1 << 14, | 32 | U32x2 = 1 << 14, |
| 33 | U32x4 = 1 << 15, | 33 | U32x3 = 1 << 15, |
| 34 | F16x2 = 1 << 16, | 34 | U32x4 = 1 << 16, |
| 35 | F16x3 = 1 << 17, | 35 | F16x2 = 1 << 17, |
| 36 | F16x4 = 1 << 18, | 36 | F16x3 = 1 << 18, |
| 37 | F32x2 = 1 << 19, | 37 | F16x4 = 1 << 19, |
| 38 | F32x3 = 1 << 20, | 38 | F32x2 = 1 << 20, |
| 39 | F32x4 = 1 << 21, | 39 | F32x3 = 1 << 21, |
| 40 | F64x2 = 1 << 22, | 40 | F32x4 = 1 << 22, |
| 41 | F64x3 = 1 << 23, | 41 | F64x2 = 1 << 23, |
| 42 | F64x4 = 1 << 24, | 42 | F64x3 = 1 << 24, |
| 43 | F64x4 = 1 << 25, | ||
| 43 | }; | 44 | }; |
| 44 | DECLARE_ENUM_FLAG_OPERATORS(Type) | 45 | DECLARE_ENUM_FLAG_OPERATORS(Type) |
| 45 | 46 | ||
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp index 1e7ffb86d..bf5f8c0c2 100644 --- a/src/shader_recompiler/frontend/ir/value.cpp +++ b/src/shader_recompiler/frontend/ir/value.cpp | |||
| @@ -18,6 +18,8 @@ Value::Value(IR::Pred value) noexcept : type{Type::Pred}, pred{value} {} | |||
| 18 | 18 | ||
| 19 | Value::Value(IR::Attribute value) noexcept : type{Type::Attribute}, attribute{value} {} | 19 | Value::Value(IR::Attribute value) noexcept : type{Type::Attribute}, attribute{value} {} |
| 20 | 20 | ||
| 21 | Value::Value(IR::Patch value) noexcept : type{Type::Patch}, patch{value} {} | ||
| 22 | |||
| 21 | Value::Value(bool value) noexcept : type{Type::U1}, imm_u1{value} {} | 23 | Value::Value(bool value) noexcept : type{Type::U1}, imm_u1{value} {} |
| 22 | 24 | ||
| 23 | Value::Value(u8 value) noexcept : type{Type::U8}, imm_u8{value} {} | 25 | Value::Value(u8 value) noexcept : type{Type::U8}, imm_u8{value} {} |
| @@ -109,6 +111,11 @@ IR::Attribute Value::Attribute() const { | |||
| 109 | return attribute; | 111 | return attribute; |
| 110 | } | 112 | } |
| 111 | 113 | ||
| 114 | IR::Patch Value::Patch() const { | ||
| 115 | ValidateAccess(Type::Patch); | ||
| 116 | return patch; | ||
| 117 | } | ||
| 118 | |||
| 112 | bool Value::U1() const { | 119 | bool Value::U1() const { |
| 113 | if (IsIdentity()) { | 120 | if (IsIdentity()) { |
| 114 | return inst->Arg(0).U1(); | 121 | return inst->Arg(0).U1(); |
| @@ -182,6 +189,8 @@ bool Value::operator==(const Value& other) const { | |||
| 182 | return pred == other.pred; | 189 | return pred == other.pred; |
| 183 | case Type::Attribute: | 190 | case Type::Attribute: |
| 184 | return attribute == other.attribute; | 191 | return attribute == other.attribute; |
| 192 | case Type::Patch: | ||
| 193 | return patch == other.patch; | ||
| 185 | case Type::U1: | 194 | case Type::U1: |
| 186 | return imm_u1 == other.imm_u1; | 195 | return imm_u1 == other.imm_u1; |
| 187 | case Type::U8: | 196 | case Type::U8: |
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index a0962863d..303745563 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "shader_recompiler/frontend/ir/attribute.h" | 9 | #include "shader_recompiler/frontend/ir/attribute.h" |
| 10 | #include "shader_recompiler/frontend/ir/pred.h" | 10 | #include "shader_recompiler/frontend/ir/pred.h" |
| 11 | #include "shader_recompiler/frontend/ir/reg.h" | 11 | #include "shader_recompiler/frontend/ir/reg.h" |
| 12 | #include "shader_recompiler/frontend/ir/patch.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/type.h" | 13 | #include "shader_recompiler/frontend/ir/type.h" |
| 13 | 14 | ||
| 14 | namespace Shader::IR { | 15 | namespace Shader::IR { |
| @@ -24,6 +25,7 @@ public: | |||
| 24 | explicit Value(IR::Reg value) noexcept; | 25 | explicit Value(IR::Reg value) noexcept; |
| 25 | explicit Value(IR::Pred value) noexcept; | 26 | explicit Value(IR::Pred value) noexcept; |
| 26 | explicit Value(IR::Attribute value) noexcept; | 27 | explicit Value(IR::Attribute value) noexcept; |
| 28 | explicit Value(IR::Patch value) noexcept; | ||
| 27 | explicit Value(bool value) noexcept; | 29 | explicit Value(bool value) noexcept; |
| 28 | explicit Value(u8 value) noexcept; | 30 | explicit Value(u8 value) noexcept; |
| 29 | explicit Value(u16 value) noexcept; | 31 | explicit Value(u16 value) noexcept; |
| @@ -46,6 +48,7 @@ public: | |||
| 46 | [[nodiscard]] IR::Reg Reg() const; | 48 | [[nodiscard]] IR::Reg Reg() const; |
| 47 | [[nodiscard]] IR::Pred Pred() const; | 49 | [[nodiscard]] IR::Pred Pred() const; |
| 48 | [[nodiscard]] IR::Attribute Attribute() const; | 50 | [[nodiscard]] IR::Attribute Attribute() const; |
| 51 | [[nodiscard]] IR::Patch Patch() const; | ||
| 49 | [[nodiscard]] bool U1() const; | 52 | [[nodiscard]] bool U1() const; |
| 50 | [[nodiscard]] u8 U8() const; | 53 | [[nodiscard]] u8 U8() const; |
| 51 | [[nodiscard]] u16 U16() const; | 54 | [[nodiscard]] u16 U16() const; |
| @@ -67,6 +70,7 @@ private: | |||
| 67 | IR::Reg reg; | 70 | IR::Reg reg; |
| 68 | IR::Pred pred; | 71 | IR::Pred pred; |
| 69 | IR::Attribute attribute; | 72 | IR::Attribute attribute; |
| 73 | IR::Patch patch; | ||
| 70 | bool imm_u1; | 74 | bool imm_u1; |
| 71 | u8 imm_u8; | 75 | u8 imm_u8; |
| 72 | u16 imm_u16; | 76 | u16 imm_u16; |
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp index ab67446c8..20a1d61cc 100644 --- a/src/shader_recompiler/frontend/maxwell/program.cpp +++ b/src/shader_recompiler/frontend/maxwell/program.cpp | |||
| @@ -70,6 +70,11 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 70 | program.stage = env.ShaderStage(); | 70 | program.stage = env.ShaderStage(); |
| 71 | program.local_memory_size = env.LocalMemorySize(); | 71 | program.local_memory_size = env.LocalMemorySize(); |
| 72 | switch (program.stage) { | 72 | switch (program.stage) { |
| 73 | case Stage::TessellationControl: { | ||
| 74 | const ProgramHeader& sph{env.SPH()}; | ||
| 75 | program.invocations = sph.common2.threads_per_input_primitive; | ||
| 76 | break; | ||
| 77 | } | ||
| 73 | case Stage::Geometry: { | 78 | case Stage::Geometry: { |
| 74 | const ProgramHeader& sph{env.SPH()}; | 79 | const ProgramHeader& sph{env.SPH()}; |
| 75 | program.output_topology = sph.common3.output_topology; | 80 | program.output_topology = sph.common3.output_topology; |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp index eb6a80de2..7d7dcc3cb 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp | |||
| @@ -70,12 +70,6 @@ void TranslatorVisitor::ALD(u64 insn) { | |||
| 70 | BitField<47, 2, Size> size; | 70 | BitField<47, 2, Size> size; |
| 71 | } const ald{insn}; | 71 | } const ald{insn}; |
| 72 | 72 | ||
| 73 | if (ald.o != 0) { | ||
| 74 | throw NotImplementedException("O"); | ||
| 75 | } | ||
| 76 | if (ald.patch != 0) { | ||
| 77 | throw NotImplementedException("P"); | ||
| 78 | } | ||
| 79 | const u64 offset{ald.absolute_offset.Value()}; | 73 | const u64 offset{ald.absolute_offset.Value()}; |
| 80 | if (offset % 4 != 0) { | 74 | if (offset % 4 != 0) { |
| 81 | throw NotImplementedException("Unaligned absolute offset {}", offset); | 75 | throw NotImplementedException("Unaligned absolute offset {}", offset); |
| @@ -84,11 +78,19 @@ void TranslatorVisitor::ALD(u64 insn) { | |||
| 84 | const u32 num_elements{NumElements(ald.size)}; | 78 | const u32 num_elements{NumElements(ald.size)}; |
| 85 | if (ald.index_reg == IR::Reg::RZ) { | 79 | if (ald.index_reg == IR::Reg::RZ) { |
| 86 | for (u32 element = 0; element < num_elements; ++element) { | 80 | for (u32 element = 0; element < num_elements; ++element) { |
| 87 | const IR::Attribute attr{offset / 4 + element}; | 81 | if (ald.patch != 0) { |
| 88 | F(ald.dest_reg + element, ir.GetAttribute(attr, vertex)); | 82 | const IR::Patch patch{offset / 4 + element}; |
| 83 | F(ald.dest_reg + element, ir.GetPatch(patch)); | ||
| 84 | } else { | ||
| 85 | const IR::Attribute attr{offset / 4 + element}; | ||
| 86 | F(ald.dest_reg + element, ir.GetAttribute(attr, vertex)); | ||
| 87 | } | ||
| 89 | } | 88 | } |
| 90 | return; | 89 | return; |
| 91 | } | 90 | } |
| 91 | if (ald.patch != 0) { | ||
| 92 | throw NotImplementedException("Indirect patch read"); | ||
| 93 | } | ||
| 92 | HandleIndexed(*this, ald.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) { | 94 | HandleIndexed(*this, ald.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) { |
| 93 | F(ald.dest_reg + element, ir.GetAttributeIndexed(final_offset, vertex)); | 95 | F(ald.dest_reg + element, ir.GetAttributeIndexed(final_offset, vertex)); |
| 94 | }); | 96 | }); |
| @@ -106,9 +108,6 @@ void TranslatorVisitor::AST(u64 insn) { | |||
| 106 | BitField<47, 2, Size> size; | 108 | BitField<47, 2, Size> size; |
| 107 | } const ast{insn}; | 109 | } const ast{insn}; |
| 108 | 110 | ||
| 109 | if (ast.patch != 0) { | ||
| 110 | throw NotImplementedException("P"); | ||
| 111 | } | ||
| 112 | if (ast.index_reg != IR::Reg::RZ) { | 111 | if (ast.index_reg != IR::Reg::RZ) { |
| 113 | throw NotImplementedException("Indexed store"); | 112 | throw NotImplementedException("Indexed store"); |
| 114 | } | 113 | } |
| @@ -120,11 +119,19 @@ void TranslatorVisitor::AST(u64 insn) { | |||
| 120 | const u32 num_elements{NumElements(ast.size)}; | 119 | const u32 num_elements{NumElements(ast.size)}; |
| 121 | if (ast.index_reg == IR::Reg::RZ) { | 120 | if (ast.index_reg == IR::Reg::RZ) { |
| 122 | for (u32 element = 0; element < num_elements; ++element) { | 121 | for (u32 element = 0; element < num_elements; ++element) { |
| 123 | const IR::Attribute attr{offset / 4 + element}; | 122 | if (ast.patch != 0) { |
| 124 | ir.SetAttribute(attr, F(ast.src_reg + element), vertex); | 123 | const IR::Patch patch{offset / 4 + element}; |
| 124 | ir.SetPatch(patch, F(ast.src_reg + element)); | ||
| 125 | } else { | ||
| 126 | const IR::Attribute attr{offset / 4 + element}; | ||
| 127 | ir.SetAttribute(attr, F(ast.src_reg + element), vertex); | ||
| 128 | } | ||
| 125 | } | 129 | } |
| 126 | return; | 130 | return; |
| 127 | } | 131 | } |
| 132 | if (ast.patch != 0) { | ||
| 133 | throw NotImplementedException("Indexed tessellation patch store"); | ||
| 134 | } | ||
| 128 | HandleIndexed(*this, ast.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) { | 135 | HandleIndexed(*this, ast.index_reg, num_elements, [&](u32 element, IR::U32 final_offset) { |
| 129 | ir.SetAttributeIndexed(final_offset, F(ast.src_reg + element), vertex); | 136 | ir.SetAttributeIndexed(final_offset, F(ast.src_reg + element), vertex); |
| 130 | }); | 137 | }); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp index bc822d585..660b84c20 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp | |||
| @@ -113,6 +113,8 @@ enum class SpecialRegister : u64 { | |||
| 113 | 113 | ||
| 114 | [[nodiscard]] IR::U32 Read(IR::IREmitter& ir, SpecialRegister special_register) { | 114 | [[nodiscard]] IR::U32 Read(IR::IREmitter& ir, SpecialRegister special_register) { |
| 115 | switch (special_register) { | 115 | switch (special_register) { |
| 116 | case SpecialRegister::SR_INVOCATION_ID: | ||
| 117 | return ir.InvocationId(); | ||
| 116 | case SpecialRegister::SR_THREAD_KILL: | 118 | case SpecialRegister::SR_THREAD_KILL: |
| 117 | return IR::U32{ir.Select(ir.IsHelperInvocation(), ir.Imm32(-1), ir.Imm32(0))}; | 119 | return IR::U32{ir.Select(ir.IsHelperInvocation(), ir.Imm32(-1), ir.Imm32(0))}; |
| 118 | case SpecialRegister::SR_INVOCATION_INFO: | 120 | case SpecialRegister::SR_INVOCATION_INFO: |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 617ec05ce..aadcf7999 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -53,6 +53,10 @@ void GetAttribute(Info& info, IR::Attribute attribute) { | |||
| 53 | case IR::Attribute::PointSpriteT: | 53 | case IR::Attribute::PointSpriteT: |
| 54 | info.loads_point_coord = true; | 54 | info.loads_point_coord = true; |
| 55 | break; | 55 | break; |
| 56 | case IR::Attribute::TessellationEvaluationPointU: | ||
| 57 | case IR::Attribute::TessellationEvaluationPointV: | ||
| 58 | info.loads_tess_coord = true; | ||
| 59 | break; | ||
| 56 | default: | 60 | default: |
| 57 | throw NotImplementedException("Get attribute {}", attribute); | 61 | throw NotImplementedException("Get attribute {}", attribute); |
| 58 | } | 62 | } |
| @@ -94,6 +98,34 @@ void SetAttribute(Info& info, IR::Attribute attribute) { | |||
| 94 | } | 98 | } |
| 95 | } | 99 | } |
| 96 | 100 | ||
| 101 | void GetPatch(Info& info, IR::Patch patch) { | ||
| 102 | if (!IR::IsGeneric(patch)) { | ||
| 103 | throw NotImplementedException("Reading non-generic patch {}", patch); | ||
| 104 | } | ||
| 105 | info.uses_patches.at(IR::GenericPatchIndex(patch)) = true; | ||
| 106 | } | ||
| 107 | |||
| 108 | void SetPatch(Info& info, IR::Patch patch) { | ||
| 109 | if (IR::IsGeneric(patch)) { | ||
| 110 | info.uses_patches.at(IR::GenericPatchIndex(patch)) = true; | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | switch (patch) { | ||
| 114 | case IR::Patch::TessellationLodLeft: | ||
| 115 | case IR::Patch::TessellationLodTop: | ||
| 116 | case IR::Patch::TessellationLodRight: | ||
| 117 | case IR::Patch::TessellationLodBottom: | ||
| 118 | info.stores_tess_level_outer = true; | ||
| 119 | break; | ||
| 120 | case IR::Patch::TessellationLodInteriorU: | ||
| 121 | case IR::Patch::TessellationLodInteriorV: | ||
| 122 | info.stores_tess_level_inner = true; | ||
| 123 | break; | ||
| 124 | default: | ||
| 125 | throw NotImplementedException("Set patch {}", patch); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 97 | void VisitUsages(Info& info, IR::Inst& inst) { | 129 | void VisitUsages(Info& info, IR::Inst& inst) { |
| 98 | switch (inst.GetOpcode()) { | 130 | switch (inst.GetOpcode()) { |
| 99 | case IR::Opcode::CompositeConstructF16x2: | 131 | case IR::Opcode::CompositeConstructF16x2: |
| @@ -350,6 +382,12 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 350 | case IR::Opcode::SetAttribute: | 382 | case IR::Opcode::SetAttribute: |
| 351 | SetAttribute(info, inst.Arg(0).Attribute()); | 383 | SetAttribute(info, inst.Arg(0).Attribute()); |
| 352 | break; | 384 | break; |
| 385 | case IR::Opcode::GetPatch: | ||
| 386 | GetPatch(info, inst.Arg(0).Patch()); | ||
| 387 | break; | ||
| 388 | case IR::Opcode::SetPatch: | ||
| 389 | SetPatch(info, inst.Arg(0).Patch()); | ||
| 390 | break; | ||
| 353 | case IR::Opcode::GetAttributeIndexed: | 391 | case IR::Opcode::GetAttributeIndexed: |
| 354 | info.loads_indexed_attributes = true; | 392 | info.loads_indexed_attributes = true; |
| 355 | break; | 393 | break; |
| @@ -368,6 +406,9 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 368 | case IR::Opcode::LocalInvocationId: | 406 | case IR::Opcode::LocalInvocationId: |
| 369 | info.uses_local_invocation_id = true; | 407 | info.uses_local_invocation_id = true; |
| 370 | break; | 408 | break; |
| 409 | case IR::Opcode::InvocationId: | ||
| 410 | info.uses_invocation_id = true; | ||
| 411 | break; | ||
| 371 | case IR::Opcode::IsHelperInvocation: | 412 | case IR::Opcode::IsHelperInvocation: |
| 372 | info.uses_is_helper_invocation = true; | 413 | info.uses_is_helper_invocation = true; |
| 373 | break; | 414 | break; |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index c26017d75..3a04f075e 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -38,6 +38,18 @@ enum class CompareFunction { | |||
| 38 | Always, | 38 | Always, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | enum class TessPrimitive { | ||
| 42 | Isolines, | ||
| 43 | Triangles, | ||
| 44 | Quads, | ||
| 45 | }; | ||
| 46 | |||
| 47 | enum class TessSpacing { | ||
| 48 | Equal, | ||
| 49 | FractionalOdd, | ||
| 50 | FractionalEven, | ||
| 51 | }; | ||
| 52 | |||
| 41 | struct TransformFeedbackVarying { | 53 | struct TransformFeedbackVarying { |
| 42 | u32 buffer{}; | 54 | u32 buffer{}; |
| 43 | u32 stride{}; | 55 | u32 stride{}; |
| @@ -74,6 +86,10 @@ struct Profile { | |||
| 74 | bool convert_depth_mode{}; | 86 | bool convert_depth_mode{}; |
| 75 | bool force_early_z{}; | 87 | bool force_early_z{}; |
| 76 | 88 | ||
| 89 | TessPrimitive tess_primitive{}; | ||
| 90 | TessSpacing tess_spacing{}; | ||
| 91 | bool tess_clockwise{}; | ||
| 92 | |||
| 77 | InputTopology input_topology{}; | 93 | InputTopology input_topology{}; |
| 78 | 94 | ||
| 79 | std::optional<float> fixed_state_point_size; | 95 | std::optional<float> fixed_state_point_size; |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 336c6131a..4dbf9ed12 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -101,8 +101,10 @@ struct Info { | |||
| 101 | 101 | ||
| 102 | bool uses_workgroup_id{}; | 102 | bool uses_workgroup_id{}; |
| 103 | bool uses_local_invocation_id{}; | 103 | bool uses_local_invocation_id{}; |
| 104 | bool uses_invocation_id{}; | ||
| 104 | bool uses_is_helper_invocation{}; | 105 | bool uses_is_helper_invocation{}; |
| 105 | bool uses_subgroup_invocation_id{}; | 106 | bool uses_subgroup_invocation_id{}; |
| 107 | std::array<bool, 30> uses_patches{}; | ||
| 106 | 108 | ||
| 107 | std::array<InputVarying, 32> input_generics{}; | 109 | std::array<InputVarying, 32> input_generics{}; |
| 108 | bool loads_position{}; | 110 | bool loads_position{}; |
| @@ -110,6 +112,7 @@ struct Info { | |||
| 110 | bool loads_vertex_id{}; | 112 | bool loads_vertex_id{}; |
| 111 | bool loads_front_face{}; | 113 | bool loads_front_face{}; |
| 112 | bool loads_point_coord{}; | 114 | bool loads_point_coord{}; |
| 115 | bool loads_tess_coord{}; | ||
| 113 | bool loads_indexed_attributes{}; | 116 | bool loads_indexed_attributes{}; |
| 114 | 117 | ||
| 115 | std::array<bool, 8> stores_frag_color{}; | 118 | std::array<bool, 8> stores_frag_color{}; |
| @@ -120,6 +123,8 @@ struct Info { | |||
| 120 | bool stores_clip_distance{}; | 123 | bool stores_clip_distance{}; |
| 121 | bool stores_layer{}; | 124 | bool stores_layer{}; |
| 122 | bool stores_viewport_index{}; | 125 | bool stores_viewport_index{}; |
| 126 | bool stores_tess_level_outer{}; | ||
| 127 | bool stores_tess_level_inner{}; | ||
| 123 | bool stores_indexed_attributes{}; | 128 | bool stores_indexed_attributes{}; |
| 124 | 129 | ||
| 125 | bool uses_fp16{}; | 130 | bool uses_fp16{}; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index dc4ff0da2..8f0b0b8ec 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -685,6 +685,19 @@ VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face) { | |||
| 685 | return {}; | 685 | return {}; |
| 686 | } | 686 | } |
| 687 | 687 | ||
| 688 | VkPolygonMode PolygonMode(Maxwell::PolygonMode polygon_mode) { | ||
| 689 | switch (polygon_mode) { | ||
| 690 | case Maxwell::PolygonMode::Point: | ||
| 691 | return VK_POLYGON_MODE_POINT; | ||
| 692 | case Maxwell::PolygonMode::Line: | ||
| 693 | return VK_POLYGON_MODE_LINE; | ||
| 694 | case Maxwell::PolygonMode::Fill: | ||
| 695 | return VK_POLYGON_MODE_FILL; | ||
| 696 | } | ||
| 697 | UNIMPLEMENTED_MSG("Unimplemented polygon mode={}", polygon_mode); | ||
| 698 | return {}; | ||
| 699 | } | ||
| 700 | |||
| 688 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle) { | 701 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle) { |
| 689 | switch (swizzle) { | 702 | switch (swizzle) { |
| 690 | case Tegra::Texture::SwizzleSource::Zero: | 703 | case Tegra::Texture::SwizzleSource::Zero: |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 9f78e15b6..50a599c11 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h | |||
| @@ -65,6 +65,8 @@ VkFrontFace FrontFace(Maxwell::FrontFace front_face); | |||
| 65 | 65 | ||
| 66 | VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face); | 66 | VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face); |
| 67 | 67 | ||
| 68 | VkPolygonMode PolygonMode(Maxwell::PolygonMode polygon_mode); | ||
| 69 | |||
| 68 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); | 70 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); |
| 69 | 71 | ||
| 70 | VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle); | 72 | VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle); |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 84720a6f9..d5e9dae0f 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -355,7 +355,8 @@ void GraphicsPipeline::MakePipeline(const Device& device, VkRenderPass render_pa | |||
| 355 | static_cast<VkBool32>(state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), | 355 | static_cast<VkBool32>(state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), |
| 356 | .rasterizerDiscardEnable = | 356 | .rasterizerDiscardEnable = |
| 357 | static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), | 357 | static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), |
| 358 | .polygonMode = VK_POLYGON_MODE_FILL, | 358 | .polygonMode = |
| 359 | MaxwellToVK::PolygonMode(FixedPipelineState::UnpackPolygonMode(state.polygon_mode)), | ||
| 359 | .cullMode = static_cast<VkCullModeFlags>( | 360 | .cullMode = static_cast<VkCullModeFlags>( |
| 360 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), | 361 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), |
| 361 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), | 362 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ee22255bf..0bccc640a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -1040,6 +1040,36 @@ Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key, | |||
| 1040 | std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(), | 1040 | std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(), |
| 1041 | &CastAttributeType); | 1041 | &CastAttributeType); |
| 1042 | break; | 1042 | break; |
| 1043 | case Shader::Stage::TessellationEval: | ||
| 1044 | // We have to flip tessellation clockwise for some reason... | ||
| 1045 | profile.tess_clockwise = key.state.tessellation_clockwise == 0; | ||
| 1046 | profile.tess_primitive = [&key] { | ||
| 1047 | const u32 raw{key.state.tessellation_primitive.Value()}; | ||
| 1048 | switch (static_cast<Maxwell::TessellationPrimitive>(raw)) { | ||
| 1049 | case Maxwell::TessellationPrimitive::Isolines: | ||
| 1050 | return Shader::TessPrimitive::Isolines; | ||
| 1051 | case Maxwell::TessellationPrimitive::Triangles: | ||
| 1052 | return Shader::TessPrimitive::Triangles; | ||
| 1053 | case Maxwell::TessellationPrimitive::Quads: | ||
| 1054 | return Shader::TessPrimitive::Quads; | ||
| 1055 | } | ||
| 1056 | UNREACHABLE(); | ||
| 1057 | return Shader::TessPrimitive::Triangles; | ||
| 1058 | }(); | ||
| 1059 | profile.tess_spacing = [&] { | ||
| 1060 | const u32 raw{key.state.tessellation_spacing}; | ||
| 1061 | switch (static_cast<Maxwell::TessellationSpacing>(raw)) { | ||
| 1062 | case Maxwell::TessellationSpacing::Equal: | ||
| 1063 | return Shader::TessSpacing::Equal; | ||
| 1064 | case Maxwell::TessellationSpacing::FractionalOdd: | ||
| 1065 | return Shader::TessSpacing::FractionalOdd; | ||
| 1066 | case Maxwell::TessellationSpacing::FractionalEven: | ||
| 1067 | return Shader::TessSpacing::FractionalEven; | ||
| 1068 | } | ||
| 1069 | UNREACHABLE(); | ||
| 1070 | return Shader::TessSpacing::Equal; | ||
| 1071 | }(); | ||
| 1072 | break; | ||
| 1043 | case Shader::Stage::Geometry: | 1073 | case Shader::Stage::Geometry: |
| 1044 | if (program.output_topology == Shader::OutputTopology::PointList) { | 1074 | if (program.output_topology == Shader::OutputTopology::PointList) { |
| 1045 | profile.fixed_state_point_size = point_size; | 1075 | profile.fixed_state_point_size = point_size; |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 0412b5234..555b12ed7 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -91,7 +91,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem | |||
| 91 | .flags = 0, | 91 | .flags = 0, |
| 92 | .size = STREAM_BUFFER_SIZE, | 92 | .size = STREAM_BUFFER_SIZE, |
| 93 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | | 93 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | |
| 94 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, | 94 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, |
| 95 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 95 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 96 | .queueFamilyIndexCount = 0, | 96 | .queueFamilyIndexCount = 0, |
| 97 | .pQueueFamilyIndices = nullptr, | 97 | .pQueueFamilyIndices = nullptr, |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 87cfe6312..f0de19ba1 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -225,7 +225,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 225 | .drawIndirectFirstInstance = false, | 225 | .drawIndirectFirstInstance = false, |
| 226 | .depthClamp = true, | 226 | .depthClamp = true, |
| 227 | .depthBiasClamp = true, | 227 | .depthBiasClamp = true, |
| 228 | .fillModeNonSolid = false, | 228 | .fillModeNonSolid = true, |
| 229 | .depthBounds = false, | 229 | .depthBounds = false, |
| 230 | .wideLines = false, | 230 | .wideLines = false, |
| 231 | .largePoints = true, | 231 | .largePoints = true, |
| @@ -670,6 +670,7 @@ void Device::CheckSuitability(bool requires_swapchain) const { | |||
| 670 | std::make_pair(features.largePoints, "largePoints"), | 670 | std::make_pair(features.largePoints, "largePoints"), |
| 671 | std::make_pair(features.multiViewport, "multiViewport"), | 671 | std::make_pair(features.multiViewport, "multiViewport"), |
| 672 | std::make_pair(features.depthBiasClamp, "depthBiasClamp"), | 672 | std::make_pair(features.depthBiasClamp, "depthBiasClamp"), |
| 673 | std::make_pair(features.fillModeNonSolid, "fillModeNonSolid"), | ||
| 673 | std::make_pair(features.geometryShader, "geometryShader"), | 674 | std::make_pair(features.geometryShader, "geometryShader"), |
| 674 | std::make_pair(features.tessellationShader, "tessellationShader"), | 675 | std::make_pair(features.tessellationShader, "tessellationShader"), |
| 675 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), | 676 | std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), |