|
|
@@ -6,6 +6,7 @@
|
|
|
|
|
|
#include <array>
|
|
|
#include <cstddef>
|
|
|
+#include <functional>
|
|
|
#include <type_traits>
|
|
|
#include <nihstro/shader_bytecode.h>
|
|
|
#include "common/assert.h"
|
|
|
@@ -31,6 +32,12 @@ struct AttributeBuffer {
|
|
|
alignas(16) Math::Vec4<float24> attr[16];
|
|
|
};
|
|
|
|
|
|
+/// Handler type for receiving vertex outputs from vertex shader or geometry shader
|
|
|
+using VertexHandler = std::function<void(const AttributeBuffer&)>;
|
|
|
+
|
|
|
+/// Handler type for signaling to invert the vertex order of the next triangle
|
|
|
+using WindingSetter = std::function<void()>;
|
|
|
+
|
|
|
struct OutputVertex {
|
|
|
Math::Vec4<float24> pos;
|
|
|
Math::Vec4<float24> quat;
|
|
|
@@ -60,6 +67,29 @@ ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U);
|
|
|
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
|
|
|
static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
|
|
|
|
|
|
+/**
|
|
|
+ * This structure contains state information for primitive emitting in geometry shader.
|
|
|
+ */
|
|
|
+struct GSEmitter {
|
|
|
+ std::array<std::array<Math::Vec4<float24>, 16>, 3> buffer;
|
|
|
+ u8 vertex_id;
|
|
|
+ bool prim_emit;
|
|
|
+ bool winding;
|
|
|
+ u32 output_mask;
|
|
|
+
|
|
|
+ // Function objects are hidden behind a raw pointer to make the structure standard layout type,
|
|
|
+ // for JIT to use offsetof to access other members.
|
|
|
+ struct Handlers {
|
|
|
+ VertexHandler vertex_handler;
|
|
|
+ WindingSetter winding_setter;
|
|
|
+ } * handlers;
|
|
|
+
|
|
|
+ GSEmitter();
|
|
|
+ ~GSEmitter();
|
|
|
+ void Emit(Math::Vec4<float24> (&vertex)[16]);
|
|
|
+};
|
|
|
+static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
|
|
|
+
|
|
|
/**
|
|
|
* This structure contains the state information that needs to be unique for a shader unit. The 3DS
|
|
|
* has four shader units that process shaders in parallel. At the present, Citra only implements a
|
|
|
@@ -67,6 +97,7 @@ static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has inva
|
|
|
* here will make it easier for us to parallelize the shader processing later.
|
|
|
*/
|
|
|
struct UnitState {
|
|
|
+ explicit UnitState(GSEmitter* emitter = nullptr);
|
|
|
struct Registers {
|
|
|
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
|
|
|
// required to be 16-byte aligned.
|
|
|
@@ -82,6 +113,8 @@ struct UnitState {
|
|
|
// TODO: How many bits do these actually have?
|
|
|
s32 address_registers[3];
|
|
|
|
|
|
+ GSEmitter* emitter_ptr;
|
|
|
+
|
|
|
static size_t InputOffset(const SourceRegister& reg) {
|
|
|
switch (reg.GetRegisterType()) {
|
|
|
case RegisterType::Input:
|
|
|
@@ -125,6 +158,19 @@ struct UnitState {
|
|
|
void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * This is an extended shader unit state that represents the special unit that can run both vertex
|
|
|
+ * shader and geometry shader. It contains an additional primitive emitter and utilities for
|
|
|
+ * geometry shader.
|
|
|
+ */
|
|
|
+struct GSUnitState : public UnitState {
|
|
|
+ GSUnitState();
|
|
|
+ void SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter);
|
|
|
+ void ConfigOutput(const ShaderRegs& config);
|
|
|
+
|
|
|
+ GSEmitter emitter;
|
|
|
+};
|
|
|
+
|
|
|
struct ShaderSetup {
|
|
|
struct {
|
|
|
// The float uniforms are accessed by the shader JIT using SSE instructions, and are
|