diff options
Diffstat (limited to 'src/shader_recompiler/backend')
19 files changed, 323 insertions, 185 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 0cb1e193e..b795c0179 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -279,6 +279,8 @@ void SetupOptions(const IR::Program& program, const Profile& profile, | |||
| 279 | header += "OPTION NV_internal;" | 279 | header += "OPTION NV_internal;" |
| 280 | "OPTION NV_shader_storage_buffer;" | 280 | "OPTION NV_shader_storage_buffer;" |
| 281 | "OPTION NV_gpu_program_fp64;"; | 281 | "OPTION NV_gpu_program_fp64;"; |
| 282 | // TODO: Enable only when MS is used | ||
| 283 | header += "OPTION NV_texture_multisample;"; | ||
| 282 | if (info.uses_int64_bit_atomics) { | 284 | if (info.uses_int64_bit_atomics) { |
| 283 | header += "OPTION NV_shader_atomic_int64;"; | 285 | header += "OPTION NV_shader_atomic_int64;"; |
| 284 | } | 286 | } |
| @@ -459,7 +461,7 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I | |||
| 459 | header += fmt::format("R{},", index); | 461 | header += fmt::format("R{},", index); |
| 460 | } | 462 | } |
| 461 | if (program.local_memory_size > 0) { | 463 | if (program.local_memory_size > 0) { |
| 462 | header += fmt::format("lmem[{}],", program.local_memory_size); | 464 | header += fmt::format("lmem[{}],", Common::DivCeil(program.local_memory_size, 4U)); |
| 463 | } | 465 | } |
| 464 | if (program.info.uses_fswzadd) { | 466 | if (program.info.uses_fswzadd) { |
| 465 | header += "FSWZA[4],FSWZB[4],"; | 467 | header += "FSWZA[4],FSWZB[4],"; |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp index 5bfdecc09..2fc2a0ac6 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp | |||
| @@ -43,10 +43,6 @@ void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | |||
| 43 | Alias(inst, value); | 43 | Alias(inst, value); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void EmitBitCastS32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||
| 47 | Alias(inst, value); | ||
| 48 | } | ||
| 49 | |||
| 50 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 46 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 51 | Alias(inst, value); | 47 | Alias(inst, value); |
| 52 | } | 48 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp index e67e80fac..85ee27333 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp | |||
| @@ -59,7 +59,14 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info, | |||
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | std::string_view TextureType(IR::TextureInstInfo info) { | 62 | bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) { |
| 63 | if (info.type == TextureType::Buffer) { | ||
| 64 | return false; | ||
| 65 | } | ||
| 66 | return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample; | ||
| 67 | } | ||
| 68 | |||
| 69 | std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) { | ||
| 63 | if (info.is_depth) { | 70 | if (info.is_depth) { |
| 64 | switch (info.type) { | 71 | switch (info.type) { |
| 65 | case TextureType::Color1D: | 72 | case TextureType::Color1D: |
| @@ -88,9 +95,9 @@ std::string_view TextureType(IR::TextureInstInfo info) { | |||
| 88 | return "ARRAY1D"; | 95 | return "ARRAY1D"; |
| 89 | case TextureType::Color2D: | 96 | case TextureType::Color2D: |
| 90 | case TextureType::Color2DRect: | 97 | case TextureType::Color2DRect: |
| 91 | return "2D"; | 98 | return is_ms ? "2DMS" : "2D"; |
| 92 | case TextureType::ColorArray2D: | 99 | case TextureType::ColorArray2D: |
| 93 | return "ARRAY2D"; | 100 | return is_ms ? "ARRAY2DMS" : "ARRAY2D"; |
| 94 | case TextureType::Color3D: | 101 | case TextureType::Color3D: |
| 95 | return "3D"; | 102 | return "3D"; |
| 96 | case TextureType::ColorCube: | 103 | case TextureType::ColorCube: |
| @@ -510,15 +517,16 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 510 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) { | 517 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) { |
| 511 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 518 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 512 | const auto sparse_inst{PrepareSparse(inst)}; | 519 | const auto sparse_inst{PrepareSparse(inst)}; |
| 520 | const bool is_multisample{ms.type != Type::Void}; | ||
| 513 | const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""}; | 521 | const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""}; |
| 514 | const std::string_view type{TextureType(info)}; | 522 | const std::string_view type{TextureType(info, is_multisample)}; |
| 515 | const std::string texture{Texture(ctx, info, index)}; | 523 | const std::string texture{Texture(ctx, info, index)}; |
| 516 | const std::string offset_vec{Offset(ctx, offset)}; | 524 | const std::string offset_vec{Offset(ctx, offset)}; |
| 517 | const auto [coord_vec, coord_alloc]{Coord(ctx, coord)}; | 525 | const auto [coord_vec, coord_alloc]{Coord(ctx, coord)}; |
| 518 | const Register ret{ctx.reg_alloc.Define(inst)}; | 526 | const Register ret{ctx.reg_alloc.Define(inst)}; |
| 519 | if (info.type == TextureType::Buffer) { | 527 | if (info.type == TextureType::Buffer) { |
| 520 | ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec); | 528 | ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec); |
| 521 | } else if (ms.type != Type::Void) { | 529 | } else if (is_multisample) { |
| 522 | ctx.Add("MOV.S {}.w,{};" | 530 | ctx.Add("MOV.S {}.w,{};" |
| 523 | "TXFMS.F{} {},{},{},{}{};", | 531 | "TXFMS.F{} {},{},{},{}{};", |
| 524 | coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec); | 532 | coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec); |
| @@ -531,10 +539,11 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 531 | } | 539 | } |
| 532 | 540 | ||
| 533 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 541 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 534 | ScalarS32 lod) { | 542 | ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) { |
| 535 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 543 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 536 | const std::string texture{Texture(ctx, info, index)}; | 544 | const std::string texture{Texture(ctx, info, index)}; |
| 537 | const std::string_view type{TextureType(info)}; | 545 | const bool is_msaa{IsTextureMsaa(ctx, info)}; |
| 546 | const std::string_view type{TextureType(info, is_msaa)}; | ||
| 538 | ctx.Add("TXQ {},{},{},{};", inst, lod, texture, type); | 547 | ctx.Add("TXQ {},{},{},{};", inst, lod, texture, type); |
| 539 | } | 548 | } |
| 540 | 549 | ||
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index eaaf9ba39..1a1ea61d5 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h | |||
| @@ -197,7 +197,6 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist | |||
| 197 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 197 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 198 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 198 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 199 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 199 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 200 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||
| 201 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 200 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 202 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 201 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 203 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 202 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| @@ -582,7 +581,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde | |||
| 582 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 581 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 583 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms); | 582 | const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms); |
| 584 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 583 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 585 | ScalarS32 lod); | 584 | ScalarS32 lod, const IR::Value& skip_mips); |
| 586 | void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord); | 585 | void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord); |
| 587 | void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 586 | void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 588 | const IR::Value& coord, const IR::Value& derivatives, | 587 | const IR::Value& coord, const IR::Value& derivatives, |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp index 911181c43..376a05827 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp | |||
| @@ -398,162 +398,162 @@ void EmitStorageAtomicMaxF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value | |||
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | void EmitGlobalAtomicIAdd32(EmitContext&) { | 400 | void EmitGlobalAtomicIAdd32(EmitContext&) { |
| 401 | throw NotImplementedException("GLSL Instrucion"); | 401 | throw NotImplementedException("GLSL Instruction"); |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | void EmitGlobalAtomicSMin32(EmitContext&) { | 404 | void EmitGlobalAtomicSMin32(EmitContext&) { |
| 405 | throw NotImplementedException("GLSL Instrucion"); | 405 | throw NotImplementedException("GLSL Instruction"); |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | void EmitGlobalAtomicUMin32(EmitContext&) { | 408 | void EmitGlobalAtomicUMin32(EmitContext&) { |
| 409 | throw NotImplementedException("GLSL Instrucion"); | 409 | throw NotImplementedException("GLSL Instruction"); |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | void EmitGlobalAtomicSMax32(EmitContext&) { | 412 | void EmitGlobalAtomicSMax32(EmitContext&) { |
| 413 | throw NotImplementedException("GLSL Instrucion"); | 413 | throw NotImplementedException("GLSL Instruction"); |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | void EmitGlobalAtomicUMax32(EmitContext&) { | 416 | void EmitGlobalAtomicUMax32(EmitContext&) { |
| 417 | throw NotImplementedException("GLSL Instrucion"); | 417 | throw NotImplementedException("GLSL Instruction"); |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | void EmitGlobalAtomicInc32(EmitContext&) { | 420 | void EmitGlobalAtomicInc32(EmitContext&) { |
| 421 | throw NotImplementedException("GLSL Instrucion"); | 421 | throw NotImplementedException("GLSL Instruction"); |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | void EmitGlobalAtomicDec32(EmitContext&) { | 424 | void EmitGlobalAtomicDec32(EmitContext&) { |
| 425 | throw NotImplementedException("GLSL Instrucion"); | 425 | throw NotImplementedException("GLSL Instruction"); |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | void EmitGlobalAtomicAnd32(EmitContext&) { | 428 | void EmitGlobalAtomicAnd32(EmitContext&) { |
| 429 | throw NotImplementedException("GLSL Instrucion"); | 429 | throw NotImplementedException("GLSL Instruction"); |
| 430 | } | 430 | } |
| 431 | 431 | ||
| 432 | void EmitGlobalAtomicOr32(EmitContext&) { | 432 | void EmitGlobalAtomicOr32(EmitContext&) { |
| 433 | throw NotImplementedException("GLSL Instrucion"); | 433 | throw NotImplementedException("GLSL Instruction"); |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | void EmitGlobalAtomicXor32(EmitContext&) { | 436 | void EmitGlobalAtomicXor32(EmitContext&) { |
| 437 | throw NotImplementedException("GLSL Instrucion"); | 437 | throw NotImplementedException("GLSL Instruction"); |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | void EmitGlobalAtomicExchange32(EmitContext&) { | 440 | void EmitGlobalAtomicExchange32(EmitContext&) { |
| 441 | throw NotImplementedException("GLSL Instrucion"); | 441 | throw NotImplementedException("GLSL Instruction"); |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | void EmitGlobalAtomicIAdd64(EmitContext&) { | 444 | void EmitGlobalAtomicIAdd64(EmitContext&) { |
| 445 | throw NotImplementedException("GLSL Instrucion"); | 445 | throw NotImplementedException("GLSL Instruction"); |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | void EmitGlobalAtomicSMin64(EmitContext&) { | 448 | void EmitGlobalAtomicSMin64(EmitContext&) { |
| 449 | throw NotImplementedException("GLSL Instrucion"); | 449 | throw NotImplementedException("GLSL Instruction"); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | void EmitGlobalAtomicUMin64(EmitContext&) { | 452 | void EmitGlobalAtomicUMin64(EmitContext&) { |
| 453 | throw NotImplementedException("GLSL Instrucion"); | 453 | throw NotImplementedException("GLSL Instruction"); |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | void EmitGlobalAtomicSMax64(EmitContext&) { | 456 | void EmitGlobalAtomicSMax64(EmitContext&) { |
| 457 | throw NotImplementedException("GLSL Instrucion"); | 457 | throw NotImplementedException("GLSL Instruction"); |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | void EmitGlobalAtomicUMax64(EmitContext&) { | 460 | void EmitGlobalAtomicUMax64(EmitContext&) { |
| 461 | throw NotImplementedException("GLSL Instrucion"); | 461 | throw NotImplementedException("GLSL Instruction"); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | void EmitGlobalAtomicInc64(EmitContext&) { | 464 | void EmitGlobalAtomicInc64(EmitContext&) { |
| 465 | throw NotImplementedException("GLSL Instrucion"); | 465 | throw NotImplementedException("GLSL Instruction"); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | void EmitGlobalAtomicDec64(EmitContext&) { | 468 | void EmitGlobalAtomicDec64(EmitContext&) { |
| 469 | throw NotImplementedException("GLSL Instrucion"); | 469 | throw NotImplementedException("GLSL Instruction"); |
| 470 | } | 470 | } |
| 471 | 471 | ||
| 472 | void EmitGlobalAtomicAnd64(EmitContext&) { | 472 | void EmitGlobalAtomicAnd64(EmitContext&) { |
| 473 | throw NotImplementedException("GLSL Instrucion"); | 473 | throw NotImplementedException("GLSL Instruction"); |
| 474 | } | 474 | } |
| 475 | 475 | ||
| 476 | void EmitGlobalAtomicOr64(EmitContext&) { | 476 | void EmitGlobalAtomicOr64(EmitContext&) { |
| 477 | throw NotImplementedException("GLSL Instrucion"); | 477 | throw NotImplementedException("GLSL Instruction"); |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | void EmitGlobalAtomicXor64(EmitContext&) { | 480 | void EmitGlobalAtomicXor64(EmitContext&) { |
| 481 | throw NotImplementedException("GLSL Instrucion"); | 481 | throw NotImplementedException("GLSL Instruction"); |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | void EmitGlobalAtomicExchange64(EmitContext&) { | 484 | void EmitGlobalAtomicExchange64(EmitContext&) { |
| 485 | throw NotImplementedException("GLSL Instrucion"); | 485 | throw NotImplementedException("GLSL Instruction"); |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | void EmitGlobalAtomicIAdd32x2(EmitContext&) { | 488 | void EmitGlobalAtomicIAdd32x2(EmitContext&) { |
| 489 | throw NotImplementedException("GLSL Instrucion"); | 489 | throw NotImplementedException("GLSL Instruction"); |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | void EmitGlobalAtomicSMin32x2(EmitContext&) { | 492 | void EmitGlobalAtomicSMin32x2(EmitContext&) { |
| 493 | throw NotImplementedException("GLSL Instrucion"); | 493 | throw NotImplementedException("GLSL Instruction"); |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | void EmitGlobalAtomicUMin32x2(EmitContext&) { | 496 | void EmitGlobalAtomicUMin32x2(EmitContext&) { |
| 497 | throw NotImplementedException("GLSL Instrucion"); | 497 | throw NotImplementedException("GLSL Instruction"); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | void EmitGlobalAtomicSMax32x2(EmitContext&) { | 500 | void EmitGlobalAtomicSMax32x2(EmitContext&) { |
| 501 | throw NotImplementedException("GLSL Instrucion"); | 501 | throw NotImplementedException("GLSL Instruction"); |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | void EmitGlobalAtomicUMax32x2(EmitContext&) { | 504 | void EmitGlobalAtomicUMax32x2(EmitContext&) { |
| 505 | throw NotImplementedException("GLSL Instrucion"); | 505 | throw NotImplementedException("GLSL Instruction"); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | void EmitGlobalAtomicInc32x2(EmitContext&) { | 508 | void EmitGlobalAtomicInc32x2(EmitContext&) { |
| 509 | throw NotImplementedException("GLSL Instrucion"); | 509 | throw NotImplementedException("GLSL Instruction"); |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | void EmitGlobalAtomicDec32x2(EmitContext&) { | 512 | void EmitGlobalAtomicDec32x2(EmitContext&) { |
| 513 | throw NotImplementedException("GLSL Instrucion"); | 513 | throw NotImplementedException("GLSL Instruction"); |
| 514 | } | 514 | } |
| 515 | 515 | ||
| 516 | void EmitGlobalAtomicAnd32x2(EmitContext&) { | 516 | void EmitGlobalAtomicAnd32x2(EmitContext&) { |
| 517 | throw NotImplementedException("GLSL Instrucion"); | 517 | throw NotImplementedException("GLSL Instruction"); |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | void EmitGlobalAtomicOr32x2(EmitContext&) { | 520 | void EmitGlobalAtomicOr32x2(EmitContext&) { |
| 521 | throw NotImplementedException("GLSL Instrucion"); | 521 | throw NotImplementedException("GLSL Instruction"); |
| 522 | } | 522 | } |
| 523 | 523 | ||
| 524 | void EmitGlobalAtomicXor32x2(EmitContext&) { | 524 | void EmitGlobalAtomicXor32x2(EmitContext&) { |
| 525 | throw NotImplementedException("GLSL Instrucion"); | 525 | throw NotImplementedException("GLSL Instruction"); |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | void EmitGlobalAtomicExchange32x2(EmitContext&) { | 528 | void EmitGlobalAtomicExchange32x2(EmitContext&) { |
| 529 | throw NotImplementedException("GLSL Instrucion"); | 529 | throw NotImplementedException("GLSL Instruction"); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | void EmitGlobalAtomicAddF32(EmitContext&) { | 532 | void EmitGlobalAtomicAddF32(EmitContext&) { |
| 533 | throw NotImplementedException("GLSL Instrucion"); | 533 | throw NotImplementedException("GLSL Instruction"); |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | void EmitGlobalAtomicAddF16x2(EmitContext&) { | 536 | void EmitGlobalAtomicAddF16x2(EmitContext&) { |
| 537 | throw NotImplementedException("GLSL Instrucion"); | 537 | throw NotImplementedException("GLSL Instruction"); |
| 538 | } | 538 | } |
| 539 | 539 | ||
| 540 | void EmitGlobalAtomicAddF32x2(EmitContext&) { | 540 | void EmitGlobalAtomicAddF32x2(EmitContext&) { |
| 541 | throw NotImplementedException("GLSL Instrucion"); | 541 | throw NotImplementedException("GLSL Instruction"); |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | void EmitGlobalAtomicMinF16x2(EmitContext&) { | 544 | void EmitGlobalAtomicMinF16x2(EmitContext&) { |
| 545 | throw NotImplementedException("GLSL Instrucion"); | 545 | throw NotImplementedException("GLSL Instruction"); |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | void EmitGlobalAtomicMinF32x2(EmitContext&) { | 548 | void EmitGlobalAtomicMinF32x2(EmitContext&) { |
| 549 | throw NotImplementedException("GLSL Instrucion"); | 549 | throw NotImplementedException("GLSL Instruction"); |
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | void EmitGlobalAtomicMaxF16x2(EmitContext&) { | 552 | void EmitGlobalAtomicMaxF16x2(EmitContext&) { |
| 553 | throw NotImplementedException("GLSL Instrucion"); | 553 | throw NotImplementedException("GLSL Instruction"); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | void EmitGlobalAtomicMaxF32x2(EmitContext&) { | 556 | void EmitGlobalAtomicMaxF32x2(EmitContext&) { |
| 557 | throw NotImplementedException("GLSL Instrucion"); | 557 | throw NotImplementedException("GLSL Instruction"); |
| 558 | } | 558 | } |
| 559 | } // namespace Shader::Backend::GLSL | 559 | } // namespace Shader::Backend::GLSL |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp index 8e5e6cf1f..1be4a0f59 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp | |||
| @@ -48,10 +48,6 @@ void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value) | |||
| 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); | 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | ||
| 52 | ctx.AddF32("{}=ftoi({});", inst, value); | ||
| 53 | } | ||
| 54 | |||
| 55 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | 51 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { |
| 56 | NotImplemented(); | 52 | NotImplemented(); |
| 57 | } | 53 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp index cecdbb9d6..418505475 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp | |||
| @@ -25,6 +25,13 @@ std::string Image(EmitContext& ctx, const IR::TextureInstInfo& info, const IR::V | |||
| 25 | return fmt::format("img{}{}", def.binding, index_offset); | 25 | return fmt::format("img{}{}", def.binding, index_offset); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) { | ||
| 29 | if (info.type == TextureType::Buffer) { | ||
| 30 | return false; | ||
| 31 | } | ||
| 32 | return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample; | ||
| 33 | } | ||
| 34 | |||
| 28 | std::string CastToIntVec(std::string_view value, const IR::TextureInstInfo& info) { | 35 | std::string CastToIntVec(std::string_view value, const IR::TextureInstInfo& info) { |
| 29 | switch (info.type) { | 36 | switch (info.type) { |
| 30 | case TextureType::Color1D: | 37 | case TextureType::Color1D: |
| @@ -136,6 +143,21 @@ IR::Inst* PrepareSparse(IR::Inst& inst) { | |||
| 136 | } | 143 | } |
| 137 | return sparse_inst; | 144 | return sparse_inst; |
| 138 | } | 145 | } |
| 146 | |||
| 147 | std::string ImageGatherSubpixelOffset(const IR::TextureInstInfo& info, std::string_view texture, | ||
| 148 | std::string_view coords) { | ||
| 149 | switch (info.type) { | ||
| 150 | case TextureType::Color2D: | ||
| 151 | case TextureType::Color2DRect: | ||
| 152 | return fmt::format("{}+vec2(0.001953125)/vec2(textureSize({}, 0))", coords, texture); | ||
| 153 | case TextureType::ColorArray2D: | ||
| 154 | case TextureType::ColorCube: | ||
| 155 | return fmt::format("vec3({0}.xy+vec2(0.001953125)/vec2(textureSize({1}, 0)),{0}.z)", coords, | ||
| 156 | texture); | ||
| 157 | default: | ||
| 158 | return std::string{coords}; | ||
| 159 | } | ||
| 160 | } | ||
| 139 | } // Anonymous namespace | 161 | } // Anonymous namespace |
| 140 | 162 | ||
| 141 | void EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 163 | void EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| @@ -333,6 +355,13 @@ void EmitImageGather(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 333 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); | 355 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); |
| 334 | ctx.AddU1("{}=true;", *sparse_inst); | 356 | ctx.AddU1("{}=true;", *sparse_inst); |
| 335 | } | 357 | } |
| 358 | std::string coords_with_subpixel_offset; | ||
| 359 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 360 | // Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on | ||
| 361 | // AMD hardware as on Maxwell or other Nvidia architectures. | ||
| 362 | coords_with_subpixel_offset = ImageGatherSubpixelOffset(info, texture, coords); | ||
| 363 | coords = coords_with_subpixel_offset; | ||
| 364 | } | ||
| 336 | if (!sparse_inst || !supports_sparse) { | 365 | if (!sparse_inst || !supports_sparse) { |
| 337 | if (offset.IsEmpty()) { | 366 | if (offset.IsEmpty()) { |
| 338 | ctx.Add("{}=textureGather({},{},int({}));", texel, texture, coords, | 367 | ctx.Add("{}=textureGather({},{},int({}));", texel, texture, coords, |
| @@ -380,6 +409,13 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde | |||
| 380 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); | 409 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); |
| 381 | ctx.AddU1("{}=true;", *sparse_inst); | 410 | ctx.AddU1("{}=true;", *sparse_inst); |
| 382 | } | 411 | } |
| 412 | std::string coords_with_subpixel_offset; | ||
| 413 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 414 | // Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on | ||
| 415 | // AMD hardware as on Maxwell or other Nvidia architectures. | ||
| 416 | coords_with_subpixel_offset = ImageGatherSubpixelOffset(info, texture, coords); | ||
| 417 | coords = coords_with_subpixel_offset; | ||
| 418 | } | ||
| 383 | if (!sparse_inst || !supports_sparse) { | 419 | if (!sparse_inst || !supports_sparse) { |
| 384 | if (offset.IsEmpty()) { | 420 | if (offset.IsEmpty()) { |
| 385 | ctx.Add("{}=textureGather({},{},{});", texel, texture, coords, dref); | 421 | ctx.Add("{}=textureGather({},{},{});", texel, texture, coords, dref); |
| @@ -414,7 +450,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde | |||
| 414 | 450 | ||
| 415 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 451 | void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 416 | std::string_view coords, std::string_view offset, std::string_view lod, | 452 | std::string_view coords, std::string_view offset, std::string_view lod, |
| 417 | [[maybe_unused]] std::string_view ms) { | 453 | std::string_view ms) { |
| 418 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 454 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 419 | if (info.has_bias) { | 455 | if (info.has_bias) { |
| 420 | throw NotImplementedException("EmitImageFetch Bias texture samples"); | 456 | throw NotImplementedException("EmitImageFetch Bias texture samples"); |
| @@ -431,19 +467,24 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 431 | ctx.AddU1("{}=true;", *sparse_inst); | 467 | ctx.AddU1("{}=true;", *sparse_inst); |
| 432 | } | 468 | } |
| 433 | if (!sparse_inst || !supports_sparse) { | 469 | if (!sparse_inst || !supports_sparse) { |
| 434 | if (!offset.empty()) { | 470 | const auto int_coords{CoordsCastToInt(coords, info)}; |
| 435 | ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, | 471 | if (!ms.empty()) { |
| 436 | CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info)); | 472 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms); |
| 473 | } else if (!offset.empty()) { | ||
| 474 | ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod, | ||
| 475 | CoordsCastToInt(offset, info)); | ||
| 437 | } else { | 476 | } else { |
| 438 | if (info.type == TextureType::Buffer) { | 477 | if (info.type == TextureType::Buffer) { |
| 439 | ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords); | 478 | ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords); |
| 440 | } else { | 479 | } else { |
| 441 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, | 480 | ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod); |
| 442 | CoordsCastToInt(coords, info), lod); | ||
| 443 | } | 481 | } |
| 444 | } | 482 | } |
| 445 | return; | 483 | return; |
| 446 | } | 484 | } |
| 485 | if (!ms.empty()) { | ||
| 486 | throw NotImplementedException("EmitImageFetch Sparse MSAA samples"); | ||
| 487 | } | ||
| 447 | if (!offset.empty()) { | 488 | if (!offset.empty()) { |
| 448 | ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));", | 489 | ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));", |
| 449 | *sparse_inst, texture, CastToIntVec(coords, info), lod, | 490 | *sparse_inst, texture, CastToIntVec(coords, info), lod, |
| @@ -455,29 +496,36 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 455 | } | 496 | } |
| 456 | 497 | ||
| 457 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 498 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 458 | std::string_view lod) { | 499 | std::string_view lod, const IR::Value& skip_mips_val) { |
| 459 | const auto info{inst.Flags<IR::TextureInstInfo>()}; | 500 | const auto info{inst.Flags<IR::TextureInstInfo>()}; |
| 460 | const auto texture{Texture(ctx, info, index)}; | 501 | const auto texture{Texture(ctx, info, index)}; |
| 502 | const bool is_msaa{IsTextureMsaa(ctx, info)}; | ||
| 503 | const bool skip_mips{skip_mips_val.U1()}; | ||
| 504 | const auto mips{skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture)}; | ||
| 505 | if (is_msaa && !skip_mips) { | ||
| 506 | throw NotImplementedException("EmitImageQueryDimensions MSAA QueryLevels"); | ||
| 507 | } | ||
| 508 | if (info.type == TextureType::Buffer && !skip_mips) { | ||
| 509 | throw NotImplementedException("EmitImageQueryDimensions TextureType::Buffer QueryLevels"); | ||
| 510 | } | ||
| 511 | const bool uses_lod{!is_msaa && info.type != TextureType::Buffer}; | ||
| 512 | const auto lod_str{uses_lod ? fmt::format(",int({})", lod) : ""}; | ||
| 461 | switch (info.type) { | 513 | switch (info.type) { |
| 462 | case TextureType::Color1D: | 514 | case TextureType::Color1D: |
| 463 | return ctx.AddU32x4( | 515 | return ctx.AddU32x4("{}=uvec4(uint(textureSize({}{})),0u,0u,{});", inst, texture, lod_str, |
| 464 | "{}=uvec4(uint(textureSize({},int({}))),0u,0u,uint(textureQueryLevels({})));", inst, | 516 | mips); |
| 465 | texture, lod, texture); | ||
| 466 | case TextureType::ColorArray1D: | 517 | case TextureType::ColorArray1D: |
| 467 | case TextureType::Color2D: | 518 | case TextureType::Color2D: |
| 468 | case TextureType::ColorCube: | 519 | case TextureType::ColorCube: |
| 469 | case TextureType::Color2DRect: | 520 | case TextureType::Color2DRect: |
| 470 | return ctx.AddU32x4( | 521 | return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({}{})),0u,{});", inst, texture, lod_str, |
| 471 | "{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst, | 522 | mips); |
| 472 | texture, lod, texture); | ||
| 473 | case TextureType::ColorArray2D: | 523 | case TextureType::ColorArray2D: |
| 474 | case TextureType::Color3D: | 524 | case TextureType::Color3D: |
| 475 | case TextureType::ColorArrayCube: | 525 | case TextureType::ColorArrayCube: |
| 476 | return ctx.AddU32x4( | 526 | return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({}{})),{});", inst, texture, lod_str, mips); |
| 477 | "{}=uvec4(uvec3(textureSize({},int({}))),uint(textureQueryLevels({})));", inst, texture, | ||
| 478 | lod, texture); | ||
| 479 | case TextureType::Buffer: | 527 | case TextureType::Buffer: |
| 480 | throw NotImplementedException("EmitImageQueryDimensions Texture buffers"); | 528 | return ctx.AddU32x4("{}=uvec4(uint(textureSize({})),0u,0u,{});", inst, texture, mips); |
| 481 | } | 529 | } |
| 482 | throw LogicError("Unspecified image type {}", info.type.Value()); | 530 | throw LogicError("Unspecified image type {}", info.type.Value()); |
| 483 | } | 531 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index 4151c89de..8d0a65047 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h | |||
| @@ -231,7 +231,6 @@ void EmitSelectF64(EmitContext& ctx, IR::Inst& inst, std::string_view cond, | |||
| 231 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); | 231 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); |
| 232 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 232 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 233 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 233 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 234 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||
| 235 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); | 234 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); |
| 236 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 235 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 237 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 236 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| @@ -655,7 +654,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 655 | std::string_view coords, std::string_view offset, std::string_view lod, | 654 | std::string_view coords, std::string_view offset, std::string_view lod, |
| 656 | std::string_view ms); | 655 | std::string_view ms); |
| 657 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 656 | void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 658 | std::string_view lod); | 657 | std::string_view lod, const IR::Value& skip_mips); |
| 659 | void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 658 | void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| 660 | std::string_view coords); | 659 | std::string_view coords); |
| 661 | void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 660 | void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 5d01ec0cd..9ff4028c2 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -61,24 +61,28 @@ std::string OutputDecorator(Stage stage, u32 size) { | |||
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | std::string_view SamplerType(TextureType type, bool is_depth) { | 64 | std::string_view DepthSamplerType(TextureType type) { |
| 65 | if (is_depth) { | 65 | switch (type) { |
| 66 | switch (type) { | 66 | case TextureType::Color1D: |
| 67 | case TextureType::Color1D: | 67 | return "sampler1DShadow"; |
| 68 | return "sampler1DShadow"; | 68 | case TextureType::ColorArray1D: |
| 69 | case TextureType::ColorArray1D: | 69 | return "sampler1DArrayShadow"; |
| 70 | return "sampler1DArrayShadow"; | 70 | case TextureType::Color2D: |
| 71 | case TextureType::Color2D: | 71 | return "sampler2DShadow"; |
| 72 | return "sampler2DShadow"; | 72 | case TextureType::ColorArray2D: |
| 73 | case TextureType::ColorArray2D: | 73 | return "sampler2DArrayShadow"; |
| 74 | return "sampler2DArrayShadow"; | 74 | case TextureType::ColorCube: |
| 75 | case TextureType::ColorCube: | 75 | return "samplerCubeShadow"; |
| 76 | return "samplerCubeShadow"; | 76 | case TextureType::ColorArrayCube: |
| 77 | case TextureType::ColorArrayCube: | 77 | return "samplerCubeArrayShadow"; |
| 78 | return "samplerCubeArrayShadow"; | 78 | default: |
| 79 | default: | 79 | throw NotImplementedException("Texture type: {}", type); |
| 80 | throw NotImplementedException("Texture type: {}", type); | 80 | } |
| 81 | } | 81 | } |
| 82 | |||
| 83 | std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) { | ||
| 84 | if (is_multisample) { | ||
| 85 | ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D); | ||
| 82 | } | 86 | } |
| 83 | switch (type) { | 87 | switch (type) { |
| 84 | case TextureType::Color1D: | 88 | case TextureType::Color1D: |
| @@ -87,9 +91,9 @@ std::string_view SamplerType(TextureType type, bool is_depth) { | |||
| 87 | return "sampler1DArray"; | 91 | return "sampler1DArray"; |
| 88 | case TextureType::Color2D: | 92 | case TextureType::Color2D: |
| 89 | case TextureType::Color2DRect: | 93 | case TextureType::Color2DRect: |
| 90 | return "sampler2D"; | 94 | return is_multisample ? "sampler2DMS" : "sampler2D"; |
| 91 | case TextureType::ColorArray2D: | 95 | case TextureType::ColorArray2D: |
| 92 | return "sampler2DArray"; | 96 | return is_multisample ? "sampler2DMSArray" : "sampler2DArray"; |
| 93 | case TextureType::Color3D: | 97 | case TextureType::Color3D: |
| 94 | return "sampler3D"; | 98 | return "sampler3D"; |
| 95 | case TextureType::ColorCube: | 99 | case TextureType::ColorCube: |
| @@ -306,12 +310,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile | |||
| 306 | if (runtime_info.force_early_z) { | 310 | if (runtime_info.force_early_z) { |
| 307 | header += "layout(early_fragment_tests)in;"; | 311 | header += "layout(early_fragment_tests)in;"; |
| 308 | } | 312 | } |
| 309 | if (info.uses_sample_id) { | ||
| 310 | header += "in int gl_SampleID;"; | ||
| 311 | } | ||
| 312 | if (info.stores_sample_mask) { | ||
| 313 | header += "out int gl_SampleMask[];"; | ||
| 314 | } | ||
| 315 | break; | 313 | break; |
| 316 | case Stage::Compute: | 314 | case Stage::Compute: |
| 317 | stage_name = "cs"; | 315 | stage_name = "cs"; |
| @@ -481,7 +479,7 @@ void EmitContext::DefineGenericOutput(size_t index, u32 invocations) { | |||
| 481 | const u32 remainder{4 - element}; | 479 | const u32 remainder{4 - element}; |
| 482 | const TransformFeedbackVarying* xfb_varying{}; | 480 | const TransformFeedbackVarying* xfb_varying{}; |
| 483 | const size_t xfb_varying_index{base_index + element}; | 481 | const size_t xfb_varying_index{base_index + element}; |
| 484 | if (xfb_varying_index < runtime_info.xfb_varyings.size()) { | 482 | if (xfb_varying_index < runtime_info.xfb_count) { |
| 485 | xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; | 483 | xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; |
| 486 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | 484 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; |
| 487 | } | 485 | } |
| @@ -677,7 +675,7 @@ void EmitContext::SetupTextures(Bindings& bindings) { | |||
| 677 | texture_buffers.reserve(info.texture_buffer_descriptors.size()); | 675 | texture_buffers.reserve(info.texture_buffer_descriptors.size()); |
| 678 | for (const auto& desc : info.texture_buffer_descriptors) { | 676 | for (const auto& desc : info.texture_buffer_descriptors) { |
| 679 | texture_buffers.push_back({bindings.texture, desc.count}); | 677 | texture_buffers.push_back({bindings.texture, desc.count}); |
| 680 | const auto sampler_type{SamplerType(TextureType::Buffer, false)}; | 678 | const auto sampler_type{ColorSamplerType(TextureType::Buffer)}; |
| 681 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; | 679 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; |
| 682 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, | 680 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, |
| 683 | sampler_type, bindings.texture, array_decorator); | 681 | sampler_type, bindings.texture, array_decorator); |
| @@ -686,7 +684,8 @@ void EmitContext::SetupTextures(Bindings& bindings) { | |||
| 686 | textures.reserve(info.texture_descriptors.size()); | 684 | textures.reserve(info.texture_descriptors.size()); |
| 687 | for (const auto& desc : info.texture_descriptors) { | 685 | for (const auto& desc : info.texture_descriptors) { |
| 688 | textures.push_back({bindings.texture, desc.count}); | 686 | textures.push_back({bindings.texture, desc.count}); |
| 689 | const auto sampler_type{SamplerType(desc.type, desc.is_depth)}; | 687 | const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type) |
| 688 | : ColorSamplerType(desc.type, desc.is_multisample)}; | ||
| 690 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; | 689 | const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; |
| 691 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, | 690 | header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, |
| 692 | sampler_type, bindings.texture, array_decorator); | 691 | sampler_type, bindings.texture, array_decorator); |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.h b/src/shader_recompiler/backend/glsl/glsl_emit_context.h index dfd10ac28..7587f7bab 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.h +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.h | |||
| @@ -49,7 +49,7 @@ public: | |||
| 49 | void Add(const char* format_str, IR::Inst& inst, Args&&... args) { | 49 | void Add(const char* format_str, IR::Inst& inst, Args&&... args) { |
| 50 | const auto var_def{var_alloc.AddDefine(inst, type)}; | 50 | const auto var_def{var_alloc.AddDefine(inst, type)}; |
| 51 | if (var_def.empty()) { | 51 | if (var_def.empty()) { |
| 52 | // skip assigment. | 52 | // skip assignment. |
| 53 | code += fmt::format(fmt::runtime(format_str + 3), std::forward<Args>(args)...); | 53 | code += fmt::format(fmt::runtime(format_str + 3), std::forward<Args>(args)...); |
| 54 | } else { | 54 | } else { |
| 55 | code += fmt::format(fmt::runtime(format_str), var_def, std::forward<Args>(args)...); | 55 | code += fmt::format(fmt::runtime(format_str), var_def, std::forward<Args>(args)...); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 0f86a8004..34592a01f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -387,7 +387,7 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr | |||
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) { | 389 | void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) { |
| 390 | if (ctx.runtime_info.xfb_varyings.empty()) { | 390 | if (ctx.runtime_info.xfb_count == 0) { |
| 391 | return; | 391 | return; |
| 392 | } | 392 | } |
| 393 | ctx.AddCapability(spv::Capability::TransformFeedback); | 393 | ctx.AddCapability(spv::Capability::TransformFeedback); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 4b3043b65..0ce73f289 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp | |||
| @@ -69,6 +69,11 @@ Id StorageAtomicU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& | |||
| 69 | Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, | 69 | Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, |
| 70 | Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id), | 70 | Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id), |
| 71 | Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { | 71 | Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { |
| 72 | if (!ctx.profile.support_descriptor_aliasing) { | ||
| 73 | LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic."); | ||
| 74 | return ctx.ConstantNull(ctx.U64); | ||
| 75 | } | ||
| 76 | |||
| 72 | if (ctx.profile.support_int64_atomics) { | 77 | if (ctx.profile.support_int64_atomics) { |
| 73 | const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64, | 78 | const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64, |
| 74 | binding, offset, sizeof(u64))}; | 79 | binding, offset, sizeof(u64))}; |
| @@ -86,6 +91,11 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& | |||
| 86 | 91 | ||
| 87 | Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, | 92 | Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, |
| 88 | Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { | 93 | Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { |
| 94 | if (!ctx.profile.support_descriptor_aliasing) { | ||
| 95 | LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic."); | ||
| 96 | return ctx.ConstantNull(ctx.U32[2]); | ||
| 97 | } | ||
| 98 | |||
| 89 | LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic"); | 99 | LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic"); |
| 90 | const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2, | 100 | const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2, |
| 91 | binding, offset, sizeof(u32[2]))}; | 101 | binding, offset, sizeof(u32[2]))}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp index 50daacd95..c4ca28d11 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp | |||
| @@ -18,10 +18,6 @@ void EmitBitCastU64F64(EmitContext&) { | |||
| 18 | throw NotImplementedException("SPIR-V Instruction"); | 18 | throw NotImplementedException("SPIR-V Instruction"); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void EmitBitCastS32F32(EmitContext&) { | ||
| 22 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 23 | } | ||
| 24 | |||
| 25 | void EmitBitCastF16U16(EmitContext&) { | 21 | void EmitBitCastF16U16(EmitContext&) { |
| 26 | throw NotImplementedException("SPIR-V Instruction"); | 22 | throw NotImplementedException("SPIR-V Instruction"); |
| 27 | } | 23 | } |
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 0cd87a48f..2868fc57d 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 | |||
| @@ -10,27 +10,6 @@ | |||
| 10 | 10 | ||
| 11 | namespace Shader::Backend::SPIRV { | 11 | namespace Shader::Backend::SPIRV { |
| 12 | namespace { | 12 | namespace { |
| 13 | struct AttrInfo { | ||
| 14 | Id pointer; | ||
| 15 | Id id; | ||
| 16 | bool needs_cast; | ||
| 17 | }; | ||
| 18 | |||
| 19 | std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | ||
| 20 | const AttributeType type{ctx.runtime_info.generic_input_types.at(index)}; | ||
| 21 | switch (type) { | ||
| 22 | case AttributeType::Float: | ||
| 23 | return AttrInfo{ctx.input_f32, ctx.F32[1], false}; | ||
| 24 | case AttributeType::UnsignedInt: | ||
| 25 | return AttrInfo{ctx.input_u32, ctx.U32[1], true}; | ||
| 26 | case AttributeType::SignedInt: | ||
| 27 | return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; | ||
| 28 | case AttributeType::Disabled: | ||
| 29 | return std::nullopt; | ||
| 30 | } | ||
| 31 | throw InvalidArgument("Invalid attribute type {}", type); | ||
| 32 | } | ||
| 33 | |||
| 34 | template <typename... Args> | 13 | template <typename... Args> |
| 35 | Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) { | 14 | Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) { |
| 36 | switch (ctx.stage) { | 15 | switch (ctx.stage) { |
| @@ -302,15 +281,26 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 302 | const u32 element{static_cast<u32>(attr) % 4}; | 281 | const u32 element{static_cast<u32>(attr) % 4}; |
| 303 | if (IR::IsGeneric(attr)) { | 282 | if (IR::IsGeneric(attr)) { |
| 304 | const u32 index{IR::GenericAttributeIndex(attr)}; | 283 | const u32 index{IR::GenericAttributeIndex(attr)}; |
| 305 | const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; | 284 | const auto& generic{ctx.input_generics.at(index)}; |
| 306 | if (!type || !ctx.runtime_info.previous_stage_stores.Generic(index, element)) { | 285 | if (!ValidId(generic.id)) { |
| 307 | // Attribute is disabled or varying component is not written | 286 | // Attribute is disabled or varying component is not written |
| 308 | return ctx.Const(element == 3 ? 1.0f : 0.0f); | 287 | return ctx.Const(element == 3 ? 1.0f : 0.0f); |
| 309 | } | 288 | } |
| 310 | const Id generic_id{ctx.input_generics.at(index)}; | 289 | const Id pointer{ |
| 311 | const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))}; | 290 | AttrPointer(ctx, generic.pointer_type, vertex, generic.id, ctx.Const(element))}; |
| 312 | const Id value{ctx.OpLoad(type->id, pointer)}; | 291 | const Id value{ctx.OpLoad(generic.component_type, pointer)}; |
| 313 | return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; | 292 | return [&ctx, generic, value]() { |
| 293 | switch (generic.load_op) { | ||
| 294 | case InputGenericLoadOp::Bitcast: | ||
| 295 | return ctx.OpBitcast(ctx.F32[1], value); | ||
| 296 | case InputGenericLoadOp::SToF: | ||
| 297 | return ctx.OpConvertSToF(ctx.F32[1], value); | ||
| 298 | case InputGenericLoadOp::UToF: | ||
| 299 | return ctx.OpConvertUToF(ctx.F32[1], value); | ||
| 300 | default: | ||
| 301 | return value; | ||
| 302 | }; | ||
| 303 | }(); | ||
| 314 | } | 304 | } |
| 315 | switch (attr) { | 305 | switch (attr) { |
| 316 | case IR::Attribute::PrimitiveId: | 306 | case IR::Attribute::PrimitiveId: |
| @@ -339,9 +329,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 339 | if (ctx.profile.support_vertex_instance_id) { | 329 | if (ctx.profile.support_vertex_instance_id) { |
| 340 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id)); | 330 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id)); |
| 341 | } else { | 331 | } else { |
| 342 | const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; | 332 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index)); |
| 343 | const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)}; | ||
| 344 | return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base)); | ||
| 345 | } | 333 | } |
| 346 | case IR::Attribute::BaseInstance: | 334 | case IR::Attribute::BaseInstance: |
| 347 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance)); | 335 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance)); |
| @@ -386,9 +374,7 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) { | |||
| 386 | if (ctx.profile.support_vertex_instance_id) { | 374 | if (ctx.profile.support_vertex_instance_id) { |
| 387 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | 375 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); |
| 388 | } else { | 376 | } else { |
| 389 | const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; | 377 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_index); |
| 390 | const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)}; | ||
| 391 | return ctx.OpISub(ctx.U32[1], index, base); | ||
| 392 | } | 378 | } |
| 393 | case IR::Attribute::BaseInstance: | 379 | case IR::Attribute::BaseInstance: |
| 394 | return ctx.OpLoad(ctx.U32[1], ctx.base_instance); | 380 | return ctx.OpLoad(ctx.U32[1], ctx.base_instance); |
| @@ -473,7 +459,8 @@ void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { | |||
| 473 | } | 459 | } |
| 474 | 460 | ||
| 475 | void EmitSetSampleMask(EmitContext& ctx, Id value) { | 461 | void EmitSetSampleMask(EmitContext& ctx, Id value) { |
| 476 | ctx.OpStore(ctx.sample_mask, value); | 462 | const Id pointer{ctx.OpAccessChain(ctx.output_u32, ctx.sample_mask, ctx.u32_zero_value)}; |
| 463 | ctx.OpStore(pointer, value); | ||
| 477 | } | 464 | } |
| 478 | 465 | ||
| 479 | void EmitSetFragDepth(EmitContext& ctx, Id value) { | 466 | void EmitSetFragDepth(EmitContext& ctx, Id value) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index fb5799c42..7d901c04b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -201,6 +201,13 @@ Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | |||
| 201 | } | 201 | } |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) { | ||
| 205 | if (info.type == TextureType::Buffer) { | ||
| 206 | return false; | ||
| 207 | } | ||
| 208 | return ctx.textures.at(info.descriptor_index).is_multisample; | ||
| 209 | } | ||
| 210 | |||
| 204 | Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { | 211 | Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { |
| 205 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 212 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 206 | if (info.relaxed_precision != 0) { | 213 | if (info.relaxed_precision != 0) { |
| @@ -254,6 +261,30 @@ Id BitTest(EmitContext& ctx, Id mask, Id bit) { | |||
| 254 | const Id bit_value{ctx.OpBitwiseAnd(ctx.U32[1], shifted, ctx.Const(1u))}; | 261 | const Id bit_value{ctx.OpBitwiseAnd(ctx.U32[1], shifted, ctx.Const(1u))}; |
| 255 | return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value); | 262 | return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value); |
| 256 | } | 263 | } |
| 264 | |||
| 265 | Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info, Id texture, | ||
| 266 | Id coords) { | ||
| 267 | // Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on | ||
| 268 | // AMD hardware as on Maxwell or other Nvidia architectures. | ||
| 269 | const auto calculate_coords{[&](size_t dim) { | ||
| 270 | const Id nudge{ctx.Const(0x1p-9f)}; | ||
| 271 | const Id image_size{ctx.OpImageQuerySizeLod(ctx.U32[dim], texture, ctx.u32_zero_value)}; | ||
| 272 | Id offset{dim == 2 ? ctx.ConstantComposite(ctx.F32[dim], nudge, nudge) | ||
| 273 | : ctx.ConstantComposite(ctx.F32[dim], nudge, nudge, ctx.f32_zero_value)}; | ||
| 274 | offset = ctx.OpFDiv(ctx.F32[dim], offset, ctx.OpConvertUToF(ctx.F32[dim], image_size)); | ||
| 275 | return ctx.OpFAdd(ctx.F32[dim], coords, offset); | ||
| 276 | }}; | ||
| 277 | switch (info.type) { | ||
| 278 | case TextureType::Color2D: | ||
| 279 | case TextureType::Color2DRect: | ||
| 280 | return calculate_coords(2); | ||
| 281 | case TextureType::ColorArray2D: | ||
| 282 | case TextureType::ColorCube: | ||
| 283 | return calculate_coords(3); | ||
| 284 | default: | ||
| 285 | return coords; | ||
| 286 | } | ||
| 287 | } | ||
| 257 | } // Anonymous namespace | 288 | } // Anonymous namespace |
| 258 | 289 | ||
| 259 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { | 290 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { |
| @@ -416,6 +447,9 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id | |||
| 416 | const IR::Value& offset, const IR::Value& offset2) { | 447 | const IR::Value& offset, const IR::Value& offset2) { |
| 417 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 448 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 418 | const ImageOperands operands(ctx, offset, offset2); | 449 | const ImageOperands operands(ctx, offset, offset2); |
| 450 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 451 | coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); | ||
| 452 | } | ||
| 419 | return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, | 453 | return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, |
| 420 | ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component), | 454 | ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component), |
| 421 | operands.MaskOptional(), operands.Span()); | 455 | operands.MaskOptional(), operands.Span()); |
| @@ -425,6 +459,9 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | |||
| 425 | const IR::Value& offset, const IR::Value& offset2, Id dref) { | 459 | const IR::Value& offset, const IR::Value& offset2, Id dref) { |
| 426 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 460 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 427 | const ImageOperands operands(ctx, offset, offset2); | 461 | const ImageOperands operands(ctx, offset, offset2); |
| 462 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 463 | coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); | ||
| 464 | } | ||
| 428 | return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, | 465 | return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, |
| 429 | ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(), | 466 | ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(), |
| 430 | operands.Span()); | 467 | operands.Span()); |
| @@ -436,34 +473,42 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c | |||
| 436 | if (info.type == TextureType::Buffer) { | 473 | if (info.type == TextureType::Buffer) { |
| 437 | lod = Id{}; | 474 | lod = Id{}; |
| 438 | } | 475 | } |
| 476 | if (Sirit::ValidId(ms)) { | ||
| 477 | // This image is multisampled, lod must be implicit | ||
| 478 | lod = Id{}; | ||
| 479 | } | ||
| 439 | const ImageOperands operands(offset, lod, ms); | 480 | const ImageOperands operands(offset, lod, ms); |
| 440 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], | 481 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], |
| 441 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); | 482 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); |
| 442 | } | 483 | } |
| 443 | 484 | ||
| 444 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { | 485 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, |
| 486 | const IR::Value& skip_mips_val) { | ||
| 445 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 487 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 446 | const Id image{TextureImage(ctx, info, index)}; | 488 | const Id image{TextureImage(ctx, info, index)}; |
| 447 | const Id zero{ctx.u32_zero_value}; | 489 | const Id zero{ctx.u32_zero_value}; |
| 448 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | 490 | const bool skip_mips{skip_mips_val.U1()}; |
| 491 | const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | ||
| 492 | const bool is_msaa{IsTextureMsaa(ctx, info)}; | ||
| 493 | const bool uses_lod{!is_msaa && info.type != TextureType::Buffer}; | ||
| 494 | const auto query{[&](Id type) { | ||
| 495 | return uses_lod ? ctx.OpImageQuerySizeLod(type, image, lod) | ||
| 496 | : ctx.OpImageQuerySize(type, image); | ||
| 497 | }}; | ||
| 449 | switch (info.type) { | 498 | switch (info.type) { |
| 450 | case TextureType::Color1D: | 499 | case TextureType::Color1D: |
| 451 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), | 500 | return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips()); |
| 452 | zero, zero, mips()); | ||
| 453 | case TextureType::ColorArray1D: | 501 | case TextureType::ColorArray1D: |
| 454 | case TextureType::Color2D: | 502 | case TextureType::Color2D: |
| 455 | case TextureType::ColorCube: | 503 | case TextureType::ColorCube: |
| 456 | case TextureType::Color2DRect: | 504 | case TextureType::Color2DRect: |
| 457 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), | 505 | return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[2]), zero, mips()); |
| 458 | zero, mips()); | ||
| 459 | case TextureType::ColorArray2D: | 506 | case TextureType::ColorArray2D: |
| 460 | case TextureType::Color3D: | 507 | case TextureType::Color3D: |
| 461 | case TextureType::ColorArrayCube: | 508 | case TextureType::ColorArrayCube: |
| 462 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), | 509 | return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[3]), mips()); |
| 463 | mips()); | ||
| 464 | case TextureType::Buffer: | 510 | case TextureType::Buffer: |
| 465 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySize(ctx.U32[1], image), zero, | 511 | return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips()); |
| 466 | zero, mips()); | ||
| 467 | } | 512 | } |
| 468 | throw LogicError("Unspecified image type {}", info.type.Value()); | 513 | throw LogicError("Unspecified image type {}", info.type.Value()); |
| 469 | } | 514 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index e31cdc5e8..a440b557d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -179,7 +179,6 @@ Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value); | |||
| 179 | void EmitBitCastU16F16(EmitContext& ctx); | 179 | void EmitBitCastU16F16(EmitContext& ctx); |
| 180 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); | 180 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); |
| 181 | void EmitBitCastU64F64(EmitContext& ctx); | 181 | void EmitBitCastU64F64(EmitContext& ctx); |
| 182 | void EmitBitCastS32F32(EmitContext& ctx); | ||
| 183 | void EmitBitCastF16U16(EmitContext&); | 182 | void EmitBitCastF16U16(EmitContext&); |
| 184 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); | 183 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); |
| 185 | void EmitBitCastF64U64(EmitContext& ctx); | 184 | void EmitBitCastF64U64(EmitContext& ctx); |
| @@ -540,7 +539,8 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | |||
| 540 | const IR::Value& offset, const IR::Value& offset2, Id dref); | 539 | const IR::Value& offset, const IR::Value& offset2, Id dref); |
| 541 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, | 540 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| 542 | Id lod, Id ms); | 541 | Id lod, Id ms); |
| 543 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod); | 542 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, |
| 543 | const IR::Value& skip_mips); | ||
| 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
| 545 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 545 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 546 | Id derivates, Id offset, Id lod_clamp); | 546 | Id derivates, Id offset, Id lod_clamp); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index c5db19d09..77ff8c573 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp | |||
| @@ -17,7 +17,22 @@ Id GetThreadId(EmitContext& ctx) { | |||
| 17 | Id WarpExtract(EmitContext& ctx, Id value) { | 17 | Id WarpExtract(EmitContext& ctx, Id value) { |
| 18 | const Id thread_id{GetThreadId(ctx)}; | 18 | const Id thread_id{GetThreadId(ctx)}; |
| 19 | const Id local_index{ctx.OpShiftRightArithmetic(ctx.U32[1], thread_id, ctx.Const(5U))}; | 19 | const Id local_index{ctx.OpShiftRightArithmetic(ctx.U32[1], thread_id, ctx.Const(5U))}; |
| 20 | return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index); | 20 | if (ctx.profile.has_broken_spirv_subgroup_mask_vector_extract_dynamic) { |
| 21 | const Id c0_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(0U)), | ||
| 22 | ctx.OpCompositeExtract(ctx.U32[1], value, 0U), ctx.Const(0U))}; | ||
| 23 | const Id c1_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(1U)), | ||
| 24 | ctx.OpCompositeExtract(ctx.U32[1], value, 1U), ctx.Const(0U))}; | ||
| 25 | const Id c2_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(2U)), | ||
| 26 | ctx.OpCompositeExtract(ctx.U32[1], value, 2U), ctx.Const(0U))}; | ||
| 27 | const Id c3_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(3U)), | ||
| 28 | ctx.OpCompositeExtract(ctx.U32[1], value, 3U), ctx.Const(0U))}; | ||
| 29 | const Id c0_or_c1{ctx.OpBitwiseOr(ctx.U32[1], c0_sel, c1_sel)}; | ||
| 30 | const Id c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c2_sel, c3_sel)}; | ||
| 31 | const Id c0_or_c1_or_c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c0_or_c1, c2_or_c3)}; | ||
| 32 | return c0_or_c1_or_c2_or_c3; | ||
| 33 | } else { | ||
| 34 | return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index); | ||
| 35 | } | ||
| 21 | } | 36 | } |
| 22 | 37 | ||
| 23 | Id LoadMask(EmitContext& ctx, Id mask) { | 38 | Id LoadMask(EmitContext& ctx, Id mask) { |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index a0c155fdb..bec5db173 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -25,16 +25,11 @@ enum class Operation { | |||
| 25 | FPMax, | 25 | FPMax, |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | struct AttrInfo { | ||
| 29 | Id pointer; | ||
| 30 | Id id; | ||
| 31 | bool needs_cast; | ||
| 32 | }; | ||
| 33 | |||
| 34 | Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { | 28 | Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { |
| 35 | const spv::ImageFormat format{spv::ImageFormat::Unknown}; | 29 | const spv::ImageFormat format{spv::ImageFormat::Unknown}; |
| 36 | const Id type{ctx.F32[1]}; | 30 | const Id type{ctx.F32[1]}; |
| 37 | const bool depth{desc.is_depth}; | 31 | const bool depth{desc.is_depth}; |
| 32 | const bool ms{desc.is_multisample}; | ||
| 38 | switch (desc.type) { | 33 | switch (desc.type) { |
| 39 | case TextureType::Color1D: | 34 | case TextureType::Color1D: |
| 40 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); | 35 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); |
| @@ -42,9 +37,9 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { | |||
| 42 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); | 37 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); |
| 43 | case TextureType::Color2D: | 38 | case TextureType::Color2D: |
| 44 | case TextureType::Color2DRect: | 39 | case TextureType::Color2DRect: |
| 45 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format); | 40 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, ms, 1, format); |
| 46 | case TextureType::ColorArray2D: | 41 | case TextureType::ColorArray2D: |
| 47 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format); | 42 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, ms, 1, format); |
| 48 | case TextureType::Color3D: | 43 | case TextureType::Color3D: |
| 49 | return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); | 44 | return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); |
| 50 | case TextureType::ColorCube: | 45 | case TextureType::ColorCube: |
| @@ -165,7 +160,7 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo | |||
| 165 | const u32 remainder{4 - element}; | 160 | const u32 remainder{4 - element}; |
| 166 | const TransformFeedbackVarying* xfb_varying{}; | 161 | const TransformFeedbackVarying* xfb_varying{}; |
| 167 | const size_t xfb_varying_index{base_attr_index + element}; | 162 | const size_t xfb_varying_index{base_attr_index + element}; |
| 168 | if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) { | 163 | if (xfb_varying_index < ctx.runtime_info.xfb_count) { |
| 169 | xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; | 164 | xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; |
| 170 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | 165 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; |
| 171 | } | 166 | } |
| @@ -205,23 +200,37 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) { | |||
| 205 | return ctx.TypeVector(ctx.TypeInt(32, true), 4); | 200 | return ctx.TypeVector(ctx.TypeInt(32, true), 4); |
| 206 | case AttributeType::UnsignedInt: | 201 | case AttributeType::UnsignedInt: |
| 207 | return ctx.U32[4]; | 202 | return ctx.U32[4]; |
| 203 | case AttributeType::SignedScaled: | ||
| 204 | return ctx.profile.support_scaled_attributes ? ctx.F32[4] | ||
| 205 | : ctx.TypeVector(ctx.TypeInt(32, true), 4); | ||
| 206 | case AttributeType::UnsignedScaled: | ||
| 207 | return ctx.profile.support_scaled_attributes ? ctx.F32[4] : ctx.U32[4]; | ||
| 208 | case AttributeType::Disabled: | 208 | case AttributeType::Disabled: |
| 209 | break; | 209 | break; |
| 210 | } | 210 | } |
| 211 | throw InvalidArgument("Invalid attribute type {}", type); | 211 | throw InvalidArgument("Invalid attribute type {}", type); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | 214 | InputGenericInfo GetAttributeInfo(EmitContext& ctx, AttributeType type, Id id) { |
| 215 | const AttributeType type{ctx.runtime_info.generic_input_types.at(index)}; | ||
| 216 | switch (type) { | 215 | switch (type) { |
| 217 | case AttributeType::Float: | 216 | case AttributeType::Float: |
| 218 | return AttrInfo{ctx.input_f32, ctx.F32[1], false}; | 217 | return InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None}; |
| 219 | case AttributeType::UnsignedInt: | 218 | case AttributeType::UnsignedInt: |
| 220 | return AttrInfo{ctx.input_u32, ctx.U32[1], true}; | 219 | return InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::Bitcast}; |
| 221 | case AttributeType::SignedInt: | 220 | case AttributeType::SignedInt: |
| 222 | return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; | 221 | return InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true), |
| 222 | InputGenericLoadOp::Bitcast}; | ||
| 223 | case AttributeType::SignedScaled: | ||
| 224 | return ctx.profile.support_scaled_attributes | ||
| 225 | ? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None} | ||
| 226 | : InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true), | ||
| 227 | InputGenericLoadOp::SToF}; | ||
| 228 | case AttributeType::UnsignedScaled: | ||
| 229 | return ctx.profile.support_scaled_attributes | ||
| 230 | ? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None} | ||
| 231 | : InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::UToF}; | ||
| 223 | case AttributeType::Disabled: | 232 | case AttributeType::Disabled: |
| 224 | return std::nullopt; | 233 | return InputGenericInfo{}; |
| 225 | } | 234 | } |
| 226 | throw InvalidArgument("Invalid attribute type {}", type); | 235 | throw InvalidArgument("Invalid attribute type {}", type); |
| 227 | } | 236 | } |
| @@ -745,18 +754,29 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 745 | continue; | 754 | continue; |
| 746 | } | 755 | } |
| 747 | AddLabel(labels[label_index]); | 756 | AddLabel(labels[label_index]); |
| 748 | const auto type{AttrTypes(*this, static_cast<u32>(index))}; | 757 | const auto& generic{input_generics.at(index)}; |
| 749 | if (!type) { | 758 | const Id generic_id{generic.id}; |
| 759 | if (!ValidId(generic_id)) { | ||
| 750 | OpReturnValue(Const(0.0f)); | 760 | OpReturnValue(Const(0.0f)); |
| 751 | ++label_index; | 761 | ++label_index; |
| 752 | continue; | 762 | continue; |
| 753 | } | 763 | } |
| 754 | const Id generic_id{input_generics.at(index)}; | 764 | const Id pointer{ |
| 755 | const Id pointer{is_array | 765 | is_array ? OpAccessChain(generic.pointer_type, generic_id, vertex, masked_index) |
| 756 | ? OpAccessChain(type->pointer, generic_id, vertex, masked_index) | 766 | : OpAccessChain(generic.pointer_type, generic_id, masked_index)}; |
| 757 | : OpAccessChain(type->pointer, generic_id, masked_index)}; | 767 | const Id value{OpLoad(generic.component_type, pointer)}; |
| 758 | const Id value{OpLoad(type->id, pointer)}; | 768 | const Id result{[this, generic, value]() { |
| 759 | const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value}; | 769 | switch (generic.load_op) { |
| 770 | case InputGenericLoadOp::Bitcast: | ||
| 771 | return OpBitcast(F32[1], value); | ||
| 772 | case InputGenericLoadOp::SToF: | ||
| 773 | return OpConvertSToF(F32[1], value); | ||
| 774 | case InputGenericLoadOp::UToF: | ||
| 775 | return OpConvertUToF(F32[1], value); | ||
| 776 | default: | ||
| 777 | return value; | ||
| 778 | }; | ||
| 779 | }()}; | ||
| 760 | OpReturnValue(result); | 780 | OpReturnValue(result); |
| 761 | ++label_index; | 781 | ++label_index; |
| 762 | } | 782 | } |
| @@ -1287,6 +1307,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in | |||
| 1287 | .pointer_type = pointer_type, | 1307 | .pointer_type = pointer_type, |
| 1288 | .image_type = image_type, | 1308 | .image_type = image_type, |
| 1289 | .count = desc.count, | 1309 | .count = desc.count, |
| 1310 | .is_multisample = desc.is_multisample, | ||
| 1290 | }); | 1311 | }); |
| 1291 | if (profile.supported_spirv >= 0x00010400) { | 1312 | if (profile.supported_spirv >= 0x00010400) { |
| 1292 | interfaces.push_back(id); | 1313 | interfaces.push_back(id); |
| @@ -1455,7 +1476,7 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1455 | const Id id{DefineInput(*this, type, true)}; | 1476 | const Id id{DefineInput(*this, type, true)}; |
| 1456 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 1477 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| 1457 | Name(id, fmt::format("in_attr{}", index)); | 1478 | Name(id, fmt::format("in_attr{}", index)); |
| 1458 | input_generics[index] = id; | 1479 | input_generics[index] = GetAttributeInfo(*this, input_type, id); |
| 1459 | 1480 | ||
| 1460 | if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) { | 1481 | if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) { |
| 1461 | Decorate(id, spv::Decoration::PassthroughNV); | 1482 | Decorate(id, spv::Decoration::PassthroughNV); |
| @@ -1570,7 +1591,8 @@ void EmitContext::DefineOutputs(const IR::Program& program) { | |||
| 1570 | Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth); | 1591 | Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth); |
| 1571 | } | 1592 | } |
| 1572 | if (info.stores_sample_mask) { | 1593 | if (info.stores_sample_mask) { |
| 1573 | sample_mask = DefineOutput(*this, U32[1], std::nullopt); | 1594 | const Id array_type{TypeArray(U32[1], Const(1U))}; |
| 1595 | sample_mask = DefineOutput(*this, array_type, std::nullopt); | ||
| 1574 | Decorate(sample_mask, spv::Decoration::BuiltIn, spv::BuiltIn::SampleMask); | 1596 | Decorate(sample_mask, spv::Decoration::BuiltIn, spv::BuiltIn::SampleMask); |
| 1575 | } | 1597 | } |
| 1576 | break; | 1598 | break; |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index dbc5c55b9..e63330f11 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -35,6 +35,7 @@ struct TextureDefinition { | |||
| 35 | Id pointer_type; | 35 | Id pointer_type; |
| 36 | Id image_type; | 36 | Id image_type; |
| 37 | u32 count; | 37 | u32 count; |
| 38 | bool is_multisample; | ||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | struct TextureBufferDefinition { | 41 | struct TextureBufferDefinition { |
| @@ -94,6 +95,20 @@ struct StorageDefinitions { | |||
| 94 | Id U32x4{}; | 95 | Id U32x4{}; |
| 95 | }; | 96 | }; |
| 96 | 97 | ||
| 98 | enum class InputGenericLoadOp { | ||
| 99 | None, | ||
| 100 | Bitcast, | ||
| 101 | SToF, | ||
| 102 | UToF, | ||
| 103 | }; | ||
| 104 | |||
| 105 | struct InputGenericInfo { | ||
| 106 | Id id; | ||
| 107 | Id pointer_type; | ||
| 108 | Id component_type; | ||
| 109 | InputGenericLoadOp load_op; | ||
| 110 | }; | ||
| 111 | |||
| 97 | struct GenericElementInfo { | 112 | struct GenericElementInfo { |
| 98 | Id id{}; | 113 | Id id{}; |
| 99 | u32 first_element{}; | 114 | u32 first_element{}; |
| @@ -282,7 +297,7 @@ public: | |||
| 282 | 297 | ||
| 283 | bool need_input_position_indirect{}; | 298 | bool need_input_position_indirect{}; |
| 284 | Id input_position{}; | 299 | Id input_position{}; |
| 285 | std::array<Id, 32> input_generics{}; | 300 | std::array<InputGenericInfo, 32> input_generics{}; |
| 286 | 301 | ||
| 287 | Id output_point_size{}; | 302 | Id output_point_size{}; |
| 288 | Id output_position{}; | 303 | Id output_position{}; |