diff options
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_context.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 002b305dc..eadecb064 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -82,6 +82,28 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) { | |||
| 82 | } | 82 | } |
| 83 | throw InvalidArgument("Invalid attribute type {}", type); | 83 | throw InvalidArgument("Invalid attribute type {}", type); |
| 84 | } | 84 | } |
| 85 | |||
| 86 | struct AttrInfo { | ||
| 87 | Id pointer; | ||
| 88 | Id id; | ||
| 89 | bool needs_cast; | ||
| 90 | }; | ||
| 91 | |||
| 92 | std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | ||
| 93 | const AttributeType type{ctx.profile.generic_input_types.at(index)}; | ||
| 94 | switch (type) { | ||
| 95 | case AttributeType::Float: | ||
| 96 | return AttrInfo{ctx.input_f32, ctx.F32[1], false}; | ||
| 97 | case AttributeType::UnsignedInt: | ||
| 98 | return AttrInfo{ctx.input_u32, ctx.U32[1], true}; | ||
| 99 | case AttributeType::SignedInt: | ||
| 100 | return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; | ||
| 101 | case AttributeType::Disabled: | ||
| 102 | return std::nullopt; | ||
| 103 | } | ||
| 104 | throw InvalidArgument("Invalid attribute type {}", type); | ||
| 105 | } | ||
| 106 | |||
| 85 | } // Anonymous namespace | 107 | } // Anonymous namespace |
| 86 | 108 | ||
| 87 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 109 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -107,6 +129,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
| 107 | DefineConstantBuffers(program.info, binding); | 129 | DefineConstantBuffers(program.info, binding); |
| 108 | DefineStorageBuffers(program.info, binding); | 130 | DefineStorageBuffers(program.info, binding); |
| 109 | DefineTextures(program.info, binding); | 131 | DefineTextures(program.info, binding); |
| 132 | DefineAttributeMemAccess(program.info); | ||
| 110 | DefineLabels(program); | 133 | DefineLabels(program); |
| 111 | } | 134 | } |
| 112 | 135 | ||
| @@ -290,6 +313,107 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) { | |||
| 290 | } | 313 | } |
| 291 | } | 314 | } |
| 292 | 315 | ||
| 316 | void EmitContext::DefineAttributeMemAccess(const Info& info) { | ||
| 317 | const auto make_load{[&]() { | ||
| 318 | const Id end_block{OpLabel()}; | ||
| 319 | const Id default_label{OpLabel()}; | ||
| 320 | |||
| 321 | const Id func_type_load{TypeFunction(F32[1], U32[1])}; | ||
| 322 | const Id func{OpFunction(F32[1], spv::FunctionControlMask::MaskNone, func_type_load)}; | ||
| 323 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 324 | AddLabel(); | ||
| 325 | const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||
| 326 | const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||
| 327 | const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||
| 328 | std::vector<Sirit::Literal> literals; | ||
| 329 | std::vector<Id> labels; | ||
| 330 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||
| 331 | for (u32 i = 0; i < info.input_generics.size(); i++) { | ||
| 332 | if (!info.input_generics[i].used) { | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | literals.push_back(base_attribute_value + i); | ||
| 336 | labels.push_back(OpLabel()); | ||
| 337 | } | ||
| 338 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||
| 339 | OpSwitch(compare_index, default_label, literals, labels); | ||
| 340 | AddLabel(default_label); | ||
| 341 | OpReturnValue(Constant(F32[1], 0.0f)); | ||
| 342 | size_t label_index = 0; | ||
| 343 | for (u32 i = 0; i < info.input_generics.size(); i++) { | ||
| 344 | if (!info.input_generics[i].used) { | ||
| 345 | continue; | ||
| 346 | } | ||
| 347 | AddLabel(labels[label_index]); | ||
| 348 | const auto type{AttrTypes(*this, i)}; | ||
| 349 | if (!type) { | ||
| 350 | OpReturnValue(Constant(F32[1], 0.0f)); | ||
| 351 | label_index++; | ||
| 352 | continue; | ||
| 353 | } | ||
| 354 | const Id generic_id{input_generics.at(i)}; | ||
| 355 | const Id pointer{OpAccessChain(type->pointer, generic_id, masked_index)}; | ||
| 356 | const Id value{OpLoad(type->id, pointer)}; | ||
| 357 | const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value}; | ||
| 358 | OpReturnValue(result); | ||
| 359 | label_index++; | ||
| 360 | } | ||
| 361 | AddLabel(end_block); | ||
| 362 | OpUnreachable(); | ||
| 363 | OpFunctionEnd(); | ||
| 364 | return func; | ||
| 365 | }}; | ||
| 366 | const auto make_store{[&]() { | ||
| 367 | const Id end_block{OpLabel()}; | ||
| 368 | const Id default_label{OpLabel()}; | ||
| 369 | |||
| 370 | const Id func_type_store{TypeFunction(void_id, U32[1], F32[1])}; | ||
| 371 | const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type_store)}; | ||
| 372 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 373 | const Id store_value{OpFunctionParameter(F32[1])}; | ||
| 374 | AddLabel(); | ||
| 375 | const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||
| 376 | const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||
| 377 | const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||
| 378 | std::vector<Sirit::Literal> literals; | ||
| 379 | std::vector<Id> labels; | ||
| 380 | const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||
| 381 | for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||
| 382 | if (!info.stores_generics[i]) { | ||
| 383 | continue; | ||
| 384 | } | ||
| 385 | literals.push_back(base_attribute_value + i); | ||
| 386 | labels.push_back(OpLabel()); | ||
| 387 | } | ||
| 388 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||
| 389 | OpSwitch(compare_index, default_label, literals, labels); | ||
| 390 | AddLabel(default_label); | ||
| 391 | OpReturn(); | ||
| 392 | size_t label_index = 0; | ||
| 393 | for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||
| 394 | if (!info.stores_generics[i]) { | ||
| 395 | continue; | ||
| 396 | } | ||
| 397 | AddLabel(labels[label_index]); | ||
| 398 | const Id generic_id{output_generics.at(i)}; | ||
| 399 | const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; | ||
| 400 | OpStore(pointer, store_value); | ||
| 401 | OpReturn(); | ||
| 402 | label_index++; | ||
| 403 | } | ||
| 404 | AddLabel(end_block); | ||
| 405 | OpUnreachable(); | ||
| 406 | OpFunctionEnd(); | ||
| 407 | return func; | ||
| 408 | }}; | ||
| 409 | if (info.loads_indexed_attributes) { | ||
| 410 | indexed_load_func = make_load(); | ||
| 411 | } | ||
| 412 | if (info.stores_indexed_attributes) { | ||
| 413 | indexed_store_func = make_store(); | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 293 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 417 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| 294 | if (info.constant_buffer_descriptors.empty()) { | 418 | if (info.constant_buffer_descriptors.empty()) { |
| 295 | return; | 419 | return; |