mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 19:20:15 +00:00
Make shader code less VS-specific
This commit is contained in:
parent
63557e3fc1
commit
2796552790
@ -501,7 +501,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
|
||||
info.labels.insert({ entry_point, "main" });
|
||||
|
||||
// Generate debug information
|
||||
debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup);
|
||||
debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config);
|
||||
|
||||
// Reload widget state
|
||||
for (int attr = 0; attr < num_attributes; ++attr) {
|
||||
|
@ -149,7 +149,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||
// Send to vertex shader
|
||||
if (g_debug_context)
|
||||
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, static_cast<void*>(&immediate_input));
|
||||
g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1);
|
||||
g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1, regs.vs);
|
||||
Shader::OutputVertex output_vertex = shader_unit.output_registers.ToVertex(regs.vs);
|
||||
|
||||
// Send to renderer
|
||||
@ -274,7 +274,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||
// Send to vertex shader
|
||||
if (g_debug_context)
|
||||
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, (void*)&input);
|
||||
g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes());
|
||||
g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes(), regs.vs);
|
||||
output_registers = shader_unit.output_registers;
|
||||
|
||||
if (is_indexed) {
|
||||
|
@ -83,8 +83,7 @@ OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) {
|
||||
}
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
static std::unordered_map<u64, std::unique_ptr<JitShader>> shader_map;
|
||||
static const JitShader* jit_shader;
|
||||
static std::unordered_map<u64, std::shared_ptr<JitShader>> shader_map;
|
||||
#endif // ARCHITECTURE_x86_64
|
||||
|
||||
void ClearCache() {
|
||||
@ -96,16 +95,16 @@ void ClearCache() {
|
||||
void ShaderSetup::Setup() {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
if (VideoCore::g_shader_jit_enabled) {
|
||||
u64 cache_key = (Common::ComputeHash64(&g_state.vs.program_code, sizeof(g_state.vs.program_code)) ^
|
||||
Common::ComputeHash64(&g_state.vs.swizzle_data, sizeof(g_state.vs.swizzle_data)));
|
||||
u64 cache_key = (Common::ComputeHash64(&program_code, sizeof(program_code)) ^
|
||||
Common::ComputeHash64(&swizzle_data, sizeof(swizzle_data)));
|
||||
|
||||
auto iter = shader_map.find(cache_key);
|
||||
if (iter != shader_map.end()) {
|
||||
jit_shader = iter->second.get();
|
||||
jit_shader = iter->second;
|
||||
} else {
|
||||
auto shader = std::make_unique<JitShader>();
|
||||
shader->Compile();
|
||||
jit_shader = shader.get();
|
||||
auto shader = std::make_shared<JitShader>();
|
||||
shader->Compile(*this);
|
||||
jit_shader = shader;
|
||||
shader_map[cache_key] = std::move(shader);
|
||||
}
|
||||
}
|
||||
@ -114,9 +113,7 @@ void ShaderSetup::Setup() {
|
||||
|
||||
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
|
||||
|
||||
void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
|
||||
auto& config = g_state.regs.vs;
|
||||
auto& setup = g_state.vs;
|
||||
void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config) {
|
||||
|
||||
MICROPROFILE_SCOPE(GPU_Shader);
|
||||
|
||||
@ -134,16 +131,16 @@ void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
if (VideoCore::g_shader_jit_enabled)
|
||||
jit_shader->Run(setup, state, config.main_offset);
|
||||
jit_shader.lock().get()->Run(*this, state, config.main_offset);
|
||||
else
|
||||
RunInterpreter(setup, state, config.main_offset);
|
||||
RunInterpreter(*this, state, config.main_offset);
|
||||
#else
|
||||
RunInterpreter(setup, state, config.main_offset);
|
||||
RunInterpreter(*this, state, config.main_offset);
|
||||
#endif // ARCHITECTURE_x86_64
|
||||
|
||||
}
|
||||
|
||||
DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup) {
|
||||
DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config) {
|
||||
UnitState<true> state;
|
||||
|
||||
state.debug.max_offset = 0;
|
||||
@ -160,7 +157,7 @@ DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_
|
||||
state.conditional_code[0] = false;
|
||||
state.conditional_code[1] = false;
|
||||
|
||||
RunInterpreter(setup, state, config.main_offset);
|
||||
RunInterpreter(*this, state, config.main_offset);
|
||||
return state.debug;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,11 @@ namespace Pica {
|
||||
|
||||
namespace Shader {
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
// Forward declare JitShader because shader_jit_x64.h requires ShaderSetup (which uses JitShader) from this file
|
||||
class JitShader;
|
||||
#endif // ARCHITECTURE_x86_64
|
||||
|
||||
struct InputVertex {
|
||||
alignas(16) Math::Vec4<float24> attr[16];
|
||||
};
|
||||
@ -191,9 +196,9 @@ inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* va
|
||||
record.src3.x = value[0];
|
||||
record.src3.y = value[1];
|
||||
record.src3.z = value[2];
|
||||
|
||||
record.src3.w = value[3];
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) {
|
||||
record.dest_in.x = value[0];
|
||||
@ -353,8 +358,12 @@ struct ShaderSetup {
|
||||
std::array<u32, 1024> program_code;
|
||||
std::array<u32, 1024> swizzle_data;
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
std::weak_ptr<const JitShader> jit_shader;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Performs any shader unit setup that only needs to happen once per shader (as opposed to once per
|
||||
* Performs any shader setup that only needs to happen once per shader (as opposed to once per
|
||||
* vertex, which would happen within the `Run` function).
|
||||
*/
|
||||
void Setup();
|
||||
@ -364,18 +373,18 @@ struct ShaderSetup {
|
||||
* @param state Shader unit state, must be setup per shader and per shader unit
|
||||
* @param input Input vertex into the shader
|
||||
* @param num_attributes The number of vertex shader attributes
|
||||
* @param config Configuration object for the shader pipeline
|
||||
*/
|
||||
void Run(UnitState<false>& state, const InputVertex& input, int num_attributes);
|
||||
void Run(UnitState<false>& state, const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config);
|
||||
|
||||
/**
|
||||
* Produce debug information based on the given shader and input vertex
|
||||
* @param input Input vertex into the shader
|
||||
* @param num_attributes The number of vertex shader attributes
|
||||
* @param config Configuration object for the shader pipeline
|
||||
* @param setup Setup object for the shader pipeline
|
||||
* @return Debug information for this shader with regards to the given vertex
|
||||
*/
|
||||
DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup);
|
||||
DebugData<true> ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config);
|
||||
|
||||
};
|
||||
|
||||
|
@ -47,9 +47,9 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
|
||||
|
||||
u32 program_counter = offset;
|
||||
|
||||
const auto& uniforms = g_state.vs.uniforms;
|
||||
const auto& swizzle_data = g_state.vs.swizzle_data;
|
||||
const auto& program_code = g_state.vs.program_code;
|
||||
const auto& uniforms = setup.uniforms;
|
||||
const auto& swizzle_data = setup.swizzle_data;
|
||||
const auto& program_code = setup.program_code;
|
||||
|
||||
// Placeholder for invalid inputs
|
||||
static float24 dummy_vec4_float24[4];
|
||||
|
@ -146,15 +146,6 @@ static const u8 NO_SRC_REG_SWIZZLE = 0x1b;
|
||||
/// Raw constant for the destination register enable mask that indicates all components are enabled
|
||||
static const u8 NO_DEST_REG_MASK = 0xf;
|
||||
|
||||
/**
|
||||
* Get the vertex shader instruction for a given offset in the current shader program
|
||||
* @param offset Offset in the current shader program of the instruction
|
||||
* @return Instruction at the specified offset
|
||||
*/
|
||||
static Instruction GetVertexShaderInstruction(size_t offset) {
|
||||
return { g_state.vs.program_code[offset] };
|
||||
}
|
||||
|
||||
static void LogCritical(const char* msg) {
|
||||
LOG_CRITICAL(HW_GPU, "%s", msg);
|
||||
}
|
||||
@ -225,7 +216,7 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
|
||||
MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
|
||||
}
|
||||
|
||||
SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] };
|
||||
SwizzlePattern swiz = { setup->swizzle_data[operand_desc_id] };
|
||||
|
||||
// Generate instructions for source register swizzling as needed
|
||||
u8 sel = swiz.GetRawSelector(src_num);
|
||||
@ -256,7 +247,7 @@ void JitShader::Compile_DestEnable(Instruction instr,X64Reg src) {
|
||||
dest = instr.common.dest.Value();
|
||||
}
|
||||
|
||||
SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] };
|
||||
SwizzlePattern swiz = { setup->swizzle_data[operand_desc_id] };
|
||||
|
||||
int dest_offset_disp = (int)UnitState<false>::OutputOffset(dest);
|
||||
ASSERT_MSG(dest_offset_disp == UnitState<false>::OutputOffset(dest), "Destinaton offset too large for int type");
|
||||
@ -512,7 +503,7 @@ void JitShader::Compile_MIN(Instruction instr) {
|
||||
}
|
||||
|
||||
void JitShader::Compile_MOVA(Instruction instr) {
|
||||
SwizzlePattern swiz = { g_state.vs.swizzle_data[instr.common.operand_desc_id] };
|
||||
SwizzlePattern swiz = { setup->swizzle_data[instr.common.operand_desc_id] };
|
||||
|
||||
if (!swiz.DestComponentEnabled(0) && !swiz.DestComponentEnabled(1)) {
|
||||
return; // NoOp
|
||||
@ -776,7 +767,7 @@ void JitShader::Compile_NextInstr() {
|
||||
ASSERT_MSG(code_ptr[program_counter] == nullptr, "Tried to compile already compiled shader location!");
|
||||
code_ptr[program_counter] = GetCodePtr();
|
||||
|
||||
Instruction instr = GetVertexShaderInstruction(program_counter++);
|
||||
Instruction instr = GetShaderInstruction(program_counter++);
|
||||
|
||||
OpCode::Id opcode = instr.opcode.Value();
|
||||
auto instr_func = instr_table[static_cast<unsigned>(opcode)];
|
||||
@ -794,8 +785,8 @@ void JitShader::Compile_NextInstr() {
|
||||
void JitShader::FindReturnOffsets() {
|
||||
return_offsets.clear();
|
||||
|
||||
for (size_t offset = 0; offset < g_state.vs.program_code.size(); ++offset) {
|
||||
Instruction instr = GetVertexShaderInstruction(offset);
|
||||
for (size_t offset = 0; offset < setup->program_code.size(); ++offset) {
|
||||
Instruction instr = GetShaderInstruction(offset);
|
||||
|
||||
switch (instr.opcode.Value()) {
|
||||
case OpCode::Id::CALL:
|
||||
@ -812,7 +803,11 @@ void JitShader::FindReturnOffsets() {
|
||||
std::sort(return_offsets.begin(), return_offsets.end());
|
||||
}
|
||||
|
||||
void JitShader::Compile() {
|
||||
void JitShader::Compile(const ShaderSetup& setup) {
|
||||
|
||||
// Get a pointer to the setup to access program_code and swizzle_data
|
||||
this->setup = &setup;
|
||||
|
||||
// Reset flow control state
|
||||
program = (CompiledShader*)GetCodePtr();
|
||||
program_counter = 0;
|
||||
@ -848,7 +843,7 @@ void JitShader::Compile() {
|
||||
JMPptr(R(ABI_PARAM3));
|
||||
|
||||
// Compile entire program
|
||||
Compile_Block(static_cast<unsigned>(g_state.vs.program_code.size()));
|
||||
Compile_Block(static_cast<unsigned>(this->setup->program_code.size()));
|
||||
|
||||
// Set the target for any incomplete branches now that the entire shader program has been emitted
|
||||
for (const auto& branch : fixup_branches) {
|
||||
@ -865,6 +860,9 @@ void JitShader::Compile() {
|
||||
ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
|
||||
|
||||
LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size);
|
||||
|
||||
// We don't need the setup anymore
|
||||
this->setup = nullptr;
|
||||
}
|
||||
|
||||
JitShader::JitShader() {
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
program(&setup, &state, code_ptr[offset]);
|
||||
}
|
||||
|
||||
void Compile();
|
||||
void Compile(const ShaderSetup& setup);
|
||||
|
||||
void Compile_ADD(Instruction instr);
|
||||
void Compile_DP3(Instruction instr);
|
||||
@ -99,6 +99,17 @@ private:
|
||||
*/
|
||||
void Compile_Assert(bool condition, const char* msg);
|
||||
|
||||
/**
|
||||
* Get the shader instruction for a given offset in the current shader program
|
||||
* @param offset Offset in the current shader program of the instruction
|
||||
* @return Instruction at the specified offset
|
||||
*/
|
||||
Instruction GetShaderInstruction(size_t offset) {
|
||||
Instruction instruction;
|
||||
std::memcpy(&instruction, &setup->program_code[offset], sizeof(Instruction));
|
||||
return instruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the entire shader program for `CALL` instructions before emitting any code,
|
||||
* identifying the locations where a return needs to be inserted.
|
||||
@ -119,6 +130,8 @@ private:
|
||||
|
||||
using CompiledShader = void(const void* setup, void* state, const u8* start_addr);
|
||||
CompiledShader* program = nullptr;
|
||||
|
||||
const ShaderSetup* setup = nullptr;
|
||||
};
|
||||
|
||||
} // Shader
|
||||
|
Loading…
Reference in New Issue
Block a user