mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 21:40:14 +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" });
|
info.labels.insert({ entry_point, "main" });
|
||||||
|
|
||||||
// Generate debug information
|
// 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
|
// Reload widget state
|
||||||
for (int attr = 0; attr < num_attributes; ++attr) {
|
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
|
// Send to vertex shader
|
||||||
if (g_debug_context)
|
if (g_debug_context)
|
||||||
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, static_cast<void*>(&immediate_input));
|
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);
|
Shader::OutputVertex output_vertex = shader_unit.output_registers.ToVertex(regs.vs);
|
||||||
|
|
||||||
// Send to renderer
|
// Send to renderer
|
||||||
@ -274,7 +274,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
// Send to vertex shader
|
// Send to vertex shader
|
||||||
if (g_debug_context)
|
if (g_debug_context)
|
||||||
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, (void*)&input);
|
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;
|
output_registers = shader_unit.output_registers;
|
||||||
|
|
||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
|
@ -83,8 +83,7 @@ OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
static std::unordered_map<u64, std::unique_ptr<JitShader>> shader_map;
|
static std::unordered_map<u64, std::shared_ptr<JitShader>> shader_map;
|
||||||
static const JitShader* jit_shader;
|
|
||||||
#endif // ARCHITECTURE_x86_64
|
#endif // ARCHITECTURE_x86_64
|
||||||
|
|
||||||
void ClearCache() {
|
void ClearCache() {
|
||||||
@ -96,16 +95,16 @@ void ClearCache() {
|
|||||||
void ShaderSetup::Setup() {
|
void ShaderSetup::Setup() {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
if (VideoCore::g_shader_jit_enabled) {
|
if (VideoCore::g_shader_jit_enabled) {
|
||||||
u64 cache_key = (Common::ComputeHash64(&g_state.vs.program_code, sizeof(g_state.vs.program_code)) ^
|
u64 cache_key = (Common::ComputeHash64(&program_code, sizeof(program_code)) ^
|
||||||
Common::ComputeHash64(&g_state.vs.swizzle_data, sizeof(g_state.vs.swizzle_data)));
|
Common::ComputeHash64(&swizzle_data, sizeof(swizzle_data)));
|
||||||
|
|
||||||
auto iter = shader_map.find(cache_key);
|
auto iter = shader_map.find(cache_key);
|
||||||
if (iter != shader_map.end()) {
|
if (iter != shader_map.end()) {
|
||||||
jit_shader = iter->second.get();
|
jit_shader = iter->second;
|
||||||
} else {
|
} else {
|
||||||
auto shader = std::make_unique<JitShader>();
|
auto shader = std::make_shared<JitShader>();
|
||||||
shader->Compile();
|
shader->Compile(*this);
|
||||||
jit_shader = shader.get();
|
jit_shader = shader;
|
||||||
shader_map[cache_key] = std::move(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));
|
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
|
||||||
|
|
||||||
void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
|
void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config) {
|
||||||
auto& config = g_state.regs.vs;
|
|
||||||
auto& setup = g_state.vs;
|
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(GPU_Shader);
|
MICROPROFILE_SCOPE(GPU_Shader);
|
||||||
|
|
||||||
@ -134,16 +131,16 @@ void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num
|
|||||||
|
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
if (VideoCore::g_shader_jit_enabled)
|
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
|
else
|
||||||
RunInterpreter(setup, state, config.main_offset);
|
RunInterpreter(*this, state, config.main_offset);
|
||||||
#else
|
#else
|
||||||
RunInterpreter(setup, state, config.main_offset);
|
RunInterpreter(*this, state, config.main_offset);
|
||||||
#endif // ARCHITECTURE_x86_64
|
#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;
|
UnitState<true> state;
|
||||||
|
|
||||||
state.debug.max_offset = 0;
|
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[0] = false;
|
||||||
state.conditional_code[1] = false;
|
state.conditional_code[1] = false;
|
||||||
|
|
||||||
RunInterpreter(setup, state, config.main_offset);
|
RunInterpreter(*this, state, config.main_offset);
|
||||||
return state.debug;
|
return state.debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,11 @@ namespace Pica {
|
|||||||
|
|
||||||
namespace Shader {
|
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 {
|
struct InputVertex {
|
||||||
alignas(16) Math::Vec4<float24> attr[16];
|
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.x = value[0];
|
||||||
record.src3.y = value[1];
|
record.src3.y = value[1];
|
||||||
record.src3.z = value[2];
|
record.src3.z = value[2];
|
||||||
|
|
||||||
record.src3.w = value[3];
|
record.src3.w = value[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) {
|
inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) {
|
||||||
record.dest_in.x = value[0];
|
record.dest_in.x = value[0];
|
||||||
@ -353,8 +358,12 @@ struct ShaderSetup {
|
|||||||
std::array<u32, 1024> program_code;
|
std::array<u32, 1024> program_code;
|
||||||
std::array<u32, 1024> swizzle_data;
|
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).
|
* vertex, which would happen within the `Run` function).
|
||||||
*/
|
*/
|
||||||
void Setup();
|
void Setup();
|
||||||
@ -364,18 +373,18 @@ struct ShaderSetup {
|
|||||||
* @param state Shader unit state, must be setup per shader and per shader unit
|
* @param state Shader unit state, must be setup per shader and per shader unit
|
||||||
* @param input Input vertex into the shader
|
* @param input Input vertex into the shader
|
||||||
* @param num_attributes The number of vertex shader attributes
|
* @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
|
* Produce debug information based on the given shader and input vertex
|
||||||
* @param input Input vertex into the shader
|
* @param input Input vertex into the shader
|
||||||
* @param num_attributes The number of vertex shader attributes
|
* @param num_attributes The number of vertex shader attributes
|
||||||
* @param config Configuration object for the shader pipeline
|
* @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
|
* @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;
|
u32 program_counter = offset;
|
||||||
|
|
||||||
const auto& uniforms = g_state.vs.uniforms;
|
const auto& uniforms = setup.uniforms;
|
||||||
const auto& swizzle_data = g_state.vs.swizzle_data;
|
const auto& swizzle_data = setup.swizzle_data;
|
||||||
const auto& program_code = g_state.vs.program_code;
|
const auto& program_code = setup.program_code;
|
||||||
|
|
||||||
// Placeholder for invalid inputs
|
// Placeholder for invalid inputs
|
||||||
static float24 dummy_vec4_float24[4];
|
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
|
/// Raw constant for the destination register enable mask that indicates all components are enabled
|
||||||
static const u8 NO_DEST_REG_MASK = 0xf;
|
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) {
|
static void LogCritical(const char* msg) {
|
||||||
LOG_CRITICAL(HW_GPU, "%s", 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));
|
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
|
// Generate instructions for source register swizzling as needed
|
||||||
u8 sel = swiz.GetRawSelector(src_num);
|
u8 sel = swiz.GetRawSelector(src_num);
|
||||||
@ -256,7 +247,7 @@ void JitShader::Compile_DestEnable(Instruction instr,X64Reg src) {
|
|||||||
dest = instr.common.dest.Value();
|
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);
|
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");
|
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) {
|
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)) {
|
if (!swiz.DestComponentEnabled(0) && !swiz.DestComponentEnabled(1)) {
|
||||||
return; // NoOp
|
return; // NoOp
|
||||||
@ -776,7 +767,7 @@ void JitShader::Compile_NextInstr() {
|
|||||||
ASSERT_MSG(code_ptr[program_counter] == nullptr, "Tried to compile already compiled shader location!");
|
ASSERT_MSG(code_ptr[program_counter] == nullptr, "Tried to compile already compiled shader location!");
|
||||||
code_ptr[program_counter] = GetCodePtr();
|
code_ptr[program_counter] = GetCodePtr();
|
||||||
|
|
||||||
Instruction instr = GetVertexShaderInstruction(program_counter++);
|
Instruction instr = GetShaderInstruction(program_counter++);
|
||||||
|
|
||||||
OpCode::Id opcode = instr.opcode.Value();
|
OpCode::Id opcode = instr.opcode.Value();
|
||||||
auto instr_func = instr_table[static_cast<unsigned>(opcode)];
|
auto instr_func = instr_table[static_cast<unsigned>(opcode)];
|
||||||
@ -794,8 +785,8 @@ void JitShader::Compile_NextInstr() {
|
|||||||
void JitShader::FindReturnOffsets() {
|
void JitShader::FindReturnOffsets() {
|
||||||
return_offsets.clear();
|
return_offsets.clear();
|
||||||
|
|
||||||
for (size_t offset = 0; offset < g_state.vs.program_code.size(); ++offset) {
|
for (size_t offset = 0; offset < setup->program_code.size(); ++offset) {
|
||||||
Instruction instr = GetVertexShaderInstruction(offset);
|
Instruction instr = GetShaderInstruction(offset);
|
||||||
|
|
||||||
switch (instr.opcode.Value()) {
|
switch (instr.opcode.Value()) {
|
||||||
case OpCode::Id::CALL:
|
case OpCode::Id::CALL:
|
||||||
@ -812,7 +803,11 @@ void JitShader::FindReturnOffsets() {
|
|||||||
std::sort(return_offsets.begin(), return_offsets.end());
|
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
|
// Reset flow control state
|
||||||
program = (CompiledShader*)GetCodePtr();
|
program = (CompiledShader*)GetCodePtr();
|
||||||
program_counter = 0;
|
program_counter = 0;
|
||||||
@ -848,7 +843,7 @@ void JitShader::Compile() {
|
|||||||
JMPptr(R(ABI_PARAM3));
|
JMPptr(R(ABI_PARAM3));
|
||||||
|
|
||||||
// Compile entire program
|
// 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
|
// Set the target for any incomplete branches now that the entire shader program has been emitted
|
||||||
for (const auto& branch : fixup_branches) {
|
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!");
|
ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
|
||||||
|
|
||||||
LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size);
|
LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size);
|
||||||
|
|
||||||
|
// We don't need the setup anymore
|
||||||
|
this->setup = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JitShader::JitShader() {
|
JitShader::JitShader() {
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
program(&setup, &state, code_ptr[offset]);
|
program(&setup, &state, code_ptr[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compile();
|
void Compile(const ShaderSetup& setup);
|
||||||
|
|
||||||
void Compile_ADD(Instruction instr);
|
void Compile_ADD(Instruction instr);
|
||||||
void Compile_DP3(Instruction instr);
|
void Compile_DP3(Instruction instr);
|
||||||
@ -99,6 +99,17 @@ private:
|
|||||||
*/
|
*/
|
||||||
void Compile_Assert(bool condition, const char* msg);
|
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,
|
* Analyzes the entire shader program for `CALL` instructions before emitting any code,
|
||||||
* identifying the locations where a return needs to be inserted.
|
* 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);
|
using CompiledShader = void(const void* setup, void* state, const u8* start_addr);
|
||||||
CompiledShader* program = nullptr;
|
CompiledShader* program = nullptr;
|
||||||
|
|
||||||
|
const ShaderSetup* setup = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Shader
|
} // Shader
|
||||||
|
Loading…
Reference in New Issue
Block a user