diff options
Diffstat (limited to 'src/video_core/shader')
| -rw-r--r-- | src/video_core/shader/shader.cpp | 65 | ||||
| -rw-r--r-- | src/video_core/shader/shader.h | 65 | ||||
| -rw-r--r-- | src/video_core/shader/shader_interpreter.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/shader/shader_interpreter.h | 8 | ||||
| -rw-r--r-- | src/video_core/shader/shader_jit_x64_compiler.cpp | 17 | ||||
| -rw-r--r-- | src/video_core/shader/shader_jit_x64_compiler.h | 4 |
6 files changed, 80 insertions, 85 deletions
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 2da50bd62..67ed19ba8 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -4,10 +4,12 @@ #include <cmath> #include <cstring> +#include "common/bit_set.h" #include "common/logging/log.h" #include "common/microprofile.h" -#include "video_core/pica.h" #include "video_core/pica_state.h" +#include "video_core/regs_rasterizer.h" +#include "video_core/regs_shader.h" #include "video_core/shader/shader.h" #include "video_core/shader/shader_interpreter.h" #ifdef ARCHITECTURE_x86_64 @@ -19,38 +21,31 @@ namespace Pica { namespace Shader { -OutputVertex OutputVertex::FromRegisters(Math::Vec4<float24> output_regs[16], const Regs& regs, - u32 output_mask) { +OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) { // Setup output data - OutputVertex ret; - // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to - // figure out what those circumstances are and enable the remaining outputs then. - unsigned index = 0; - for (unsigned i = 0; i < 7; ++i) { + union { + OutputVertex ret{}; + std::array<float24, 24> vertex_slots; + }; + static_assert(sizeof(vertex_slots) == sizeof(ret), "Struct and array have different sizes."); - if (index >= regs.vs_output_total) - break; + unsigned int num_attributes = regs.vs_output_total; + ASSERT(num_attributes <= 7); + for (unsigned int i = 0; i < num_attributes; ++i) { + const auto& output_register_map = regs.vs_output_attributes[i]; - if ((output_mask & (1 << i)) == 0) - continue; - - const auto& output_register_map = regs.vs_output_attributes[index]; - - u32 semantics[4] = {output_register_map.map_x, output_register_map.map_y, - output_register_map.map_z, output_register_map.map_w}; + RasterizerRegs::VSOutputAttributes::Semantic semantics[4] = { + output_register_map.map_x, output_register_map.map_y, output_register_map.map_z, + output_register_map.map_w}; for (unsigned comp = 0; comp < 4; ++comp) { - float24* out = ((float24*)&ret) + semantics[comp]; - if (semantics[comp] != Regs::VSOutputAttributes::INVALID) { - *out = output_regs[i][comp]; - } else { - // Zero output so that attributes which aren't output won't have denormals in them, - // which would slow us down later. - memset(out, 0, sizeof(*out)); + RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp]; + if (semantic < vertex_slots.size()) { + vertex_slots[semantic] = input.attr[i][comp]; + } else if (semantic != RasterizerRegs::VSOutputAttributes::INVALID) { + LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic); } } - - index++; } // The hardware takes the absolute and saturates vertex colors like this, *before* doing @@ -71,12 +66,20 @@ OutputVertex OutputVertex::FromRegisters(Math::Vec4<float24> output_regs[16], co return ret; } -void UnitState::LoadInputVertex(const InputVertex& input, int num_attributes) { - // Setup input register table - const auto& attribute_register_map = g_state.regs.vs.input_register_map; +void UnitState::LoadInput(const ShaderRegs& config, const AttributeBuffer& input) { + const unsigned max_attribute = config.max_input_attribute_index; - for (int i = 0; i < num_attributes; i++) - registers.input[attribute_register_map.GetRegisterForAttribute(i)] = input.attr[i]; + for (unsigned attr = 0; attr <= max_attribute; ++attr) { + unsigned reg = config.GetRegisterForAttribute(attr); + registers.input[reg] = input.attr[attr]; + } +} + +void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) { + unsigned int output_i = 0; + for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) { + output.attr[output_i++] = registers.output[reg]; + } } MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index 44d9f76c3..38ea717ab 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -12,8 +12,9 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/vector_math.h" -#include "video_core/pica.h" #include "video_core/pica_types.h" +#include "video_core/regs_rasterizer.h" +#include "video_core/regs_shader.h" using nihstro::RegisterType; using nihstro::SourceRegister; @@ -23,14 +24,11 @@ namespace Pica { namespace Shader { -struct InputVertex { +struct AttributeBuffer { alignas(16) Math::Vec4<float24> attr[16]; }; struct OutputVertex { - OutputVertex() = default; - - // VS output attributes Math::Vec4<float24> pos; Math::Vec4<float24> quat; Math::Vec4<float24> color; @@ -42,43 +40,22 @@ struct OutputVertex { INSERT_PADDING_WORDS(1); Math::Vec2<float24> tc2; - // Padding for optimal alignment - INSERT_PADDING_WORDS(4); - - // Attributes used to store intermediate results - - // position after perspective divide - Math::Vec3<float24> screenpos; - INSERT_PADDING_WORDS(1); - - // Linear interpolation - // factor: 0=this, 1=vtx - void Lerp(float24 factor, const OutputVertex& vtx) { - pos = pos * factor + vtx.pos * (float24::FromFloat32(1) - factor); - - // TODO: Should perform perspective correct interpolation here... - tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); - tc1 = tc1 * factor + vtx.tc1 * (float24::FromFloat32(1) - factor); - tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor); - - screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); - - color = color * factor + vtx.color * (float24::FromFloat32(1) - factor); - } - - // Linear interpolation - // factor: 0=v0, 1=v1 - static OutputVertex Lerp(float24 factor, const OutputVertex& v0, const OutputVertex& v1) { - OutputVertex ret = v0; - ret.Lerp(factor, v1); - return ret; - } - - static OutputVertex FromRegisters(Math::Vec4<float24> output_regs[16], const Regs& regs, - u32 output_mask); + static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& output); }; +#define ASSERT_POS(var, pos) \ + static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \ + "offset.") +ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X); +ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X); +ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R); +ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U); +ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U); +ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W); +ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X); +ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U); +#undef ASSERT_POS static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); -static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); +static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); /** * This structure contains the state information that needs to be unique for a shader unit. The 3DS @@ -137,10 +114,12 @@ struct UnitState { /** * Loads the unit state with an input vertex. * - * @param input Input vertex into the shader - * @param num_attributes The number of vertex shader attributes to load + * @param config Shader configuration registers corresponding to the unit. + * @param input Attribute buffer to load into the input registers. */ - void LoadInputVertex(const InputVertex& input, int num_attributes); + void LoadInput(const ShaderRegs& config, const AttributeBuffer& input); + + void WriteOutput(const ShaderRegs& config, AttributeBuffer& output); }; struct ShaderSetup { diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index c0c89b857..f4d1c46c5 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -668,14 +668,14 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const { } DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup, - const InputVertex& input, - int num_attributes) const { + const AttributeBuffer& input, + const ShaderRegs& config) const { UnitState state; DebugData<true> debug_data; // Setup input register table boost::fill(state.registers.input, Math::Vec4<float24>::AssignToAll(float24::Zero())); - state.LoadInputVertex(input, num_attributes); + state.LoadInput(config, input); RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point); return debug_data; } diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h index d6c0e2d8c..50fd7c69d 100644 --- a/src/video_core/shader/shader_interpreter.h +++ b/src/video_core/shader/shader_interpreter.h @@ -18,13 +18,13 @@ public: /** * 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 setup Shader engine state + * @param input Input vertex into the shader * @param config Configuration object for the shader pipeline * @return Debug information for this shader with regards to the given vertex */ - DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const InputVertex& input, - int num_attributes) const; + DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input, + const ShaderRegs& config) const; }; } // namespace diff --git a/src/video_core/shader/shader_jit_x64_compiler.cpp b/src/video_core/shader/shader_jit_x64_compiler.cpp index 49806e8c9..2dbc8b147 100644 --- a/src/video_core/shader/shader_jit_x64_compiler.cpp +++ b/src/video_core/shader/shader_jit_x64_compiler.cpp @@ -144,6 +144,8 @@ static const BitSet32 persistent_regs = BuildRegSet({ ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1, // Constants ONE, NEGBIT, + // Loop variables + LOOPCOUNT, LOOPINC, }); /// Raw constant for the source register selector that indicates no swizzling is performed @@ -293,14 +295,22 @@ void JitShader::Compile_DestEnable(Instruction instr, Xmm src) { } void JitShader::Compile_SanitizedMul(Xmm src1, Xmm src2, Xmm scratch) { + // 0 * inf and inf * 0 in the PICA should return 0 instead of NaN. This can be implemented by + // checking for NaNs before and after the multiplication. If the multiplication result is NaN + // where neither source was, this NaN was generated by a 0 * inf multiplication, and so the + // result should be transformed to 0 to match PICA fp rules. + + // Set scratch to mask of (src1 != NaN and src2 != NaN) movaps(scratch, src1); cmpordps(scratch, src2); mulps(src1, src2); + // Set src2 to mask of (result == NaN) movaps(src2, src1); cmpunordps(src2, src2); + // Clear components where scratch != src2 (i.e. if result is NaN where neither source was NaN) xorps(scratch, src2); andps(src1, scratch); } @@ -587,7 +597,7 @@ void JitShader::Compile_RSQ(Instruction instr) { void JitShader::Compile_NOP(Instruction instr) {} void JitShader::Compile_END(Instruction instr) { - ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8); + ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8, 16); ret(); } @@ -839,7 +849,10 @@ void JitShader::Compile(const std::array<u32, 1024>* program_code_, FindReturnOffsets(); // The stack pointer is 8 modulo 16 at the entry of a procedure - ABI_PushRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8); + // We reserve 16 bytes and assign a dummy value to the first 8 bytes, to catch any potential + // return checks (see Compile_Return) that happen in shader main routine. + ABI_PushRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8, 16); + mov(qword[rsp + 8], 0xFFFFFFFFFFFFFFFFULL); mov(SETUP, ABI_PARAM1); mov(STATE, ABI_PARAM2); diff --git a/src/video_core/shader/shader_jit_x64_compiler.h b/src/video_core/shader/shader_jit_x64_compiler.h index 29e9875ea..f27675560 100644 --- a/src/video_core/shader/shader_jit_x64_compiler.h +++ b/src/video_core/shader/shader_jit_x64_compiler.h @@ -12,7 +12,6 @@ #include <xbyak.h> #include "common/bit_set.h" #include "common/common_types.h" -#include "common/x64/emitter.h" #include "video_core/shader/shader.h" using nihstro::Instruction; @@ -94,7 +93,8 @@ private: /** * Assertion evaluated at compile-time, but only triggered if executed at runtime. - * @param msg Message to be logged if the assertion fails. + * @param condition Condition to be evaluated. + * @param msg Message to be logged if the assertion fails. */ void Compile_Assert(bool condition, const char* msg); |
