Make shader code less VS-specific

This commit is contained in:
Jannik Vogel 2016-03-30 06:42:30 +02:00
parent 63557e3fc1
commit 2796552790
7 changed files with 62 additions and 45 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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);
}; };

View File

@ -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];

View File

@ -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() {

View File

@ -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