aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/shader.cpp65
-rw-r--r--src/video_core/shader/shader.h65
-rw-r--r--src/video_core/shader/shader_interpreter.cpp6
-rw-r--r--src/video_core/shader/shader_interpreter.h8
-rw-r--r--src/video_core/shader/shader_jit_x64_compiler.cpp17
-rw-r--r--src/video_core/shader/shader_jit_x64_compiler.h4
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);