mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-04-07 09:01:29 -06:00
shader_jit: Optimize GeometryEmitter SETEMIT state
The `SETEMIT`/`SETE` instruction only actually encodes 4 bits of possible state, but this is currently expanded into three separate bytes of data(four with padding) and requires three separate byte-writes for the x64 and a64 JITs to write into. These 4 bits from the instruction can instead be compacted into a singular 1-byte write from the JIT by encoding these 4 bits of state into a singular byte at JIT-time, and unpacking this data is instead done by `GeometryEmitter::Emit`. This also allows the serializer to use a singular byte for all 3 fields now as well.
This commit is contained in:
parent
60f331b43b
commit
4cbd75b413
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -29,15 +29,15 @@ void ShaderUnit::WriteOutput(const ShaderRegs& config, AttributeBuffer& buffer)
|
||||
}
|
||||
|
||||
void GeometryEmitter::Emit(std::span<Common::Vec4<f24>, 16> output_regs) {
|
||||
ASSERT(vertex_id < 3);
|
||||
ASSERT(emit_state.vertex_id < 3);
|
||||
|
||||
u32 output_index{};
|
||||
for (u32 reg : Common::BitSet<u32>(output_mask)) {
|
||||
buffer[vertex_id][output_index++] = output_regs[reg];
|
||||
buffer[emit_state.vertex_id][output_index++] = output_regs[reg];
|
||||
}
|
||||
|
||||
if (prim_emit) {
|
||||
if (winding) {
|
||||
if (emit_state.prim_emit) {
|
||||
if (emit_state.winding) {
|
||||
handlers->winding_setter();
|
||||
}
|
||||
for (std::size_t i = 0; i < buffer.size(); ++i) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -75,11 +75,18 @@ struct GeometryEmitter {
|
||||
void Emit(std::span<Common::Vec4<f24>, 16> output_regs);
|
||||
|
||||
public:
|
||||
std::array<AttributeBuffer, 3> buffer;
|
||||
u8 vertex_id;
|
||||
bool prim_emit;
|
||||
bool winding;
|
||||
union EmitState {
|
||||
struct {
|
||||
bool winding : 1;
|
||||
bool prim_emit : 1;
|
||||
u8 vertex_id : 2;
|
||||
};
|
||||
u8 raw;
|
||||
} emit_state;
|
||||
static_assert(sizeof(emit_state) == 1);
|
||||
|
||||
u32 output_mask;
|
||||
std::array<AttributeBuffer, 3> buffer;
|
||||
Handlers* handlers;
|
||||
|
||||
private:
|
||||
@ -87,9 +94,7 @@ private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const u32 file_version) {
|
||||
ar & buffer;
|
||||
ar & vertex_id;
|
||||
ar & prim_emit;
|
||||
ar & winding;
|
||||
ar & emit_state.raw;
|
||||
ar & output_mask;
|
||||
}
|
||||
};
|
||||
|
||||
@ -671,9 +671,9 @@ static void RunInterpreter(const ShaderSetup& setup, ShaderUnit& state,
|
||||
case OpCode::Id::SETEMIT: {
|
||||
auto* emitter = state.emitter_ptr;
|
||||
ASSERT_MSG(emitter, "Execute SETEMIT on VS");
|
||||
emitter->vertex_id = instr.setemit.vertex_id;
|
||||
emitter->prim_emit = instr.setemit.prim_emit != 0;
|
||||
emitter->winding = instr.setemit.winding != 0;
|
||||
emitter->emit_state.vertex_id = instr.setemit.vertex_id;
|
||||
emitter->emit_state.prim_emit = instr.setemit.prim_emit != 0;
|
||||
emitter->emit_state.winding = instr.setemit.winding != 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -865,12 +865,13 @@ void JitShader::Compile_SETE(Instruction instr) {
|
||||
|
||||
l(have_emitter);
|
||||
|
||||
MOV(XSCRATCH1.toW(), instr.setemit.vertex_id);
|
||||
STRB(XSCRATCH1.toW(), XSCRATCH0, u32(offsetof(GeometryEmitter, vertex_id)));
|
||||
MOV(XSCRATCH1.toW(), instr.setemit.prim_emit);
|
||||
STRB(XSCRATCH1.toW(), XSCRATCH0, u32(offsetof(GeometryEmitter, prim_emit)));
|
||||
MOV(XSCRATCH1.toW(), instr.setemit.winding);
|
||||
STRB(XSCRATCH1.toW(), XSCRATCH0, u32(offsetof(GeometryEmitter, winding)));
|
||||
const GeometryEmitter::EmitState new_state{
|
||||
.winding = instr.setemit.winding != 0,
|
||||
.prim_emit = instr.setemit.prim_emit != 0,
|
||||
.vertex_id = static_cast<uint8_t>(instr.setemit.vertex_id),
|
||||
};
|
||||
MOV(XSCRATCH1.toW(), new_state.raw);
|
||||
STRB(XSCRATCH1.toW(), XSCRATCH0, u32(offsetof(GeometryEmitter, emit_state)));
|
||||
|
||||
l(end);
|
||||
}
|
||||
|
||||
@ -905,9 +905,12 @@ void JitShader::Compile_SETE(Instruction instr) {
|
||||
jmp(end);
|
||||
|
||||
L(have_emitter);
|
||||
mov(byte[rax + offsetof(GeometryEmitter, vertex_id)], instr.setemit.vertex_id);
|
||||
mov(byte[rax + offsetof(GeometryEmitter, prim_emit)], instr.setemit.prim_emit);
|
||||
mov(byte[rax + offsetof(GeometryEmitter, winding)], instr.setemit.winding);
|
||||
const GeometryEmitter::EmitState new_state{
|
||||
.winding = instr.setemit.winding != 0,
|
||||
.prim_emit = instr.setemit.prim_emit != 0,
|
||||
.vertex_id = static_cast<uint8_t>(instr.setemit.vertex_id),
|
||||
};
|
||||
mov(byte[rax + offsetof(GeometryEmitter, emit_state)], new_state.raw);
|
||||
L(end);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user