mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-27 02:49:00 +02:00
[cmake] Allow proper unity builds
Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
3ce5463d2d
commit
eee06fba4b
73 changed files with 860 additions and 1012 deletions
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,14 +12,13 @@
|
|||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
constexpr std::string_view SWIZZLE{"xyzw"};
|
||||
void CompositeInsert(EmitContext& ctx, std::string_view result, std::string_view composite,
|
||||
std::string_view object, u32 index) {
|
||||
if (result == composite) {
|
||||
// The result is aliased with the composite
|
||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
||||
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||
} else {
|
||||
ctx.Add("{}={};{}.{}={};", result, composite, result, SWIZZLE[index], object);
|
||||
ctx.Add("{}={};{}.{}={};", result, composite, result, "xyzw"[index], object);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
|
@ -38,17 +40,17 @@ void EmitCompositeConstructU32x4(EmitContext& ctx, IR::Inst& inst, std::string_v
|
|||
|
||||
void EmitCompositeExtractU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeExtractU32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeExtractU32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddU32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddU32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeInsertU32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
|
|
@ -146,17 +148,17 @@ void EmitCompositeConstructF32x4(EmitContext& ctx, IR::Inst& inst, std::string_v
|
|||
|
||||
void EmitCompositeExtractF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeExtractF32x3(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeExtractF32x4(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
u32 index) {
|
||||
ctx.AddF32("{}={}.{};", inst, composite, SWIZZLE[index]);
|
||||
ctx.AddF32("{}={}.{};", inst, composite, "xyzw"[index]);
|
||||
}
|
||||
|
||||
void EmitCompositeInsertF32x2(EmitContext& ctx, IR::Inst& inst, std::string_view composite,
|
||||
|
|
@ -203,16 +205,16 @@ void EmitCompositeExtractF64x4([[maybe_unused]] EmitContext& ctx) {
|
|||
|
||||
void EmitCompositeInsertF64x2(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||
u32 index) {
|
||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
||||
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||
}
|
||||
|
||||
void EmitCompositeInsertF64x3(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||
u32 index) {
|
||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
||||
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||
}
|
||||
|
||||
void EmitCompositeInsertF64x4(EmitContext& ctx, std::string_view composite, std::string_view object,
|
||||
u32 index) {
|
||||
ctx.Add("{}.{}={};", composite, SWIZZLE[index], object);
|
||||
ctx.Add("{}.{}={};", composite, "xyzw"[index], object);
|
||||
}
|
||||
} // namespace Shader::Backend::GLSL
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -11,14 +14,13 @@
|
|||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
constexpr char SWIZZLE[]{"xyzw"};
|
||||
|
||||
u32 CbufIndex(u32 offset) {
|
||||
return (offset / 4) % 4;
|
||||
}
|
||||
|
||||
char OffsetSwizzle(u32 offset) {
|
||||
return SWIZZLE[CbufIndex(offset)];
|
||||
return "xyzw"[CbufIndex(offset)];
|
||||
}
|
||||
|
||||
bool IsInputArray(Stage stage) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -10,14 +13,13 @@
|
|||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
constexpr char cas_loop[]{"for(;;){{uint old_value={};uint "
|
||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||
"if(cas_result==old_value){{break;}}}}"};
|
||||
|
||||
void SsboWriteCas(EmitContext& ctx, const IR::Value& binding, std::string_view offset_var,
|
||||
std::string_view value, std::string_view bit_offset, u32 num_bits) {
|
||||
const auto ssbo{fmt::format("{}_ssbo{}[{}>>2]", ctx.stage_name, binding.U32(), offset_var)};
|
||||
ctx.Add(cas_loop, ssbo, ssbo, ssbo, value, bit_offset, num_bits);
|
||||
ctx.Add(
|
||||
"for(;;){{uint old_value={};uint "
|
||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||
"if(cas_result==old_value){{break;}}}}", ssbo, ssbo, ssbo, value, bit_offset, num_bits);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,14 +10,13 @@
|
|||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
constexpr char cas_loop[]{"for(;;){{uint old_value={};uint "
|
||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||
"if(cas_result==old_value){{break;}}}}"};
|
||||
|
||||
void SharedWriteCas(EmitContext& ctx, std::string_view offset, std::string_view value,
|
||||
std::string_view bit_offset, u32 num_bits) {
|
||||
const auto smem{fmt::format("smem[{}>>2]", offset)};
|
||||
ctx.Add(cas_loop, smem, smem, smem, value, bit_offset, num_bits);
|
||||
ctx.Add(
|
||||
"for(;;){{uint old_value={};uint "
|
||||
"cas_result=atomicCompSwap({},old_value,bitfieldInsert({},{},{},{}));"
|
||||
"if(cas_result==old_value){{break;}}}}", smem, smem, smem, value, bit_offset, num_bits);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
|
||||
Id DecorateNoContraction(EmitContext& ctx, IR::Inst* inst, Id op) {
|
||||
const auto flags{inst->Flags<IR::FpControl>()};
|
||||
if (flags.no_contraction) {
|
||||
ctx.Decorate(op, spv::Decoration::NoContraction);
|
||||
|
|
@ -61,27 +61,27 @@ Id EmitFPAbs64(EmitContext& ctx, Id value) {
|
|||
}
|
||||
|
||||
Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
||||
}
|
||||
|
||||
Id EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
||||
}
|
||||
|
||||
Id EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
||||
}
|
||||
|
||||
Id EmitFPMax32(EmitContext& ctx, Id a, Id b) {
|
||||
|
|
@ -101,15 +101,15 @@ Id EmitFPMin64(EmitContext& ctx, Id a, Id b) {
|
|||
}
|
||||
|
||||
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
||||
return DecorateNoContraction(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
||||
}
|
||||
|
||||
Id EmitFPNeg16(EmitContext& ctx, Id value) {
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
|
|||
return ctx.textures.at(info.descriptor_index).is_multisample;
|
||||
}
|
||||
|
||||
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
|
||||
Id DecorateRelaxedPrecision(EmitContext& ctx, IR::Inst* inst, Id sample) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
if (info.relaxed_precision != 0) {
|
||||
ctx.Decorate(sample, spv::Decoration::RelaxedPrecision);
|
||||
|
|
@ -256,14 +256,14 @@ Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx
|
|||
Id result_type, Args&&... args) {
|
||||
IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
|
||||
if (!sparse) {
|
||||
return Decorate(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
|
||||
return DecorateRelaxedPrecision(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
|
||||
}
|
||||
const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
|
||||
const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
|
||||
const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
|
||||
sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
|
||||
sparse->Invalidate();
|
||||
Decorate(ctx, inst, sample);
|
||||
DecorateRelaxedPrecision(ctx, inst, sample);
|
||||
return ctx.OpCompositeExtract(result_type, sample, 1U);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -12,7 +15,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
union Encoding {
|
||||
union EncodingIBTT {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> src_reg;
|
||||
|
|
@ -45,7 +48,7 @@ std::optional<u64> TrackLDC(Environment& env, Location block_begin, Location& po
|
|||
std::optional<u64> TrackSHL(Environment& env, Location block_begin, Location& pos,
|
||||
IR::Reg ldc_reg) {
|
||||
return Track(env, block_begin, pos, [ldc_reg](u64 insn, Opcode opcode) {
|
||||
const Encoding shl{insn};
|
||||
const EncodingIBTT shl{insn};
|
||||
return opcode == Opcode::SHL_imm && shl.dest_reg == ldc_reg;
|
||||
});
|
||||
}
|
||||
|
|
@ -53,7 +56,7 @@ std::optional<u64> TrackSHL(Environment& env, Location block_begin, Location& po
|
|||
std::optional<u64> TrackIMNMX(Environment& env, Location block_begin, Location& pos,
|
||||
IR::Reg shl_reg) {
|
||||
return Track(env, block_begin, pos, [shl_reg](u64 insn, Opcode opcode) {
|
||||
const Encoding imnmx{insn};
|
||||
const EncodingIBTT imnmx{insn};
|
||||
return opcode == Opcode::IMNMX_imm && imnmx.dest_reg == shl_reg;
|
||||
});
|
||||
}
|
||||
|
|
@ -66,8 +69,8 @@ std::optional<IndirectBranchTableInfo> TrackIndirectBranchTable(Environment& env
|
|||
if (brx_opcode != Opcode::BRX && brx_opcode != Opcode::JMX) {
|
||||
throw LogicError("Tracked instruction is not BRX or JMX");
|
||||
}
|
||||
const IR::Reg brx_reg{Encoding{brx_insn}.src_reg};
|
||||
const s32 brx_offset{static_cast<s32>(Encoding{brx_insn}.brx_offset)};
|
||||
const IR::Reg brx_reg{EncodingIBTT{brx_insn}.src_reg};
|
||||
const s32 brx_offset{static_cast<s32>(EncodingIBTT{brx_insn}.brx_offset)};
|
||||
|
||||
Location pos{brx_pos};
|
||||
const std::optional<u64> ldc_insn{TrackLDC(env, block_begin, pos, brx_reg)};
|
||||
|
|
@ -83,14 +86,14 @@ std::optional<IndirectBranchTableInfo> TrackIndirectBranchTable(Environment& env
|
|||
if (!shl_insn) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const Encoding shl{*shl_insn};
|
||||
const EncodingIBTT shl{*shl_insn};
|
||||
const IR::Reg shl_reg{shl.src_reg};
|
||||
|
||||
const std::optional<u64> imnmx_insn{TrackIMNMX(env, block_begin, pos, shl_reg)};
|
||||
if (!imnmx_insn) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const Encoding imnmx{*imnmx_insn};
|
||||
const EncodingIBTT imnmx{*imnmx_insn};
|
||||
if (imnmx.is_negative != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class AtomOp : u64 {
|
||||
enum class AtomicGlobalMemoryOp : u64 {
|
||||
ADD,
|
||||
MIN,
|
||||
MAX,
|
||||
|
|
@ -32,33 +32,33 @@ enum class AtomSize : u64 {
|
|||
S64,
|
||||
};
|
||||
|
||||
IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, AtomOp op, AtomSize size) {
|
||||
IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, AtomicGlobalMemoryOp op, AtomSize size) {
|
||||
bool const is_signed = size == AtomSize::S64 || size == AtomSize::S32;
|
||||
switch (op) {
|
||||
case AtomOp::ADD:
|
||||
case AtomicGlobalMemoryOp::ADD:
|
||||
return ir.GlobalAtomicIAdd(offset, op_b);
|
||||
case AtomOp::MIN:
|
||||
case AtomicGlobalMemoryOp::MIN:
|
||||
return ir.GlobalAtomicIMin(offset, op_b, is_signed);
|
||||
case AtomOp::MAX:
|
||||
case AtomicGlobalMemoryOp::MAX:
|
||||
return ir.GlobalAtomicIMax(offset, op_b, is_signed);
|
||||
case AtomOp::INC:
|
||||
case AtomicGlobalMemoryOp::INC:
|
||||
return ir.GlobalAtomicInc(offset, op_b);
|
||||
case AtomOp::DEC:
|
||||
case AtomicGlobalMemoryOp::DEC:
|
||||
return ir.GlobalAtomicDec(offset, op_b);
|
||||
case AtomOp::AND:
|
||||
case AtomicGlobalMemoryOp::AND:
|
||||
return ir.GlobalAtomicAnd(offset, op_b);
|
||||
case AtomOp::OR:
|
||||
case AtomicGlobalMemoryOp::OR:
|
||||
return ir.GlobalAtomicOr(offset, op_b);
|
||||
case AtomOp::XOR:
|
||||
case AtomicGlobalMemoryOp::XOR:
|
||||
return ir.GlobalAtomicXor(offset, op_b);
|
||||
case AtomOp::EXCH:
|
||||
case AtomicGlobalMemoryOp::EXCH:
|
||||
return ir.GlobalAtomicExchange(offset, op_b);
|
||||
default:
|
||||
throw NotImplementedException("Integer Atom Operation {}", op);
|
||||
}
|
||||
}
|
||||
|
||||
IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Value& op_b, AtomOp op,
|
||||
IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Value& op_b, AtomicGlobalMemoryOp op,
|
||||
AtomSize size) {
|
||||
static constexpr IR::FpControl f16_control{
|
||||
.no_contraction = false,
|
||||
|
|
@ -71,12 +71,12 @@ IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Valu
|
|||
.fmz_mode = IR::FmzMode::FTZ,
|
||||
};
|
||||
switch (op) {
|
||||
case AtomOp::ADD:
|
||||
case AtomicGlobalMemoryOp::ADD:
|
||||
return size == AtomSize::F32 ? ir.GlobalAtomicF32Add(offset, op_b, f32_control)
|
||||
: ir.GlobalAtomicF16x2Add(offset, op_b, f16_control);
|
||||
case AtomOp::MIN:
|
||||
case AtomicGlobalMemoryOp::MIN:
|
||||
return ir.GlobalAtomicF16x2Min(offset, op_b, f16_control);
|
||||
case AtomOp::MAX:
|
||||
case AtomicGlobalMemoryOp::MAX:
|
||||
return ir.GlobalAtomicF16x2Max(offset, op_b, f16_control);
|
||||
default:
|
||||
throw NotImplementedException("FP Atom Operation {}", op);
|
||||
|
|
@ -112,19 +112,19 @@ IR::U64 AtomOffset(TranslatorVisitor& v, u64 insn) {
|
|||
// ADD, INC, DEC for S64 does nothing
|
||||
// Only ADD does something for F32
|
||||
// Only ADD, MIN and MAX does something for F16x2
|
||||
bool AtomOpNotApplicable(AtomSize size, AtomOp op) {
|
||||
bool AtomOpNotApplicable(AtomSize size, AtomicGlobalMemoryOp op) {
|
||||
// TODO: SAFEADD
|
||||
switch (size) {
|
||||
case AtomSize::U32:
|
||||
case AtomSize::S32:
|
||||
case AtomSize::U64:
|
||||
return (op == AtomOp::INC || op == AtomOp::DEC);
|
||||
return (op == AtomicGlobalMemoryOp::INC || op == AtomicGlobalMemoryOp::DEC);
|
||||
case AtomSize::S64:
|
||||
return (op == AtomOp::ADD || op == AtomOp::INC || op == AtomOp::DEC);
|
||||
return (op == AtomicGlobalMemoryOp::ADD || op == AtomicGlobalMemoryOp::INC || op == AtomicGlobalMemoryOp::DEC);
|
||||
case AtomSize::F32:
|
||||
return op != AtomOp::ADD;
|
||||
return op != AtomicGlobalMemoryOp::ADD;
|
||||
case AtomSize::F16x2:
|
||||
return !(op == AtomOp::ADD || op == AtomOp::MIN || op == AtomOp::MAX);
|
||||
return !(op == AtomicGlobalMemoryOp::ADD || op == AtomicGlobalMemoryOp::MIN || op == AtomicGlobalMemoryOp::MAX);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ void StoreResult(TranslatorVisitor& v, IR::Reg dest_reg, const IR::Value& result
|
|||
}
|
||||
|
||||
IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64& offset,
|
||||
AtomSize size, AtomOp op) {
|
||||
AtomSize size, AtomicGlobalMemoryOp op) {
|
||||
switch (size) {
|
||||
case AtomSize::U32:
|
||||
case AtomSize::S32:
|
||||
|
|
@ -180,7 +180,7 @@ IR::Value ApplyAtomOp(TranslatorVisitor& v, IR::Reg operand_reg, const IR::U64&
|
|||
}
|
||||
|
||||
void GlobalAtomic(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg,
|
||||
const IR::U64& offset, AtomSize size, AtomOp op, bool write_dest) {
|
||||
const IR::U64& offset, AtomSize size, AtomicGlobalMemoryOp op, bool write_dest) {
|
||||
IR::Value result = AtomOpNotApplicable(size, op)
|
||||
? LoadGlobal(v.ir, offset, size)
|
||||
: ApplyAtomOp(v, operand_reg, offset, size, op);
|
||||
|
|
@ -195,7 +195,7 @@ void TranslatorVisitor::ATOM(u64 insn) {
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<20, 8, IR::Reg> operand_reg;
|
||||
BitField<49, 3, AtomSize> size;
|
||||
BitField<52, 4, AtomOp> op;
|
||||
BitField<52, 4, AtomicGlobalMemoryOp> op;
|
||||
} const atom{insn};
|
||||
const IR::U64 offset{AtomOffset(*this, insn)};
|
||||
GlobalAtomic(*this, atom.dest_reg, atom.operand_reg, offset, atom.size, atom.op, true);
|
||||
|
|
@ -206,7 +206,7 @@ void TranslatorVisitor::RED(u64 insn) {
|
|||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> operand_reg;
|
||||
BitField<20, 3, AtomSize> size;
|
||||
BitField<23, 3, AtomOp> op;
|
||||
BitField<23, 3, AtomicGlobalMemoryOp> op;
|
||||
} const red{insn};
|
||||
const IR::U64 offset{AtomOffset(*this, insn)};
|
||||
GlobalAtomic(*this, IR::Reg::RZ, red.operand_reg, offset, red.size, red.op, true);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class AtomOp : u64 {
|
||||
enum class AtomicSharedMemoryOp : u64 {
|
||||
ADD,
|
||||
MIN,
|
||||
MAX,
|
||||
|
|
@ -25,26 +28,25 @@ enum class AtomsSize : u64 {
|
|||
U64,
|
||||
};
|
||||
|
||||
IR::U32U64 ApplyAtomsOp(IR::IREmitter& ir, const IR::U32& offset, const IR::U32U64& op_b, AtomOp op,
|
||||
bool is_signed) {
|
||||
IR::U32U64 ApplyAtomsOp(IR::IREmitter& ir, const IR::U32& offset, const IR::U32U64& op_b, AtomicSharedMemoryOp op, bool is_signed) {
|
||||
switch (op) {
|
||||
case AtomOp::ADD:
|
||||
case AtomicSharedMemoryOp::ADD:
|
||||
return ir.SharedAtomicIAdd(offset, op_b);
|
||||
case AtomOp::MIN:
|
||||
case AtomicSharedMemoryOp::MIN:
|
||||
return ir.SharedAtomicIMin(offset, op_b, is_signed);
|
||||
case AtomOp::MAX:
|
||||
case AtomicSharedMemoryOp::MAX:
|
||||
return ir.SharedAtomicIMax(offset, op_b, is_signed);
|
||||
case AtomOp::INC:
|
||||
case AtomicSharedMemoryOp::INC:
|
||||
return ir.SharedAtomicInc(offset, op_b);
|
||||
case AtomOp::DEC:
|
||||
case AtomicSharedMemoryOp::DEC:
|
||||
return ir.SharedAtomicDec(offset, op_b);
|
||||
case AtomOp::AND:
|
||||
case AtomicSharedMemoryOp::AND:
|
||||
return ir.SharedAtomicAnd(offset, op_b);
|
||||
case AtomOp::OR:
|
||||
case AtomicSharedMemoryOp::OR:
|
||||
return ir.SharedAtomicOr(offset, op_b);
|
||||
case AtomOp::XOR:
|
||||
case AtomicSharedMemoryOp::XOR:
|
||||
return ir.SharedAtomicXor(offset, op_b);
|
||||
case AtomOp::EXCH:
|
||||
case AtomicSharedMemoryOp::EXCH:
|
||||
return ir.SharedAtomicExchange(offset, op_b);
|
||||
default:
|
||||
throw NotImplementedException("Integer Atoms Operation {}", op);
|
||||
|
|
@ -87,11 +89,11 @@ void TranslatorVisitor::ATOMS(u64 insn) {
|
|||
BitField<8, 8, IR::Reg> addr_reg;
|
||||
BitField<20, 8, IR::Reg> src_reg_b;
|
||||
BitField<28, 2, AtomsSize> size;
|
||||
BitField<52, 4, AtomOp> op;
|
||||
BitField<52, 4, AtomicSharedMemoryOp> op;
|
||||
} const atoms{insn};
|
||||
|
||||
const bool size_64{atoms.size == AtomsSize::U64};
|
||||
if (size_64 && atoms.op != AtomOp::EXCH) {
|
||||
if (size_64 && atoms.op != AtomicSharedMemoryOp::EXCH) {
|
||||
throw NotImplementedException("64-bit Atoms Operation {}", atoms.op.Value());
|
||||
}
|
||||
const bool is_signed{atoms.size == AtomsSize::S32};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class FPReduceMode : u64 {
|
||||
SINCOS,
|
||||
EX2,
|
||||
};
|
||||
|
|
@ -16,7 +19,7 @@ void RRO(TranslatorVisitor& v, u64 insn, const IR::F32& src) {
|
|||
union {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<39, 1, Mode> mode;
|
||||
BitField<39, 1, FPReduceMode> mode;
|
||||
BitField<45, 1, u64> neg;
|
||||
BitField<49, 1, u64> abs;
|
||||
} const rro{insn};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
|
@ -24,7 +24,7 @@ enum class IntFormat : u64 {
|
|||
U64 = 3,
|
||||
};
|
||||
|
||||
union Encoding {
|
||||
union EncodingIFPC {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 2, FloatFormat> float_format;
|
||||
|
|
@ -38,7 +38,7 @@ union Encoding {
|
|||
};
|
||||
|
||||
bool Is64(u64 insn) {
|
||||
return Encoding{insn}.int_format == IntFormat::U64;
|
||||
return EncodingIFPC{insn}.int_format == IntFormat::U64;
|
||||
}
|
||||
|
||||
int BitSize(FloatFormat format) {
|
||||
|
|
@ -62,7 +62,7 @@ IR::U32 SmallAbs(TranslatorVisitor& v, const IR::U32& value, int bitsize) {
|
|||
}
|
||||
|
||||
void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
||||
const Encoding i2f{insn};
|
||||
const EncodingIFPC i2f{insn};
|
||||
if (i2f.cc != 0) {
|
||||
throw NotImplementedException("I2F CC");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class ISBERDMode : u64 {
|
||||
Default,
|
||||
Patch,
|
||||
Prim,
|
||||
|
|
@ -63,7 +63,7 @@ void TranslatorVisitor::ISBERD(u64 insn) {
|
|||
BitField<24, 8, u32> imm;
|
||||
BitField<31, 1, u64> skew;
|
||||
BitField<32, 1, u64> o;
|
||||
BitField<33, 2, Mode> mode;
|
||||
BitField<33, 2, ISBERDMode> mode;
|
||||
BitField<36, 4, SZ> sz;
|
||||
BitField<47, 2, Shift> shift;
|
||||
} const isberd{insn};
|
||||
|
|
@ -95,18 +95,18 @@ void TranslatorVisitor::ISBERD(u64 insn) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isberd.mode.Value() != Mode::Default) {
|
||||
if (isberd.mode.Value() != ISBERDMode::Default) {
|
||||
if (isberd.skew.Value()) {
|
||||
index = ir.IAdd(index, skewBytes(ir, SZ::U32));
|
||||
}
|
||||
|
||||
IR::F32 float_index{};
|
||||
switch (isberd.mode.Value()) {
|
||||
case Mode::Patch: float_index = ir.GetPatch(index.Patch());
|
||||
case ISBERDMode::Patch: float_index = ir.GetPatch(index.Patch());
|
||||
break;
|
||||
case Mode::Prim: float_index = ir.GetAttribute(index.Attribute());
|
||||
case ISBERDMode::Prim: float_index = ir.GetAttribute(index.Attribute());
|
||||
break;
|
||||
case Mode::Attr: float_index = ir.GetAttributeIndexed(index);
|
||||
case ISBERDMode::Attr: float_index = ir.GetAttributeIndexed(index);
|
||||
break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Size : u64 {
|
||||
enum class InterpolationSize : u64 {
|
||||
B32,
|
||||
B64,
|
||||
B96,
|
||||
|
|
@ -29,15 +32,15 @@ enum class SampleMode : u64 {
|
|||
Offset,
|
||||
};
|
||||
|
||||
u32 NumElements(Size size) {
|
||||
u32 NumElements(InterpolationSize size) {
|
||||
switch (size) {
|
||||
case Size::B32:
|
||||
case InterpolationSize::B32:
|
||||
return 1;
|
||||
case Size::B64:
|
||||
case InterpolationSize::B64:
|
||||
return 2;
|
||||
case Size::B96:
|
||||
case InterpolationSize::B96:
|
||||
return 3;
|
||||
case Size::B128:
|
||||
case InterpolationSize::B128:
|
||||
return 4;
|
||||
}
|
||||
throw InvalidArgument("Invalid size {}", size);
|
||||
|
|
@ -65,7 +68,7 @@ void TranslatorVisitor::ALD(u64 insn) {
|
|||
BitField<39, 8, IR::Reg> vertex_reg;
|
||||
BitField<32, 1, u64> o;
|
||||
BitField<31, 1, u64> patch;
|
||||
BitField<47, 2, Size> size;
|
||||
BitField<47, 2, InterpolationSize> size;
|
||||
} const ald{insn};
|
||||
|
||||
const u64 offset{ald.absolute_offset.Value()};
|
||||
|
|
@ -103,7 +106,7 @@ void TranslatorVisitor::AST(u64 insn) {
|
|||
BitField<20, 11, s64> relative_offset;
|
||||
BitField<31, 1, u64> patch;
|
||||
BitField<39, 8, IR::Reg> vertex_reg;
|
||||
BitField<47, 2, Size> size;
|
||||
BitField<47, 2, InterpolationSize> size;
|
||||
} const ast{insn};
|
||||
|
||||
if (ast.index_reg != IR::Reg::RZ) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Size : u64 {
|
||||
enum class LoadStoreLocalSharedSize : u64 {
|
||||
U8,
|
||||
S8,
|
||||
U16,
|
||||
|
|
@ -45,23 +48,23 @@ std::pair<IR::U32, IR::U32> WordOffset(TranslatorVisitor& v, u64 insn) {
|
|||
std::pair<int, bool> GetSize(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<48, 3, Size> size;
|
||||
BitField<48, 3, LoadStoreLocalSharedSize> size;
|
||||
} const encoding{insn};
|
||||
|
||||
switch (encoding.size) {
|
||||
case Size::U8:
|
||||
case LoadStoreLocalSharedSize::U8:
|
||||
return {8, false};
|
||||
case Size::S8:
|
||||
case LoadStoreLocalSharedSize::S8:
|
||||
return {8, true};
|
||||
case Size::U16:
|
||||
case LoadStoreLocalSharedSize::U16:
|
||||
return {16, false};
|
||||
case Size::S16:
|
||||
case LoadStoreLocalSharedSize::S16:
|
||||
return {16, true};
|
||||
case Size::B32:
|
||||
case LoadStoreLocalSharedSize::B32:
|
||||
return {32, false};
|
||||
case Size::B64:
|
||||
case LoadStoreLocalSharedSize::B64:
|
||||
return {64, false};
|
||||
case Size::B128:
|
||||
case LoadStoreLocalSharedSize::B128:
|
||||
return {128, false};
|
||||
default:
|
||||
throw NotImplementedException("Invalid size {}", encoding.size.Value());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class MovePredicateFlagMode : u64 {
|
||||
PR,
|
||||
CC,
|
||||
};
|
||||
|
|
@ -26,12 +29,12 @@ void TranslatorVisitor::P2R_imm(u64 insn) {
|
|||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> src;
|
||||
BitField<40, 1, Mode> mode;
|
||||
BitField<40, 1, MovePredicateFlagMode> mode;
|
||||
BitField<41, 2, u64> byte_selector;
|
||||
} const p2r{insn};
|
||||
|
||||
const u32 mask{GetImm20(insn).U32()};
|
||||
const bool pr_mode{p2r.mode == Mode::PR};
|
||||
const bool pr_mode{p2r.mode == MovePredicateFlagMode::PR};
|
||||
const u32 num_items{pr_mode ? 7U : 4U};
|
||||
const u32 offset{static_cast<u32>(p2r.byte_selector) * 8};
|
||||
IR::U32 insert{ir.Imm32(0)};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class PredicateFlagMode : u64 {
|
||||
PR,
|
||||
CC,
|
||||
};
|
||||
|
|
@ -31,12 +34,12 @@ void R2P(TranslatorVisitor& v, u64 insn, const IR::U32& mask) {
|
|||
union {
|
||||
u64 raw;
|
||||
BitField<8, 8, IR::Reg> src_reg;
|
||||
BitField<40, 1, Mode> mode;
|
||||
BitField<40, 1, PredicateFlagMode> mode;
|
||||
BitField<41, 2, u64> byte_selector;
|
||||
} const r2p{insn};
|
||||
const IR::U32 src{v.X(r2p.src_reg)};
|
||||
const IR::U32 count{v.ir.Imm32(1)};
|
||||
const bool pr_mode{r2p.mode == Mode::PR};
|
||||
const bool pr_mode{r2p.mode == PredicateFlagMode::PR};
|
||||
const u32 num_items{pr_mode ? 7U : 4U};
|
||||
const u32 offset_base{static_cast<u32>(r2p.byte_selector) * 8};
|
||||
for (u32 index = 0; index < num_items; ++index) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -7,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class PixelLoadMode : u64 {
|
||||
Default,
|
||||
CovMask,
|
||||
Covered,
|
||||
|
|
@ -20,7 +23,7 @@ enum class Mode : u64 {
|
|||
void TranslatorVisitor::PIXLD(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<31, 3, Mode> mode;
|
||||
BitField<31, 3, PixelLoadMode> mode;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> addr_reg;
|
||||
BitField<20, 8, s64> addr_offset;
|
||||
|
|
@ -34,11 +37,11 @@ void TranslatorVisitor::PIXLD(u64 insn) {
|
|||
throw NotImplementedException("Non-zero source register");
|
||||
}
|
||||
switch (pixld.mode) {
|
||||
case Mode::MyIndex:
|
||||
case PixelLoadMode::MyIndex:
|
||||
X(pixld.dest_reg, ir.SampleId());
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Mode {}", pixld.mode.Value());
|
||||
throw NotImplementedException("PixelLoadMode {}", pixld.mode.Value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Type : u64 {
|
||||
enum class SurfaceAtomicType : u64 {
|
||||
_1D = 0,
|
||||
_1D_BUFFER = 1,
|
||||
_1D_ARRAY = 2,
|
||||
|
|
@ -25,7 +25,7 @@ enum class Type : u64 {
|
|||
/// For any would be newcomer to here: Yes - GPU dissasembly says S64 should
|
||||
/// be after F16x2FTZRN. However if you do plan to revert this, you MUST test
|
||||
/// ToTK beforehand. As the game will break with the subtle change
|
||||
enum class Size : u64 {
|
||||
enum class SurfaceAtomicSize : u64 {
|
||||
U32,
|
||||
S32,
|
||||
U64,
|
||||
|
|
@ -48,46 +48,46 @@ enum class AtomicOp : u64 {
|
|||
EXCH,
|
||||
};
|
||||
|
||||
enum class Clamp : u64 {
|
||||
enum class SurfaceAtomicClamp : u64 {
|
||||
IGN,
|
||||
Default,
|
||||
TRAP,
|
||||
};
|
||||
|
||||
TextureType GetType(Type type) {
|
||||
TextureType GetType(SurfaceAtomicType type) {
|
||||
switch (type) {
|
||||
case Type::_1D:
|
||||
case SurfaceAtomicType::_1D:
|
||||
return TextureType::Color1D;
|
||||
case Type::_1D_BUFFER:
|
||||
case SurfaceAtomicType::_1D_BUFFER:
|
||||
return TextureType::Buffer;
|
||||
case Type::_1D_ARRAY:
|
||||
case SurfaceAtomicType::_1D_ARRAY:
|
||||
return TextureType::ColorArray1D;
|
||||
case Type::_2D:
|
||||
case SurfaceAtomicType::_2D:
|
||||
return TextureType::Color2D;
|
||||
case Type::_2D_ARRAY:
|
||||
case SurfaceAtomicType::_2D_ARRAY:
|
||||
return TextureType::ColorArray2D;
|
||||
case Type::_3D:
|
||||
case SurfaceAtomicType::_3D:
|
||||
return TextureType::Color3D;
|
||||
default:
|
||||
throw NotImplementedException("Invalid type {}", type);
|
||||
}
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, SurfaceAtomicType type) {
|
||||
const auto array{[&](int index) {
|
||||
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
||||
}};
|
||||
switch (type) {
|
||||
case Type::_1D:
|
||||
case Type::_1D_BUFFER:
|
||||
case SurfaceAtomicType::_1D:
|
||||
case SurfaceAtomicType::_1D_BUFFER:
|
||||
return v.X(reg);
|
||||
case Type::_1D_ARRAY:
|
||||
case SurfaceAtomicType::_1D_ARRAY:
|
||||
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
||||
case Type::_2D:
|
||||
case SurfaceAtomicType::_2D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||
case Type::_2D_ARRAY:
|
||||
case SurfaceAtomicType::_2D_ARRAY:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
||||
case Type::_3D:
|
||||
case SurfaceAtomicType::_3D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||
default:
|
||||
throw NotImplementedException("Invalid type {}", type);
|
||||
|
|
@ -121,11 +121,11 @@ IR::Value ApplyAtomicOp(IR::IREmitter& ir, const IR::U32& handle, const IR::Valu
|
|||
}
|
||||
}
|
||||
|
||||
ImageFormat Format(Size size) {
|
||||
ImageFormat Format(SurfaceAtomicSize size) {
|
||||
switch (size) {
|
||||
case Size::U32:
|
||||
case Size::S32:
|
||||
case Size::SD32:
|
||||
case SurfaceAtomicSize::U32:
|
||||
case SurfaceAtomicSize::S32:
|
||||
case SurfaceAtomicSize::SD32:
|
||||
return ImageFormat::R32_UINT;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -133,11 +133,11 @@ ImageFormat Format(Size size) {
|
|||
throw NotImplementedException("Invalid size {}", size);
|
||||
}
|
||||
|
||||
bool IsSizeInt32(Size size) {
|
||||
bool IsSizeInt32(SurfaceAtomicSize size) {
|
||||
switch (size) {
|
||||
case Size::U32:
|
||||
case Size::S32:
|
||||
case Size::SD32:
|
||||
case SurfaceAtomicSize::U32:
|
||||
case SurfaceAtomicSize::S32:
|
||||
case SurfaceAtomicSize::SD32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -145,15 +145,15 @@ bool IsSizeInt32(Size size) {
|
|||
}
|
||||
|
||||
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg,
|
||||
std::optional<IR::Reg> bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type,
|
||||
std::optional<IR::Reg> bindless_reg, AtomicOp op, SurfaceAtomicClamp clamp, SurfaceAtomicSize size, SurfaceAtomicType type,
|
||||
u64 bound_offset, bool is_bindless, bool write_result) {
|
||||
if (clamp != Clamp::IGN) {
|
||||
throw NotImplementedException("Clamp {}", clamp);
|
||||
if (clamp != SurfaceAtomicClamp::IGN) {
|
||||
throw NotImplementedException("SurfaceAtomicClamp {}", clamp);
|
||||
}
|
||||
if (!IsSizeInt32(size)) {
|
||||
throw NotImplementedException("Size {}", size);
|
||||
throw NotImplementedException("SurfaceAtomicSize {}", size);
|
||||
}
|
||||
const bool is_signed{size == Size::S32};
|
||||
const bool is_signed{size == SurfaceAtomicSize::S32};
|
||||
const ImageFormat format{Format(size)};
|
||||
const TextureType tex_type{GetType(type)};
|
||||
const IR::Value coords{MakeCoords(v, coord_reg, type)};
|
||||
|
|
@ -178,9 +178,9 @@ void TranslatorVisitor::SUATOM(u64 insn) {
|
|||
u64 raw;
|
||||
BitField<54, 1, u64> is_bindless;
|
||||
BitField<29, 4, AtomicOp> op;
|
||||
BitField<33, 3, Type> type;
|
||||
BitField<51, 3, Size> size;
|
||||
BitField<49, 2, Clamp> clamp;
|
||||
BitField<33, 3, SurfaceAtomicType> type;
|
||||
BitField<51, 3, SurfaceAtomicSize> size;
|
||||
BitField<49, 2, SurfaceAtomicClamp> clamp;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> operand_reg;
|
||||
|
|
@ -199,9 +199,9 @@ void TranslatorVisitor::SURED(u64 insn) {
|
|||
u64 raw;
|
||||
BitField<51, 1, u64> is_bound;
|
||||
BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp)
|
||||
BitField<33, 3, Type> type; //OK? - 33 (Dim)
|
||||
BitField<20, 3, Size> size; //?
|
||||
BitField<49, 2, Clamp> clamp; //OK - 49 (Clamp4)
|
||||
BitField<33, 3, SurfaceAtomicType> type; //OK? - 33 (Dim)
|
||||
BitField<20, 3, SurfaceAtomicSize> size; //?
|
||||
BitField<49, 2, SurfaceAtomicClamp> clamp; //OK - 49 (Clamp4)
|
||||
BitField<0, 8, IR::Reg> operand_reg; //RA?
|
||||
BitField<8, 8, IR::Reg> coord_reg; //RB?
|
||||
BitField<36, 13, u64> bound_offset; //OK 33 (TidB)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -11,7 +14,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Type : u64 {
|
||||
enum class SurfaceLoadStoreType : u64 {
|
||||
_1D,
|
||||
BUFFER_1D,
|
||||
ARRAY_1D,
|
||||
|
|
@ -44,7 +47,7 @@ constexpr std::array MASK{
|
|||
R | G | B | A, //
|
||||
};
|
||||
|
||||
enum class Size : u64 {
|
||||
enum class SurfaceLoadStoreSize : u64 {
|
||||
U8,
|
||||
S8,
|
||||
U16,
|
||||
|
|
@ -54,7 +57,7 @@ enum class Size : u64 {
|
|||
B128,
|
||||
};
|
||||
|
||||
enum class Clamp : u64 {
|
||||
enum class SurfaceLoadStoreClamp : u64 {
|
||||
IGN,
|
||||
Default,
|
||||
TRAP,
|
||||
|
|
@ -75,75 +78,75 @@ enum class StoreCache : u64 {
|
|||
WT, // Cache write-through (to system memory, volatile?)
|
||||
};
|
||||
|
||||
ImageFormat Format(Size size) {
|
||||
ImageFormat Format(SurfaceLoadStoreSize size) {
|
||||
switch (size) {
|
||||
case Size::U8:
|
||||
case SurfaceLoadStoreSize::U8:
|
||||
return ImageFormat::R8_UINT;
|
||||
case Size::S8:
|
||||
case SurfaceLoadStoreSize::S8:
|
||||
return ImageFormat::R8_SINT;
|
||||
case Size::U16:
|
||||
case SurfaceLoadStoreSize::U16:
|
||||
return ImageFormat::R16_UINT;
|
||||
case Size::S16:
|
||||
case SurfaceLoadStoreSize::S16:
|
||||
return ImageFormat::R16_SINT;
|
||||
case Size::B32:
|
||||
case SurfaceLoadStoreSize::B32:
|
||||
return ImageFormat::R32_UINT;
|
||||
case Size::B64:
|
||||
case SurfaceLoadStoreSize::B64:
|
||||
return ImageFormat::R32G32_UINT;
|
||||
case Size::B128:
|
||||
case SurfaceLoadStoreSize::B128:
|
||||
return ImageFormat::R32G32B32A32_UINT;
|
||||
}
|
||||
throw NotImplementedException("Invalid size {}", size);
|
||||
}
|
||||
|
||||
int SizeInRegs(Size size) {
|
||||
int SizeInRegs(SurfaceLoadStoreSize size) {
|
||||
switch (size) {
|
||||
case Size::U8:
|
||||
case Size::S8:
|
||||
case Size::U16:
|
||||
case Size::S16:
|
||||
case Size::B32:
|
||||
case SurfaceLoadStoreSize::U8:
|
||||
case SurfaceLoadStoreSize::S8:
|
||||
case SurfaceLoadStoreSize::U16:
|
||||
case SurfaceLoadStoreSize::S16:
|
||||
case SurfaceLoadStoreSize::B32:
|
||||
return 1;
|
||||
case Size::B64:
|
||||
case SurfaceLoadStoreSize::B64:
|
||||
return 2;
|
||||
case Size::B128:
|
||||
case SurfaceLoadStoreSize::B128:
|
||||
return 4;
|
||||
}
|
||||
throw NotImplementedException("Invalid size {}", size);
|
||||
}
|
||||
|
||||
TextureType GetType(Type type) {
|
||||
TextureType GetType(SurfaceLoadStoreType type) {
|
||||
switch (type) {
|
||||
case Type::_1D:
|
||||
case SurfaceLoadStoreType::_1D:
|
||||
return TextureType::Color1D;
|
||||
case Type::BUFFER_1D:
|
||||
case SurfaceLoadStoreType::BUFFER_1D:
|
||||
return TextureType::Buffer;
|
||||
case Type::ARRAY_1D:
|
||||
case SurfaceLoadStoreType::ARRAY_1D:
|
||||
return TextureType::ColorArray1D;
|
||||
case Type::_2D:
|
||||
case SurfaceLoadStoreType::_2D:
|
||||
return TextureType::Color2D;
|
||||
case Type::ARRAY_2D:
|
||||
case SurfaceLoadStoreType::ARRAY_2D:
|
||||
return TextureType::ColorArray2D;
|
||||
case Type::_3D:
|
||||
case SurfaceLoadStoreType::_3D:
|
||||
return TextureType::Color3D;
|
||||
}
|
||||
throw NotImplementedException("Invalid type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, SurfaceLoadStoreType type) {
|
||||
const auto array{[&](int index) {
|
||||
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
|
||||
}};
|
||||
switch (type) {
|
||||
case Type::_1D:
|
||||
case Type::BUFFER_1D:
|
||||
case SurfaceLoadStoreType::_1D:
|
||||
case SurfaceLoadStoreType::BUFFER_1D:
|
||||
return v.X(reg);
|
||||
case Type::ARRAY_1D:
|
||||
case SurfaceLoadStoreType::ARRAY_1D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), array(1));
|
||||
case Type::_2D:
|
||||
case SurfaceLoadStoreType::_2D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||
case Type::ARRAY_2D:
|
||||
case SurfaceLoadStoreType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2));
|
||||
case Type::_3D:
|
||||
case SurfaceLoadStoreType::_3D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||
}
|
||||
throw NotImplementedException("Invalid type {}", type);
|
||||
|
|
@ -174,19 +177,19 @@ void TranslatorVisitor::SULD(u64 insn) {
|
|||
BitField<51, 1, u64> is_bound;
|
||||
BitField<52, 1, u64> d;
|
||||
BitField<23, 1, u64> ba;
|
||||
BitField<33, 3, Type> type;
|
||||
BitField<33, 3, SurfaceLoadStoreType> type;
|
||||
BitField<24, 2, LoadCache> cache;
|
||||
BitField<20, 3, Size> size; // .D
|
||||
BitField<20, 3, SurfaceLoadStoreSize> size; // .D
|
||||
BitField<20, 4, u64> swizzle; // .P
|
||||
BitField<49, 2, Clamp> clamp;
|
||||
BitField<49, 2, SurfaceLoadStoreClamp> clamp;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<36, 13, u64> bound_offset; // is_bound
|
||||
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
||||
} const suld{insn};
|
||||
|
||||
if (suld.clamp != Clamp::IGN) {
|
||||
throw NotImplementedException("Clamp {}", suld.clamp.Value());
|
||||
if (suld.clamp != SurfaceLoadStoreClamp::IGN) {
|
||||
throw NotImplementedException("SurfaceLoadStoreClamp {}", suld.clamp.Value());
|
||||
}
|
||||
if (suld.cache != LoadCache::CA && suld.cache != LoadCache::CG) {
|
||||
throw NotImplementedException("Cache {}", suld.cache.Value());
|
||||
|
|
@ -234,19 +237,19 @@ void TranslatorVisitor::SUST(u64 insn) {
|
|||
BitField<51, 1, u64> is_bound;
|
||||
BitField<52, 1, u64> d;
|
||||
BitField<23, 1, u64> ba;
|
||||
BitField<33, 3, Type> type;
|
||||
BitField<33, 3, SurfaceLoadStoreType> type;
|
||||
BitField<24, 2, StoreCache> cache;
|
||||
BitField<20, 3, Size> size; // .D
|
||||
BitField<20, 3, SurfaceLoadStoreSize> size; // .D
|
||||
BitField<20, 4, u64> swizzle; // .P
|
||||
BitField<49, 2, Clamp> clamp;
|
||||
BitField<49, 2, SurfaceLoadStoreClamp> clamp;
|
||||
BitField<0, 8, IR::Reg> data_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<36, 13, u64> bound_offset; // is_bound
|
||||
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
||||
} const sust{insn};
|
||||
|
||||
if (sust.clamp != Clamp::IGN) {
|
||||
throw NotImplementedException("Clamp {}", sust.clamp.Value());
|
||||
if (sust.clamp != SurfaceLoadStoreClamp::IGN) {
|
||||
throw NotImplementedException("SurfaceLoadStoreClamp {}", sust.clamp.Value());
|
||||
}
|
||||
if (sust.cache != StoreCache::WB && sust.cache != StoreCache::CG) {
|
||||
throw NotImplementedException("Cache {}", sust.cache.Value());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -21,7 +24,7 @@ enum class Blod : u64 {
|
|||
LLA,
|
||||
};
|
||||
|
||||
enum class TextureType : u64 {
|
||||
enum class TextureFetchType : u64 {
|
||||
_1D,
|
||||
ARRAY_1D,
|
||||
_2D,
|
||||
|
|
@ -32,46 +35,46 @@ enum class TextureType : u64 {
|
|||
ARRAY_CUBE,
|
||||
};
|
||||
|
||||
Shader::TextureType GetType(TextureType type) {
|
||||
Shader::TextureType GetType(TextureFetchType type) {
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureFetchType::_1D:
|
||||
return Shader::TextureType::Color1D;
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureFetchType::ARRAY_1D:
|
||||
return Shader::TextureType::ColorArray1D;
|
||||
case TextureType::_2D:
|
||||
case TextureFetchType::_2D:
|
||||
return Shader::TextureType::Color2D;
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureFetchType::ARRAY_2D:
|
||||
return Shader::TextureType::ColorArray2D;
|
||||
case TextureType::_3D:
|
||||
case TextureFetchType::_3D:
|
||||
return Shader::TextureType::Color3D;
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureFetchType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureFetchType::CUBE:
|
||||
return Shader::TextureType::ColorCube;
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureFetchType::ARRAY_CUBE:
|
||||
return Shader::TextureType::ColorArrayCube;
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureFetchType type) {
|
||||
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureFetchType::_1D:
|
||||
return v.F(reg);
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureFetchType::ARRAY_1D:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
||||
case TextureType::_2D:
|
||||
case TextureFetchType::_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureFetchType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
||||
case TextureType::_3D:
|
||||
case TextureFetchType::_3D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureFetchType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureFetchType::CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureFetchType::ARRAY_CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
|
|
@ -95,25 +98,25 @@ IR::F32 MakeLod(TranslatorVisitor& v, IR::Reg& reg, Blod blod) {
|
|||
throw NotImplementedException("Invalid blod {}", blod);
|
||||
}
|
||||
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureFetchType type) {
|
||||
const IR::U32 value{v.X(reg++)};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureFetchType::_1D:
|
||||
case TextureFetchType::ARRAY_1D:
|
||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
||||
case TextureType::_2D:
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureFetchType::_2D:
|
||||
case TextureFetchType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||
case TextureType::_3D:
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureFetchType::_3D:
|
||||
case TextureFetchType::ARRAY_3D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
||||
case TextureType::CUBE:
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureFetchType::CUBE:
|
||||
case TextureFetchType::ARRAY_CUBE:
|
||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
|
|
@ -141,7 +144,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool aoffi, Blod blod, bool lc,
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> meta_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<28, 3, TextureFetchType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
} const tex{insn};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -8,14 +11,14 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Precision : u64 {
|
||||
enum class TextureFetchSwizzledPrecision : u64 {
|
||||
F16,
|
||||
F32,
|
||||
};
|
||||
|
||||
union Encoding {
|
||||
union EncodinTFS {
|
||||
u64 raw;
|
||||
BitField<59, 1, Precision> precision;
|
||||
BitField<59, 1, TextureFetchSwizzledPrecision> precision;
|
||||
BitField<53, 4, u64> encoding;
|
||||
BitField<49, 1, u64> nodep;
|
||||
BitField<28, 8, IR::Reg> dest_reg_b;
|
||||
|
|
@ -26,31 +29,7 @@ union Encoding {
|
|||
BitField<50, 3, u64> swizzle;
|
||||
};
|
||||
|
||||
constexpr unsigned R = 1;
|
||||
constexpr unsigned G = 2;
|
||||
constexpr unsigned B = 4;
|
||||
constexpr unsigned A = 8;
|
||||
|
||||
constexpr std::array RG_LUT{
|
||||
R, //
|
||||
G, //
|
||||
B, //
|
||||
A, //
|
||||
R | G, //
|
||||
R | A, //
|
||||
G | A, //
|
||||
B | A, //
|
||||
};
|
||||
|
||||
constexpr std::array RGBA_LUT{
|
||||
R | G | B, //
|
||||
R | G | A, //
|
||||
R | B | A, //
|
||||
G | B | A, //
|
||||
R | G | B | A, //
|
||||
};
|
||||
|
||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
||||
void CheckAlignmentTFS(IR::Reg reg, size_t alignment) {
|
||||
if (!IR::IsAligned(reg, alignment)) {
|
||||
throw NotImplementedException("Unaligned source register {}", reg);
|
||||
}
|
||||
|
|
@ -65,14 +44,14 @@ IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) {
|
|||
return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16)));
|
||||
}
|
||||
|
||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
||||
const Encoding texs{insn};
|
||||
IR::Value SampleTFS(TranslatorVisitor& v, u64 insn) {
|
||||
const EncodinTFS texs{insn};
|
||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset * 4))};
|
||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||
const IR::Reg reg_a{texs.src_reg_a};
|
||||
const IR::Reg reg_b{texs.src_reg_b};
|
||||
IR::TextureInstInfo info{};
|
||||
if (texs.precision == Precision::F16) {
|
||||
if (texs.precision == TextureFetchSwizzledPrecision::F16) {
|
||||
info.relaxed_precision.Assign(1);
|
||||
}
|
||||
switch (texs.encoding) {
|
||||
|
|
@ -86,67 +65,67 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
info.type.Assign(TextureType::Color2D);
|
||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_b), zero, {}, info);
|
||||
case 3: // 2D.LL
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::Color2D);
|
||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), {},
|
||||
info);
|
||||
case 4: // 2D.DC
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::Color2D);
|
||||
info.is_depth.Assign(1);
|
||||
return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
||||
{}, {}, {}, info);
|
||||
case 5: // 2D.LL.DC
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_b, 2);
|
||||
info.type.Assign(TextureType::Color2D);
|
||||
info.is_depth.Assign(1);
|
||||
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1),
|
||||
v.F(reg_b + 1), v.F(reg_b), {}, info);
|
||||
case 6: // 2D.LZ.DC
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::Color2D);
|
||||
info.is_depth.Assign(1);
|
||||
return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
|
||||
zero, {}, info);
|
||||
case 7: // ARRAY_2D
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::ColorArray2D);
|
||||
return v.ir.ImageSampleImplicitLod(
|
||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||
{}, {}, {}, info);
|
||||
case 8: // ARRAY_2D.LZ
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::ColorArray2D);
|
||||
return v.ir.ImageSampleExplicitLod(
|
||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||
zero, {}, info);
|
||||
case 9: // ARRAY_2D.LZ.DC
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_b, 2);
|
||||
info.type.Assign(TextureType::ColorArray2D);
|
||||
info.is_depth.Assign(1);
|
||||
return v.ir.ImageSampleDrefExplicitLod(
|
||||
handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
|
||||
v.F(reg_b + 1), zero, {}, info);
|
||||
case 10: // 3D
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::Color3D);
|
||||
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
||||
{}, info);
|
||||
case 11: // 3D.LZ
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::Color3D);
|
||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), zero, {},
|
||||
info);
|
||||
case 12: // CUBE
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
info.type.Assign(TextureType::ColorCube);
|
||||
return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
|
||||
{}, info);
|
||||
case 13: // CUBE.LL
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTFS(reg_a, 2);
|
||||
CheckAlignmentTFS(reg_b, 2);
|
||||
info.type.Assign(TextureType::ColorCube);
|
||||
return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b),
|
||||
v.F(reg_b + 1), {}, info);
|
||||
|
|
@ -156,17 +135,40 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
}
|
||||
|
||||
unsigned Swizzle(u64 insn) {
|
||||
const Encoding texs{insn};
|
||||
#define R 1
|
||||
#define G 2
|
||||
#define B 4
|
||||
#define A 8
|
||||
constexpr std::array<unsigned, 8> RG_LUT{
|
||||
R, //
|
||||
G, //
|
||||
B, //
|
||||
A, //
|
||||
R | G, //
|
||||
R | A, //
|
||||
G | A, //
|
||||
B | A, //
|
||||
};
|
||||
constexpr std::array<unsigned, 5> RGBA_LUT{
|
||||
R | G | B, //
|
||||
R | G | A, //
|
||||
R | B | A, //
|
||||
G | B | A, //
|
||||
R | G | B | A, //
|
||||
};
|
||||
#undef R
|
||||
#undef G
|
||||
#undef B
|
||||
#undef A
|
||||
const EncodinTFS texs{insn};
|
||||
const size_t encoding{texs.swizzle};
|
||||
if (texs.dest_reg_b == IR::Reg::RZ) {
|
||||
if (encoding >= RG_LUT.size()) {
|
||||
if (encoding >= RG_LUT.size())
|
||||
throw NotImplementedException("Illegal RG encoding {}", encoding);
|
||||
}
|
||||
return RG_LUT[encoding];
|
||||
} else {
|
||||
if (encoding >= RGBA_LUT.size()) {
|
||||
if (encoding >= RGBA_LUT.size())
|
||||
throw NotImplementedException("Illegal RGBA encoding {}", encoding);
|
||||
}
|
||||
return RGBA_LUT[encoding];
|
||||
}
|
||||
}
|
||||
|
|
@ -182,23 +184,23 @@ IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned componen
|
|||
}
|
||||
|
||||
IR::Reg RegStoreComponent32(u64 insn, unsigned index) {
|
||||
const Encoding texs{insn};
|
||||
const EncodinTFS texs{insn};
|
||||
switch (index) {
|
||||
case 0:
|
||||
return texs.dest_reg_a;
|
||||
case 1:
|
||||
CheckAlignment(texs.dest_reg_a, 2);
|
||||
CheckAlignmentTFS(texs.dest_reg_a, 2);
|
||||
return texs.dest_reg_a + 1;
|
||||
case 2:
|
||||
return texs.dest_reg_b;
|
||||
case 3:
|
||||
CheckAlignment(texs.dest_reg_b, 2);
|
||||
CheckAlignmentTFS(texs.dest_reg_b, 2);
|
||||
return texs.dest_reg_b + 1;
|
||||
}
|
||||
throw LogicError("Invalid store index {}", index);
|
||||
}
|
||||
|
||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store32TFS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
const unsigned swizzle{Swizzle(insn)};
|
||||
unsigned store_index{0};
|
||||
for (unsigned component = 0; component < 4; ++component) {
|
||||
|
|
@ -211,11 +213,11 @@ void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
}
|
||||
}
|
||||
|
||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
IR::U32 PackTFS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||
}
|
||||
|
||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store16TFS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
const unsigned swizzle{Swizzle(insn)};
|
||||
unsigned store_index{0};
|
||||
std::array<IR::F32, 4> swizzled;
|
||||
|
|
@ -227,23 +229,23 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
++store_index;
|
||||
}
|
||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||
const Encoding texs{insn};
|
||||
const EncodinTFS texs{insn};
|
||||
switch (store_index) {
|
||||
case 1:
|
||||
v.X(texs.dest_reg_a, Pack(v, swizzled[0], zero));
|
||||
v.X(texs.dest_reg_a, PackTFS(v, swizzled[0], zero));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
v.X(texs.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
||||
v.X(texs.dest_reg_a, PackTFS(v, swizzled[0], swizzled[1]));
|
||||
switch (store_index) {
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
v.X(texs.dest_reg_b, Pack(v, swizzled[2], zero));
|
||||
v.X(texs.dest_reg_b, PackTFS(v, swizzled[2], zero));
|
||||
break;
|
||||
case 4:
|
||||
v.X(texs.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
||||
v.X(texs.dest_reg_b, PackTFS(v, swizzled[2], swizzled[3]));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -252,11 +254,11 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TEXS(u64 insn) {
|
||||
const IR::Value sample{Sample(*this, insn)};
|
||||
if (Encoding{insn}.precision == Precision::F32) {
|
||||
Store32(*this, insn, sample);
|
||||
const IR::Value sample{SampleTFS(*this, insn)};
|
||||
if (EncodinTFS{insn}.precision == TextureFetchSwizzledPrecision::F32) {
|
||||
Store32TFS(*this, insn, sample);
|
||||
} else {
|
||||
Store16(*this, insn, sample);
|
||||
Store16TFS(*this, insn, sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
|
||||
enum class TextureType : u64 {
|
||||
enum class TextureGatherType : u64 {
|
||||
_1D,
|
||||
ARRAY_1D,
|
||||
_2D,
|
||||
|
|
@ -27,77 +30,77 @@ enum class OffsetType : u64 {
|
|||
Invalid,
|
||||
};
|
||||
|
||||
enum class ComponentType : u64 {
|
||||
enum class TextureGatherComponentType : u64 {
|
||||
R = 0,
|
||||
G = 1,
|
||||
B = 2,
|
||||
A = 3,
|
||||
};
|
||||
|
||||
Shader::TextureType GetType(TextureType type) {
|
||||
Shader::TextureType GetTextureGatherType(TextureGatherType type) {
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureGatherType::_1D:
|
||||
return Shader::TextureType::Color1D;
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureGatherType::ARRAY_1D:
|
||||
return Shader::TextureType::ColorArray1D;
|
||||
case TextureType::_2D:
|
||||
case TextureGatherType::_2D:
|
||||
return Shader::TextureType::Color2D;
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureGatherType::ARRAY_2D:
|
||||
return Shader::TextureType::ColorArray2D;
|
||||
case TextureType::_3D:
|
||||
case TextureGatherType::_3D:
|
||||
return Shader::TextureType::Color3D;
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureGatherType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureGatherType::CUBE:
|
||||
return Shader::TextureType::ColorCube;
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureGatherType::ARRAY_CUBE:
|
||||
return Shader::TextureType::ColorArrayCube;
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
||||
IR::Value MakeTextureGatherCoords(TranslatorVisitor& v, IR::Reg reg, TextureGatherType type) {
|
||||
const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureGatherType::_1D:
|
||||
return v.F(reg);
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureGatherType::ARRAY_1D:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), read_array());
|
||||
case TextureType::_2D:
|
||||
case TextureGatherType::_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureGatherType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), read_array());
|
||||
case TextureType::_3D:
|
||||
case TextureGatherType::_3D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureGatherType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureGatherType::CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureGatherType::ARRAY_CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3), read_array());
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureGatherType type) {
|
||||
const IR::U32 value{v.X(reg++)};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureGatherType::_1D:
|
||||
case TextureGatherType::ARRAY_1D:
|
||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true);
|
||||
case TextureType::_2D:
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureGatherType::_2D:
|
||||
case TextureGatherType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
||||
case TextureType::_3D:
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureGatherType::_3D:
|
||||
case TextureGatherType::ARRAY_3D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(6), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(16), v.ir.Imm32(6), true));
|
||||
case TextureType::CUBE:
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureGatherType::CUBE:
|
||||
case TextureGatherType::ARRAY_CUBE:
|
||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
|
|
@ -116,7 +119,7 @@ std::pair<IR::Value, IR::Value> MakeOffsetPTP(TranslatorVisitor& v, IR::Reg& reg
|
|||
return {make_vector(value1), make_vector(value2)};
|
||||
}
|
||||
|
||||
void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetType offset_type,
|
||||
void Impl(TranslatorVisitor& v, u64 insn, TextureGatherComponentType component_type, OffsetType offset_type,
|
||||
bool is_bindless) {
|
||||
union {
|
||||
u64 raw;
|
||||
|
|
@ -127,12 +130,12 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> meta_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<28, 3, TextureGatherType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
} const tld4{insn};
|
||||
|
||||
const IR::Value coords{MakeCoords(v, tld4.coord_reg, tld4.type)};
|
||||
const IR::Value coords{MakeTextureGatherCoords(v, tld4.coord_reg, tld4.type)};
|
||||
|
||||
IR::Reg meta_reg{tld4.meta_reg};
|
||||
IR::Value handle;
|
||||
|
|
@ -160,7 +163,7 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||
dref = v.F(meta_reg++);
|
||||
}
|
||||
IR::TextureInstInfo info{};
|
||||
info.type.Assign(GetType(tld4.type));
|
||||
info.type.Assign(GetTextureGatherType(tld4.type));
|
||||
info.is_depth.Assign(tld4.dc != 0 ? 1 : 0);
|
||||
info.gather_component.Assign(static_cast<u32>(component_type));
|
||||
const IR::Value sample{[&] {
|
||||
|
|
@ -187,7 +190,7 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy
|
|||
void TranslatorVisitor::TLD4(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<56, 2, ComponentType> component;
|
||||
BitField<56, 2, TextureGatherComponentType> component;
|
||||
BitField<54, 2, OffsetType> offset;
|
||||
} const tld4{insn};
|
||||
Impl(*this, insn, tld4.component, tld4.offset, false);
|
||||
|
|
@ -196,7 +199,7 @@ void TranslatorVisitor::TLD4(u64 insn) {
|
|||
void TranslatorVisitor::TLD4_b(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<38, 2, ComponentType> component;
|
||||
BitField<38, 2, TextureGatherComponentType> component;
|
||||
BitField<36, 2, OffsetType> offset;
|
||||
} const tld4{insn};
|
||||
Impl(*this, insn, tld4.component, tld4.offset, true);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -8,22 +11,22 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Precision : u64 {
|
||||
enum class TextureGatherSwizzledPrecision : u64 {
|
||||
F32,
|
||||
F16,
|
||||
};
|
||||
|
||||
enum class ComponentType : u64 {
|
||||
enum class TextureGatherSwizzledComponentType : u64 {
|
||||
R = 0,
|
||||
G = 1,
|
||||
B = 2,
|
||||
A = 3,
|
||||
};
|
||||
|
||||
union Encoding {
|
||||
union EncodinTGS {
|
||||
u64 raw;
|
||||
BitField<55, 1, Precision> precision;
|
||||
BitField<52, 2, ComponentType> component_type;
|
||||
BitField<55, 1, TextureGatherSwizzledPrecision> precision;
|
||||
BitField<52, 2, TextureGatherSwizzledComponentType> component_type;
|
||||
BitField<51, 1, u64> aoffi;
|
||||
BitField<50, 1, u64> dc;
|
||||
BitField<49, 1, u64> nodep;
|
||||
|
|
@ -34,7 +37,7 @@ union Encoding {
|
|||
BitField<36, 13, u64> cbuf_offset;
|
||||
};
|
||||
|
||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
||||
void CheckAlignmentTGS(IR::Reg reg, size_t alignment) {
|
||||
if (!IR::IsAligned(reg, alignment)) {
|
||||
throw NotImplementedException("Unaligned source register {}", reg);
|
||||
}
|
||||
|
|
@ -46,13 +49,13 @@ IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg) {
|
|||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(6), true));
|
||||
}
|
||||
|
||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
||||
const Encoding tld4s{insn};
|
||||
IR::Value SampleTGS(TranslatorVisitor& v, u64 insn) {
|
||||
const EncodinTGS tld4s{insn};
|
||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tld4s.cbuf_offset * 4))};
|
||||
const IR::Reg reg_a{tld4s.src_reg_a};
|
||||
const IR::Reg reg_b{tld4s.src_reg_b};
|
||||
IR::TextureInstInfo info{};
|
||||
if (tld4s.precision == Precision::F16) {
|
||||
if (tld4s.precision == TextureGatherSwizzledPrecision::F16) {
|
||||
info.relaxed_precision.Assign(1);
|
||||
}
|
||||
info.gather_component.Assign(static_cast<u32>(tld4s.component_type.Value()));
|
||||
|
|
@ -60,18 +63,18 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
info.is_depth.Assign(tld4s.dc != 0 ? 1 : 0);
|
||||
IR::Value coords;
|
||||
if (tld4s.aoffi != 0) {
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTGS(reg_a, 2);
|
||||
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
||||
IR::Value offset = MakeOffset(v, reg_b);
|
||||
if (tld4s.dc != 0) {
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTGS(reg_b, 2);
|
||||
IR::F32 dref = v.F(reg_b + 1);
|
||||
return v.ir.ImageGatherDref(handle, coords, offset, {}, dref, info);
|
||||
}
|
||||
return v.ir.ImageGather(handle, coords, offset, {}, info);
|
||||
}
|
||||
if (tld4s.dc != 0) {
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTGS(reg_a, 2);
|
||||
coords = v.ir.CompositeConstruct(v.F(reg_a), v.F(reg_a + 1));
|
||||
IR::F32 dref = v.F(reg_b);
|
||||
return v.ir.ImageGatherDref(handle, coords, {}, {}, dref, info);
|
||||
|
|
@ -81,50 +84,50 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
}
|
||||
|
||||
IR::Reg RegStoreComponent32(u64 insn, size_t index) {
|
||||
const Encoding tlds4{insn};
|
||||
const EncodinTGS tlds4{insn};
|
||||
switch (index) {
|
||||
case 0:
|
||||
return tlds4.dest_reg_a;
|
||||
case 1:
|
||||
CheckAlignment(tlds4.dest_reg_a, 2);
|
||||
CheckAlignmentTGS(tlds4.dest_reg_a, 2);
|
||||
return tlds4.dest_reg_a + 1;
|
||||
case 2:
|
||||
return tlds4.dest_reg_b;
|
||||
case 3:
|
||||
CheckAlignment(tlds4.dest_reg_b, 2);
|
||||
CheckAlignmentTGS(tlds4.dest_reg_b, 2);
|
||||
return tlds4.dest_reg_b + 1;
|
||||
}
|
||||
throw LogicError("Invalid store index {}", index);
|
||||
}
|
||||
|
||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store32TGS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
for (size_t component = 0; component < 4; ++component) {
|
||||
const IR::Reg dest{RegStoreComponent32(insn, component)};
|
||||
v.F(dest, IR::F32{v.ir.CompositeExtract(sample, component)});
|
||||
}
|
||||
}
|
||||
|
||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
IR::U32 PackTGS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||
}
|
||||
|
||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store16TGS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
std::array<IR::F32, 4> swizzled;
|
||||
for (size_t component = 0; component < 4; ++component) {
|
||||
swizzled[component] = IR::F32{v.ir.CompositeExtract(sample, component)};
|
||||
}
|
||||
const Encoding tld4s{insn};
|
||||
v.X(tld4s.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
||||
v.X(tld4s.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
||||
const EncodinTGS tld4s{insn};
|
||||
v.X(tld4s.dest_reg_a, PackTGS(v, swizzled[0], swizzled[1]));
|
||||
v.X(tld4s.dest_reg_b, PackTGS(v, swizzled[2], swizzled[3]));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TLD4S(u64 insn) {
|
||||
const IR::Value sample{Sample(*this, insn)};
|
||||
if (Encoding{insn}.precision == Precision::F32) {
|
||||
Store32(*this, insn, sample);
|
||||
const IR::Value sample{SampleTGS(*this, insn)};
|
||||
if (EncodinTGS{insn}.precision == TextureGatherSwizzledPrecision::F32) {
|
||||
Store32TGS(*this, insn, sample);
|
||||
} else {
|
||||
Store16(*this, insn, sample);
|
||||
Store16TGS(*this, insn, sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
|
||||
enum class TextureType : u64 {
|
||||
enum class TextureGradientType : u64 {
|
||||
_1D,
|
||||
ARRAY_1D,
|
||||
_2D,
|
||||
|
|
@ -20,23 +23,23 @@ enum class TextureType : u64 {
|
|||
ARRAY_CUBE,
|
||||
};
|
||||
|
||||
Shader::TextureType GetType(TextureType type) {
|
||||
Shader::TextureType GetType(TextureGradientType type) {
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureGradientType::_1D:
|
||||
return Shader::TextureType::Color1D;
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureGradientType::ARRAY_1D:
|
||||
return Shader::TextureType::ColorArray1D;
|
||||
case TextureType::_2D:
|
||||
case TextureGradientType::_2D:
|
||||
return Shader::TextureType::Color2D;
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureGradientType::ARRAY_2D:
|
||||
return Shader::TextureType::ColorArray2D;
|
||||
case TextureType::_3D:
|
||||
case TextureGradientType::_3D:
|
||||
return Shader::TextureType::Color3D;
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureGradientType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureGradientType::CUBE:
|
||||
return Shader::TextureType::ColorCube;
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureGradientType::ARRAY_CUBE:
|
||||
return Shader::TextureType::ColorArrayCube;
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
|
|
@ -50,7 +53,7 @@ IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg, bool has_lod_clamp) {
|
|||
v.ir.BitFieldExtract(value, v.ir.Imm32(base + 4), v.ir.Imm32(4), true));
|
||||
}
|
||||
|
||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
void TextureGatherImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<49, 1, u64> nodep;
|
||||
|
|
@ -60,7 +63,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> derivative_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<28, 3, TextureGradientType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
} const txd{insn};
|
||||
|
|
@ -88,25 +91,25 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
return v.ir.ConvertUToF(32, 16, array_index);
|
||||
}};
|
||||
switch (txd.type) {
|
||||
case TextureType::_1D: {
|
||||
case TextureGradientType::_1D: {
|
||||
coords = v.F(base_reg);
|
||||
num_derivatives = 1;
|
||||
last_reg = base_reg + 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_1D: {
|
||||
case TextureGradientType::ARRAY_1D: {
|
||||
last_reg = base_reg + 1;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
|
||||
num_derivatives = 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::_2D: {
|
||||
case TextureGradientType::_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
|
||||
num_derivatives = 2;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_2D: {
|
||||
case TextureGradientType::ARRAY_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
|
||||
num_derivatives = 2;
|
||||
|
|
@ -170,11 +173,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TXD(u64 insn) {
|
||||
Impl(*this, insn, false);
|
||||
TextureGatherImpl(*this, insn, false);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::TXD_b(u64 insn) {
|
||||
Impl(*this, insn, true);
|
||||
TextureGatherImpl(*this, insn, true);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
|
||||
enum class TextureType : u64 {
|
||||
enum class TextureLoadType : u64 {
|
||||
_1D,
|
||||
ARRAY_1D,
|
||||
_2D,
|
||||
|
|
@ -20,77 +23,77 @@ enum class TextureType : u64 {
|
|||
ARRAY_CUBE,
|
||||
};
|
||||
|
||||
Shader::TextureType GetType(TextureType type) {
|
||||
Shader::TextureType GetType(TextureLoadType type) {
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureLoadType::_1D:
|
||||
return Shader::TextureType::Color1D;
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureLoadType::ARRAY_1D:
|
||||
return Shader::TextureType::ColorArray1D;
|
||||
case TextureType::_2D:
|
||||
case TextureLoadType::_2D:
|
||||
return Shader::TextureType::Color2D;
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureLoadType::ARRAY_2D:
|
||||
return Shader::TextureType::ColorArray2D;
|
||||
case TextureType::_3D:
|
||||
case TextureLoadType::_3D:
|
||||
return Shader::TextureType::Color3D;
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureLoadType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureLoadType::CUBE:
|
||||
return Shader::TextureType::ColorCube;
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureLoadType::ARRAY_CUBE:
|
||||
return Shader::TextureType::ColorArrayCube;
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureLoadType type) {
|
||||
const auto read_array{
|
||||
[&]() -> IR::U32 { return v.ir.BitFieldExtract(v.X(reg), v.ir.Imm32(0), v.ir.Imm32(16)); }};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureLoadType::_1D:
|
||||
return v.X(reg);
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureLoadType::ARRAY_1D:
|
||||
return v.ir.CompositeConstruct(v.X(reg + 1), read_array());
|
||||
case TextureType::_2D:
|
||||
case TextureLoadType::_2D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1));
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureLoadType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), read_array());
|
||||
case TextureType::_3D:
|
||||
case TextureLoadType::_3D:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureLoadType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureLoadType::CUBE:
|
||||
return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 2));
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureLoadType::ARRAY_CUBE:
|
||||
return v.ir.CompositeConstruct(v.X(reg + 1), v.X(reg + 2), v.X(reg + 3), read_array());
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureType type) {
|
||||
IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg& reg, TextureLoadType type) {
|
||||
const IR::U32 value{v.X(reg++)};
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureLoadType::_1D:
|
||||
case TextureLoadType::ARRAY_1D:
|
||||
return v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true);
|
||||
case TextureType::_2D:
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureLoadType::_2D:
|
||||
case TextureLoadType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||
case TextureType::_3D:
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureLoadType::_3D:
|
||||
case TextureLoadType::ARRAY_3D:
|
||||
return v.ir.CompositeConstruct(
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true),
|
||||
v.ir.BitFieldExtract(value, v.ir.Imm32(8), v.ir.Imm32(4), true));
|
||||
case TextureType::CUBE:
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureLoadType::CUBE:
|
||||
case TextureLoadType::ARRAY_CUBE:
|
||||
throw NotImplementedException("Illegal offset on CUBE sample");
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
void TextureLoadImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<49, 1, u64> nodep;
|
||||
|
|
@ -102,7 +105,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> meta_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<28, 3, TextureLoadType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
} const tld{insn};
|
||||
|
|
@ -152,11 +155,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TLD(u64 insn) {
|
||||
Impl(*this, insn, false);
|
||||
TextureLoadImpl(*this, insn, false);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::TLD_b(u64 insn) {
|
||||
Impl(*this, insn, true);
|
||||
TextureLoadImpl(*this, insn, true);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -10,38 +13,14 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Precision : u64 {
|
||||
enum class TextureLoadSwizzledPrecision : u64 {
|
||||
F16,
|
||||
F32,
|
||||
};
|
||||
|
||||
constexpr unsigned R = 1;
|
||||
constexpr unsigned G = 2;
|
||||
constexpr unsigned B = 4;
|
||||
constexpr unsigned A = 8;
|
||||
|
||||
constexpr std::array RG_LUT{
|
||||
R, //
|
||||
G, //
|
||||
B, //
|
||||
A, //
|
||||
R | G, //
|
||||
R | A, //
|
||||
G | A, //
|
||||
B | A, //
|
||||
};
|
||||
|
||||
constexpr std::array RGBA_LUT{
|
||||
R | G | B, //
|
||||
R | G | A, //
|
||||
R | B | A, //
|
||||
G | B | A, //
|
||||
R | G | B | A, //
|
||||
};
|
||||
|
||||
union Encoding {
|
||||
union EncodinTLS {
|
||||
u64 raw;
|
||||
BitField<59, 1, Precision> precision;
|
||||
BitField<59, 1, TextureLoadSwizzledPrecision> precision;
|
||||
BitField<54, 1, u64> aoffi;
|
||||
BitField<53, 1, u64> lod;
|
||||
BitField<55, 1, u64> ms;
|
||||
|
|
@ -55,7 +34,7 @@ union Encoding {
|
|||
BitField<53, 4, u64> encoding;
|
||||
};
|
||||
|
||||
void CheckAlignment(IR::Reg reg, size_t alignment) {
|
||||
void CheckAlignmentTLS(IR::Reg reg, size_t alignment) {
|
||||
if (!IR::IsAligned(reg, alignment)) {
|
||||
throw NotImplementedException("Unaligned source register {}", reg);
|
||||
}
|
||||
|
|
@ -67,8 +46,8 @@ IR::Value MakeOffset(TranslatorVisitor& v, IR::Reg reg) {
|
|||
v.ir.BitFieldExtract(value, v.ir.Imm32(4), v.ir.Imm32(4), true));
|
||||
}
|
||||
|
||||
IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
||||
const Encoding tlds{insn};
|
||||
IR::Value SampleTLS(TranslatorVisitor& v, u64 insn) {
|
||||
const EncodinTLS tlds{insn};
|
||||
const IR::U32 handle{v.ir.Imm32(static_cast<u32>(tlds.cbuf_offset * 4))};
|
||||
const IR::Reg reg_a{tlds.src_reg_a};
|
||||
const IR::Reg reg_b{tlds.src_reg_b};
|
||||
|
|
@ -92,38 +71,38 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_b));
|
||||
break;
|
||||
case 4:
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTLS(reg_a, 2);
|
||||
texture_type = Shader::TextureType::Color2D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||
offsets = MakeOffset(v, reg_b);
|
||||
break;
|
||||
case 5:
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTLS(reg_a, 2);
|
||||
texture_type = Shader::TextureType::Color2D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||
lod = v.X(reg_b);
|
||||
break;
|
||||
case 6:
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTLS(reg_a, 2);
|
||||
texture_type = Shader::TextureType::Color2D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||
multisample = v.X(reg_b);
|
||||
break;
|
||||
case 7:
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignmentTLS(reg_a, 2);
|
||||
texture_type = Shader::TextureType::Color3D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1), v.X(reg_b));
|
||||
break;
|
||||
case 8: {
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTLS(reg_b, 2);
|
||||
const IR::U32 array{v.ir.BitFieldExtract(v.X(reg_a), v.ir.Imm32(0), v.ir.Imm32(16))};
|
||||
texture_type = Shader::TextureType::ColorArray2D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_b), v.X(reg_b + 1), array);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
CheckAlignment(reg_a, 2);
|
||||
CheckAlignment(reg_b, 2);
|
||||
CheckAlignmentTLS(reg_a, 2);
|
||||
CheckAlignmentTLS(reg_b, 2);
|
||||
texture_type = Shader::TextureType::Color2D;
|
||||
coords = v.ir.CompositeConstruct(v.X(reg_a), v.X(reg_a + 1));
|
||||
lod = v.X(reg_b);
|
||||
|
|
@ -133,7 +112,7 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
throw NotImplementedException("Illegal encoding {}", tlds.encoding.Value());
|
||||
}
|
||||
IR::TextureInstInfo info{};
|
||||
if (tlds.precision == Precision::F16) {
|
||||
if (tlds.precision == TextureLoadSwizzledPrecision::F16) {
|
||||
info.relaxed_precision.Assign(1);
|
||||
}
|
||||
info.type.Assign(texture_type);
|
||||
|
|
@ -141,7 +120,32 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
|||
}
|
||||
|
||||
unsigned Swizzle(u64 insn) {
|
||||
const Encoding tlds{insn};
|
||||
#define R 1
|
||||
#define G 2
|
||||
#define B 4
|
||||
#define A 8
|
||||
static constexpr std::array<unsigned, 8> RG_LUT{
|
||||
R, //
|
||||
G, //
|
||||
B, //
|
||||
A, //
|
||||
R | G, //
|
||||
R | A, //
|
||||
G | A, //
|
||||
B | A, //
|
||||
};
|
||||
static constexpr std::array<unsigned, 5> RGBA_LUT{
|
||||
R | G | B, //
|
||||
R | G | A, //
|
||||
R | B | A, //
|
||||
G | B | A, //
|
||||
R | G | B | A, //
|
||||
};
|
||||
#undef R
|
||||
#undef G
|
||||
#undef B
|
||||
#undef A
|
||||
const EncodinTLS tlds{insn};
|
||||
const size_t encoding{tlds.swizzle};
|
||||
if (tlds.dest_reg_b == IR::Reg::RZ) {
|
||||
if (encoding >= RG_LUT.size()) {
|
||||
|
|
@ -161,23 +165,23 @@ IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned componen
|
|||
}
|
||||
|
||||
IR::Reg RegStoreComponent32(u64 insn, unsigned index) {
|
||||
const Encoding tlds{insn};
|
||||
const EncodinTLS tlds{insn};
|
||||
switch (index) {
|
||||
case 0:
|
||||
return tlds.dest_reg_a;
|
||||
case 1:
|
||||
CheckAlignment(tlds.dest_reg_a, 2);
|
||||
CheckAlignmentTLS(tlds.dest_reg_a, 2);
|
||||
return tlds.dest_reg_a + 1;
|
||||
case 2:
|
||||
return tlds.dest_reg_b;
|
||||
case 3:
|
||||
CheckAlignment(tlds.dest_reg_b, 2);
|
||||
CheckAlignmentTLS(tlds.dest_reg_b, 2);
|
||||
return tlds.dest_reg_b + 1;
|
||||
}
|
||||
throw LogicError("Invalid store index {}", index);
|
||||
}
|
||||
|
||||
void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store32TLS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
const unsigned swizzle{Swizzle(insn)};
|
||||
unsigned store_index{0};
|
||||
for (unsigned component = 0; component < 4; ++component) {
|
||||
|
|
@ -190,11 +194,11 @@ void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
}
|
||||
}
|
||||
|
||||
IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
IR::U32 PackTLS(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
|
||||
return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
|
||||
}
|
||||
|
||||
void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
void Store16TLS(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
||||
const unsigned swizzle{Swizzle(insn)};
|
||||
unsigned store_index{0};
|
||||
std::array<IR::F32, 4> swizzled;
|
||||
|
|
@ -206,23 +210,23 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
++store_index;
|
||||
}
|
||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||
const Encoding tlds{insn};
|
||||
const EncodinTLS tlds{insn};
|
||||
switch (store_index) {
|
||||
case 1:
|
||||
v.X(tlds.dest_reg_a, Pack(v, swizzled[0], zero));
|
||||
v.X(tlds.dest_reg_a, PackTLS(v, swizzled[0], zero));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
v.X(tlds.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
|
||||
v.X(tlds.dest_reg_a, PackTLS(v, swizzled[0], swizzled[1]));
|
||||
switch (store_index) {
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
v.X(tlds.dest_reg_b, Pack(v, swizzled[2], zero));
|
||||
v.X(tlds.dest_reg_b, PackTLS(v, swizzled[2], zero));
|
||||
break;
|
||||
case 4:
|
||||
v.X(tlds.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
|
||||
v.X(tlds.dest_reg_b, PackTLS(v, swizzled[2], swizzled[3]));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -231,11 +235,11 @@ void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TLDS(u64 insn) {
|
||||
const IR::Value sample{Sample(*this, insn)};
|
||||
if (Encoding{insn}.precision == Precision::F32) {
|
||||
Store32(*this, insn, sample);
|
||||
const IR::Value sample{SampleTLS(*this, insn)};
|
||||
if (EncodinTLS{insn}.precision == TextureLoadSwizzledPrecision::F32) {
|
||||
Store32TLS(*this, insn, sample);
|
||||
} else {
|
||||
Store16(*this, insn, sample);
|
||||
Store16TLS(*this, insn, sample);
|
||||
}
|
||||
}
|
||||
} // namespace Shader::Maxwell
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
|
||||
enum class TextureType : u64 {
|
||||
enum class TextureMipmapLevelType : u64 {
|
||||
_1D,
|
||||
ARRAY_1D,
|
||||
_2D,
|
||||
|
|
@ -20,53 +23,53 @@ enum class TextureType : u64 {
|
|||
ARRAY_CUBE,
|
||||
};
|
||||
|
||||
Shader::TextureType GetType(TextureType type) {
|
||||
Shader::TextureType GetType(TextureMipmapLevelType type) {
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureMipmapLevelType::_1D:
|
||||
return Shader::TextureType::Color1D;
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureMipmapLevelType::ARRAY_1D:
|
||||
return Shader::TextureType::ColorArray1D;
|
||||
case TextureType::_2D:
|
||||
case TextureMipmapLevelType::_2D:
|
||||
return Shader::TextureType::Color2D;
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureMipmapLevelType::ARRAY_2D:
|
||||
return Shader::TextureType::ColorArray2D;
|
||||
case TextureType::_3D:
|
||||
case TextureMipmapLevelType::_3D:
|
||||
return Shader::TextureType::Color3D;
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureMipmapLevelType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureMipmapLevelType::CUBE:
|
||||
return Shader::TextureType::ColorCube;
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureMipmapLevelType::ARRAY_CUBE:
|
||||
return Shader::TextureType::ColorArrayCube;
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) {
|
||||
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureMipmapLevelType type) {
|
||||
// The ISA reads an array component here, but this is not needed on high level shading languages
|
||||
// We are dropping this information.
|
||||
switch (type) {
|
||||
case TextureType::_1D:
|
||||
case TextureMipmapLevelType::_1D:
|
||||
return v.F(reg);
|
||||
case TextureType::ARRAY_1D:
|
||||
case TextureMipmapLevelType::ARRAY_1D:
|
||||
return v.F(reg + 1);
|
||||
case TextureType::_2D:
|
||||
case TextureMipmapLevelType::_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1));
|
||||
case TextureType::ARRAY_2D:
|
||||
case TextureMipmapLevelType::ARRAY_2D:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::_3D:
|
||||
case TextureMipmapLevelType::_3D:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_3D:
|
||||
case TextureMipmapLevelType::ARRAY_3D:
|
||||
throw NotImplementedException("3D array texture type");
|
||||
case TextureType::CUBE:
|
||||
case TextureMipmapLevelType::CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg), v.F(reg + 1), v.F(reg + 2));
|
||||
case TextureType::ARRAY_CUBE:
|
||||
case TextureMipmapLevelType::ARRAY_CUBE:
|
||||
return v.ir.CompositeConstruct(v.F(reg + 1), v.F(reg + 2), v.F(reg + 3));
|
||||
}
|
||||
throw NotImplementedException("Invalid texture type {}", type);
|
||||
}
|
||||
|
||||
void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
void TextureMipmapLevelImpl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<49, 1, u64> nodep;
|
||||
|
|
@ -74,7 +77,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> meta_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<28, 3, TextureMipmapLevelType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
} const tmml{insn};
|
||||
|
|
@ -113,11 +116,11 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::TMML(u64 insn) {
|
||||
Impl(*this, insn, false);
|
||||
TextureMipmapLevelImpl(*this, insn, false);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::TMML_b(u64 insn) {
|
||||
Impl(*this, insn, true);
|
||||
TextureMipmapLevelImpl(*this, insn, true);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -9,24 +12,24 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
enum class TextureQueryMode : u64 {
|
||||
Dimension = 1,
|
||||
TextureType = 2,
|
||||
SamplePos = 5,
|
||||
};
|
||||
|
||||
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg, u64 mask) {
|
||||
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, TextureQueryMode mode, IR::Reg src_reg, u64 mask) {
|
||||
switch (mode) {
|
||||
case Mode::Dimension: {
|
||||
case TextureQueryMode::Dimension: {
|
||||
const bool needs_num_mips{((mask >> 3) & 1) != 0};
|
||||
const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
|
||||
const IR::U32 lod{v.X(src_reg)};
|
||||
return v.ir.ImageQueryDimension(handle, lod, skip_mips);
|
||||
}
|
||||
case Mode::TextureType:
|
||||
case Mode::SamplePos:
|
||||
case TextureQueryMode::TextureType:
|
||||
case TextureQueryMode::SamplePos:
|
||||
default:
|
||||
throw NotImplementedException("Mode {}", mode);
|
||||
throw NotImplementedException("TextureQueryMode {}", mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +39,7 @@ void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) {
|
|||
BitField<49, 1, u64> nodep;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> src_reg;
|
||||
BitField<22, 3, Mode> mode;
|
||||
BitField<22, 3, TextureQueryMode> mode;
|
||||
BitField<31, 4, u64> mask;
|
||||
} const txq{insn};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -6,7 +9,7 @@
|
|||
|
||||
namespace Shader::Optimization {
|
||||
namespace {
|
||||
IR::Opcode Replace(IR::Opcode op) {
|
||||
IR::Opcode ReplaceFP16ToFP32(IR::Opcode op) {
|
||||
switch (op) {
|
||||
case IR::Opcode::FPAbs16:
|
||||
return IR::Opcode::FPAbs32;
|
||||
|
|
@ -131,7 +134,7 @@ IR::Opcode Replace(IR::Opcode op) {
|
|||
void LowerFp16ToFp32(IR::Program& program) {
|
||||
for (IR::Block* const block : program.blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
inst.ReplaceOpcode(Replace(inst.GetOpcode()));
|
||||
inst.ReplaceOpcode(ReplaceFP16ToFP32(inst.GetOpcode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ IR::Value F32ToPackedF64(IR::IREmitter& ir, const IR::Value& raw) {
|
|||
return ir.CompositeConstruct(lo, hi);
|
||||
}
|
||||
|
||||
IR::Opcode Replace(IR::Opcode op) {
|
||||
IR::Opcode ReplaceFP64ToFP32(IR::Opcode op) {
|
||||
switch (op) {
|
||||
case IR::Opcode::FPAbs64:
|
||||
return IR::Opcode::FPAbs32;
|
||||
|
|
@ -154,7 +157,7 @@ IR::Opcode Replace(IR::Opcode op) {
|
|||
}
|
||||
}
|
||||
|
||||
void Lower(IR::Block& block, IR::Inst& inst) {
|
||||
void LowerFP64ToFP32(IR::Block& block, IR::Inst& inst) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::PackDouble2x32: {
|
||||
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||
|
|
@ -167,7 +170,7 @@ void Lower(IR::Block& block, IR::Inst& inst) {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
inst.ReplaceOpcode(Replace(inst.GetOpcode()));
|
||||
inst.ReplaceOpcode(ReplaceFP64ToFP32(inst.GetOpcode()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -177,7 +180,7 @@ void Lower(IR::Block& block, IR::Inst& inst) {
|
|||
void LowerFp64ToFp32(IR::Program& program) {
|
||||
for (IR::Block* const block : program.blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
Lower(*block, inst);
|
||||
LowerFP64ToFP32(*block, inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -181,7 +184,7 @@ void ShiftRightArithmetic64To32(IR::Block& block, IR::Inst& inst) {
|
|||
inst.ReplaceUsesWith(ir.CompositeConstruct(ret_lo, ret_hi));
|
||||
}
|
||||
|
||||
void Lower(IR::Block& block, IR::Inst& inst) {
|
||||
void LowerI64ToI32(IR::Block& block, IR::Inst& inst) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::PackUint2x32:
|
||||
case IR::Opcode::UnpackUint2x32:
|
||||
|
|
@ -229,7 +232,7 @@ void LowerInt64ToInt32(IR::Program& program) {
|
|||
for (auto it = program.post_order_blocks.rbegin(); it != end; ++it) {
|
||||
IR::Block* const block{*it};
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
Lower(*block, inst);
|
||||
LowerI64ToI32(*block, inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue