diff options
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_context.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.cpp | 97 |
1 files changed, 54 insertions, 43 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 4c6501129..af4fb0c69 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -557,7 +557,7 @@ void EmitContext::DefineCommonConstants() { | |||
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | void EmitContext::DefineInterfaces(const IR::Program& program) { | 559 | void EmitContext::DefineInterfaces(const IR::Program& program) { |
| 560 | DefineInputs(program.info); | 560 | DefineInputs(program); |
| 561 | DefineOutputs(program); | 561 | DefineOutputs(program); |
| 562 | } | 562 | } |
| 563 | 563 | ||
| @@ -693,16 +693,16 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 693 | const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))}; | 693 | const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))}; |
| 694 | std::vector<Sirit::Literal> literals; | 694 | std::vector<Sirit::Literal> literals; |
| 695 | std::vector<Id> labels; | 695 | std::vector<Id> labels; |
| 696 | if (info.loads_position) { | 696 | if (info.loads.AnyComponent(IR::Attribute::PositionX)) { |
| 697 | literals.push_back(static_cast<u32>(IR::Attribute::PositionX) >> 2); | 697 | literals.push_back(static_cast<u32>(IR::Attribute::PositionX) >> 2); |
| 698 | labels.push_back(OpLabel()); | 698 | labels.push_back(OpLabel()); |
| 699 | } | 699 | } |
| 700 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | 700 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; |
| 701 | for (u32 i = 0; i < info.input_generics.size(); ++i) { | 701 | for (u32 index = 0; index < static_cast<u32>(IR::NUM_GENERICS); ++index) { |
| 702 | if (!info.input_generics[i].used) { | 702 | if (!info.loads.Generic(index)) { |
| 703 | continue; | 703 | continue; |
| 704 | } | 704 | } |
| 705 | literals.push_back(base_attribute_value + i); | 705 | literals.push_back(base_attribute_value + index); |
| 706 | labels.push_back(OpLabel()); | 706 | labels.push_back(OpLabel()); |
| 707 | } | 707 | } |
| 708 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | 708 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); |
| @@ -710,7 +710,7 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 710 | AddLabel(default_label); | 710 | AddLabel(default_label); |
| 711 | OpReturnValue(Const(0.0f)); | 711 | OpReturnValue(Const(0.0f)); |
| 712 | size_t label_index{0}; | 712 | size_t label_index{0}; |
| 713 | if (info.loads_position) { | 713 | if (info.loads.AnyComponent(IR::Attribute::PositionX)) { |
| 714 | AddLabel(labels[label_index]); | 714 | AddLabel(labels[label_index]); |
| 715 | const Id pointer{is_array | 715 | const Id pointer{is_array |
| 716 | ? OpAccessChain(input_f32, input_position, vertex, masked_index) | 716 | ? OpAccessChain(input_f32, input_position, vertex, masked_index) |
| @@ -719,18 +719,18 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 719 | OpReturnValue(result); | 719 | OpReturnValue(result); |
| 720 | ++label_index; | 720 | ++label_index; |
| 721 | } | 721 | } |
| 722 | for (size_t i = 0; i < info.input_generics.size(); i++) { | 722 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 723 | if (!info.input_generics[i].used) { | 723 | if (!info.loads.Generic(index)) { |
| 724 | continue; | 724 | continue; |
| 725 | } | 725 | } |
| 726 | AddLabel(labels[label_index]); | 726 | AddLabel(labels[label_index]); |
| 727 | const auto type{AttrTypes(*this, static_cast<u32>(i))}; | 727 | const auto type{AttrTypes(*this, static_cast<u32>(index))}; |
| 728 | if (!type) { | 728 | if (!type) { |
| 729 | OpReturnValue(Const(0.0f)); | 729 | OpReturnValue(Const(0.0f)); |
| 730 | ++label_index; | 730 | ++label_index; |
| 731 | continue; | 731 | continue; |
| 732 | } | 732 | } |
| 733 | const Id generic_id{input_generics.at(i)}; | 733 | const Id generic_id{input_generics.at(index)}; |
| 734 | const Id pointer{is_array | 734 | const Id pointer{is_array |
| 735 | ? OpAccessChain(type->pointer, generic_id, vertex, masked_index) | 735 | ? OpAccessChain(type->pointer, generic_id, vertex, masked_index) |
| 736 | : OpAccessChain(type->pointer, generic_id, masked_index)}; | 736 | : OpAccessChain(type->pointer, generic_id, masked_index)}; |
| @@ -758,19 +758,19 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 758 | const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))}; | 758 | const Id compare_index{OpShiftRightArithmetic(U32[1], base_index, Const(2U))}; |
| 759 | std::vector<Sirit::Literal> literals; | 759 | std::vector<Sirit::Literal> literals; |
| 760 | std::vector<Id> labels; | 760 | std::vector<Id> labels; |
| 761 | if (info.stores_position) { | 761 | if (info.stores.AnyComponent(IR::Attribute::PositionX)) { |
| 762 | literals.push_back(static_cast<u32>(IR::Attribute::PositionX) >> 2); | 762 | literals.push_back(static_cast<u32>(IR::Attribute::PositionX) >> 2); |
| 763 | labels.push_back(OpLabel()); | 763 | labels.push_back(OpLabel()); |
| 764 | } | 764 | } |
| 765 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | 765 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; |
| 766 | for (size_t i = 0; i < info.stores_generics.size(); i++) { | 766 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 767 | if (!info.stores_generics[i]) { | 767 | if (!info.stores.Generic(index)) { |
| 768 | continue; | 768 | continue; |
| 769 | } | 769 | } |
| 770 | literals.push_back(base_attribute_value + static_cast<u32>(i)); | 770 | literals.push_back(base_attribute_value + static_cast<u32>(index)); |
| 771 | labels.push_back(OpLabel()); | 771 | labels.push_back(OpLabel()); |
| 772 | } | 772 | } |
| 773 | if (info.stores_clip_distance) { | 773 | if (info.stores.ClipDistances()) { |
| 774 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); | 774 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); |
| 775 | labels.push_back(OpLabel()); | 775 | labels.push_back(OpLabel()); |
| 776 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); | 776 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); |
| @@ -781,28 +781,28 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 781 | AddLabel(default_label); | 781 | AddLabel(default_label); |
| 782 | OpReturn(); | 782 | OpReturn(); |
| 783 | size_t label_index{0}; | 783 | size_t label_index{0}; |
| 784 | if (info.stores_position) { | 784 | if (info.stores.AnyComponent(IR::Attribute::PositionX)) { |
| 785 | AddLabel(labels[label_index]); | 785 | AddLabel(labels[label_index]); |
| 786 | const Id pointer{OpAccessChain(output_f32, output_position, masked_index)}; | 786 | const Id pointer{OpAccessChain(output_f32, output_position, masked_index)}; |
| 787 | OpStore(pointer, store_value); | 787 | OpStore(pointer, store_value); |
| 788 | OpReturn(); | 788 | OpReturn(); |
| 789 | ++label_index; | 789 | ++label_index; |
| 790 | } | 790 | } |
| 791 | for (size_t i = 0; i < info.stores_generics.size(); ++i) { | 791 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 792 | if (!info.stores_generics[i]) { | 792 | if (!info.stores.Generic(index)) { |
| 793 | continue; | 793 | continue; |
| 794 | } | 794 | } |
| 795 | if (output_generics[i][0].num_components != 4) { | 795 | if (output_generics[index][0].num_components != 4) { |
| 796 | throw NotImplementedException("Physical stores and transform feedbacks"); | 796 | throw NotImplementedException("Physical stores and transform feedbacks"); |
| 797 | } | 797 | } |
| 798 | AddLabel(labels[label_index]); | 798 | AddLabel(labels[label_index]); |
| 799 | const Id generic_id{output_generics[i][0].id}; | 799 | const Id generic_id{output_generics[index][0].id}; |
| 800 | const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; | 800 | const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; |
| 801 | OpStore(pointer, store_value); | 801 | OpStore(pointer, store_value); |
| 802 | OpReturn(); | 802 | OpReturn(); |
| 803 | ++label_index; | 803 | ++label_index; |
| 804 | } | 804 | } |
| 805 | if (info.stores_clip_distance) { | 805 | if (info.stores.ClipDistances()) { |
| 806 | AddLabel(labels[label_index]); | 806 | AddLabel(labels[label_index]); |
| 807 | const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; | 807 | const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; |
| 808 | OpStore(pointer, store_value); | 808 | OpStore(pointer, store_value); |
| @@ -1146,7 +1146,10 @@ void EmitContext::DefineImages(const Info& info, u32& binding) { | |||
| 1146 | } | 1146 | } |
| 1147 | } | 1147 | } |
| 1148 | 1148 | ||
| 1149 | void EmitContext::DefineInputs(const Info& info) { | 1149 | void EmitContext::DefineInputs(const IR::Program& program) { |
| 1150 | const Info& info{program.info}; | ||
| 1151 | const VaryingState loads{info.loads.mask | info.passthrough.mask}; | ||
| 1152 | |||
| 1150 | if (info.uses_workgroup_id) { | 1153 | if (info.uses_workgroup_id) { |
| 1151 | workgroup_id = DefineInput(*this, U32[3], false, spv::BuiltIn::WorkgroupId); | 1154 | workgroup_id = DefineInput(*this, U32[3], false, spv::BuiltIn::WorkgroupId); |
| 1152 | } | 1155 | } |
| @@ -1183,15 +1186,20 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1183 | fswzadd_lut_b = | 1186 | fswzadd_lut_b = |
| 1184 | ConstantComposite(F32[4], f32_minus_one, f32_minus_one, f32_one, f32_minus_one); | 1187 | ConstantComposite(F32[4], f32_minus_one, f32_minus_one, f32_one, f32_minus_one); |
| 1185 | } | 1188 | } |
| 1186 | if (info.loads_primitive_id) { | 1189 | if (loads[IR::Attribute::PrimitiveId]) { |
| 1187 | primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); | 1190 | primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); |
| 1188 | } | 1191 | } |
| 1189 | if (info.loads_position) { | 1192 | if (loads.AnyComponent(IR::Attribute::PositionX)) { |
| 1190 | const bool is_fragment{stage != Stage::Fragment}; | 1193 | const bool is_fragment{stage != Stage::Fragment}; |
| 1191 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; | 1194 | const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; |
| 1192 | input_position = DefineInput(*this, F32[4], true, built_in); | 1195 | input_position = DefineInput(*this, F32[4], true, built_in); |
| 1196 | if (profile.support_geometry_shader_passthrough) { | ||
| 1197 | if (info.passthrough.AnyComponent(IR::Attribute::PositionX)) { | ||
| 1198 | Decorate(input_position, spv::Decoration::PassthroughNV); | ||
| 1199 | } | ||
| 1200 | } | ||
| 1193 | } | 1201 | } |
| 1194 | if (info.loads_instance_id) { | 1202 | if (loads[IR::Attribute::InstanceId]) { |
| 1195 | if (profile.support_vertex_instance_id) { | 1203 | if (profile.support_vertex_instance_id) { |
| 1196 | instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId); | 1204 | instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId); |
| 1197 | } else { | 1205 | } else { |
| @@ -1199,7 +1207,7 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1199 | base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseInstance); | 1207 | base_instance = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseInstance); |
| 1200 | } | 1208 | } |
| 1201 | } | 1209 | } |
| 1202 | if (info.loads_vertex_id) { | 1210 | if (loads[IR::Attribute::VertexId]) { |
| 1203 | if (profile.support_vertex_instance_id) { | 1211 | if (profile.support_vertex_instance_id) { |
| 1204 | vertex_id = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexId); | 1212 | vertex_id = DefineInput(*this, U32[1], true, spv::BuiltIn::VertexId); |
| 1205 | } else { | 1213 | } else { |
| @@ -1207,24 +1215,24 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1207 | base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex); | 1215 | base_vertex = DefineInput(*this, U32[1], true, spv::BuiltIn::BaseVertex); |
| 1208 | } | 1216 | } |
| 1209 | } | 1217 | } |
| 1210 | if (info.loads_front_face) { | 1218 | if (loads[IR::Attribute::FrontFace]) { |
| 1211 | front_face = DefineInput(*this, U1, true, spv::BuiltIn::FrontFacing); | 1219 | front_face = DefineInput(*this, U1, true, spv::BuiltIn::FrontFacing); |
| 1212 | } | 1220 | } |
| 1213 | if (info.loads_point_coord) { | 1221 | if (loads[IR::Attribute::PointSpriteS] || loads[IR::Attribute::PointSpriteT]) { |
| 1214 | point_coord = DefineInput(*this, F32[2], true, spv::BuiltIn::PointCoord); | 1222 | point_coord = DefineInput(*this, F32[2], true, spv::BuiltIn::PointCoord); |
| 1215 | } | 1223 | } |
| 1216 | if (info.loads_tess_coord) { | 1224 | if (loads[IR::Attribute::TessellationEvaluationPointU] || |
| 1225 | loads[IR::Attribute::TessellationEvaluationPointV]) { | ||
| 1217 | tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord); | 1226 | tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord); |
| 1218 | } | 1227 | } |
| 1219 | for (size_t index = 0; index < info.input_generics.size(); ++index) { | 1228 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 1220 | if (!runtime_info.previous_stage_stores_generic[index]) { | 1229 | const AttributeType input_type{runtime_info.generic_input_types[index]}; |
| 1230 | if (!runtime_info.previous_stage_stores.Generic(index)) { | ||
| 1221 | continue; | 1231 | continue; |
| 1222 | } | 1232 | } |
| 1223 | const InputVarying generic{info.input_generics[index]}; | 1233 | if (!loads.Generic(index)) { |
| 1224 | if (!generic.used) { | ||
| 1225 | continue; | 1234 | continue; |
| 1226 | } | 1235 | } |
| 1227 | const AttributeType input_type{runtime_info.generic_input_types[index]}; | ||
| 1228 | if (input_type == AttributeType::Disabled) { | 1236 | if (input_type == AttributeType::Disabled) { |
| 1229 | continue; | 1237 | continue; |
| 1230 | } | 1238 | } |
| @@ -1234,10 +1242,13 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1234 | Name(id, fmt::format("in_attr{}", index)); | 1242 | Name(id, fmt::format("in_attr{}", index)); |
| 1235 | input_generics[index] = id; | 1243 | input_generics[index] = id; |
| 1236 | 1244 | ||
| 1245 | if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) { | ||
| 1246 | Decorate(id, spv::Decoration::PassthroughNV); | ||
| 1247 | } | ||
| 1237 | if (stage != Stage::Fragment) { | 1248 | if (stage != Stage::Fragment) { |
| 1238 | continue; | 1249 | continue; |
| 1239 | } | 1250 | } |
| 1240 | switch (generic.interpolation) { | 1251 | switch (info.interpolation[index]) { |
| 1241 | case Interpolation::Smooth: | 1252 | case Interpolation::Smooth: |
| 1242 | // Default | 1253 | // Default |
| 1243 | // Decorate(id, spv::Decoration::Smooth); | 1254 | // Decorate(id, spv::Decoration::Smooth); |
| @@ -1266,42 +1277,42 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 1266 | void EmitContext::DefineOutputs(const IR::Program& program) { | 1277 | void EmitContext::DefineOutputs(const IR::Program& program) { |
| 1267 | const Info& info{program.info}; | 1278 | const Info& info{program.info}; |
| 1268 | const std::optional<u32> invocations{program.invocations}; | 1279 | const std::optional<u32> invocations{program.invocations}; |
| 1269 | if (info.stores_position || stage == Stage::VertexB) { | 1280 | if (info.stores.AnyComponent(IR::Attribute::PositionX) || stage == Stage::VertexB) { |
| 1270 | output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position); | 1281 | output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position); |
| 1271 | } | 1282 | } |
| 1272 | if (info.stores_point_size || runtime_info.fixed_state_point_size) { | 1283 | if (info.stores[IR::Attribute::PointSize] || runtime_info.fixed_state_point_size) { |
| 1273 | if (stage == Stage::Fragment) { | 1284 | if (stage == Stage::Fragment) { |
| 1274 | throw NotImplementedException("Storing PointSize in fragment stage"); | 1285 | throw NotImplementedException("Storing PointSize in fragment stage"); |
| 1275 | } | 1286 | } |
| 1276 | output_point_size = DefineOutput(*this, F32[1], invocations, spv::BuiltIn::PointSize); | 1287 | output_point_size = DefineOutput(*this, F32[1], invocations, spv::BuiltIn::PointSize); |
| 1277 | } | 1288 | } |
| 1278 | if (info.stores_clip_distance) { | 1289 | if (info.stores.ClipDistances()) { |
| 1279 | if (stage == Stage::Fragment) { | 1290 | if (stage == Stage::Fragment) { |
| 1280 | throw NotImplementedException("Storing ClipDistance in fragment stage"); | 1291 | throw NotImplementedException("Storing ClipDistance in fragment stage"); |
| 1281 | } | 1292 | } |
| 1282 | const Id type{TypeArray(F32[1], Const(8U))}; | 1293 | const Id type{TypeArray(F32[1], Const(8U))}; |
| 1283 | clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); | 1294 | clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); |
| 1284 | } | 1295 | } |
| 1285 | if (info.stores_layer && | 1296 | if (info.stores[IR::Attribute::Layer] && |
| 1286 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { | 1297 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { |
| 1287 | if (stage == Stage::Fragment) { | 1298 | if (stage == Stage::Fragment) { |
| 1288 | throw NotImplementedException("Storing Layer in fragment stage"); | 1299 | throw NotImplementedException("Storing Layer in fragment stage"); |
| 1289 | } | 1300 | } |
| 1290 | layer = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::Layer); | 1301 | layer = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::Layer); |
| 1291 | } | 1302 | } |
| 1292 | if (info.stores_viewport_index && | 1303 | if (info.stores[IR::Attribute::ViewportIndex] && |
| 1293 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { | 1304 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { |
| 1294 | if (stage == Stage::Fragment) { | 1305 | if (stage == Stage::Fragment) { |
| 1295 | throw NotImplementedException("Storing ViewportIndex in fragment stage"); | 1306 | throw NotImplementedException("Storing ViewportIndex in fragment stage"); |
| 1296 | } | 1307 | } |
| 1297 | viewport_index = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::ViewportIndex); | 1308 | viewport_index = DefineOutput(*this, U32[1], invocations, spv::BuiltIn::ViewportIndex); |
| 1298 | } | 1309 | } |
| 1299 | if (info.stores_viewport_mask && profile.support_viewport_mask) { | 1310 | if (info.stores[IR::Attribute::ViewportMask] && profile.support_viewport_mask) { |
| 1300 | viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt, | 1311 | viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt, |
| 1301 | spv::BuiltIn::ViewportMaskNV); | 1312 | spv::BuiltIn::ViewportMaskNV); |
| 1302 | } | 1313 | } |
| 1303 | for (size_t index = 0; index < info.stores_generics.size(); ++index) { | 1314 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 1304 | if (info.stores_generics[index]) { | 1315 | if (info.stores.Generic(index)) { |
| 1305 | DefineGenericOutput(*this, index, invocations); | 1316 | DefineGenericOutput(*this, index, invocations); |
| 1306 | } | 1317 | } |
| 1307 | } | 1318 | } |