summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar wwylele2017-07-25 22:30:29 +0300
committerGravatar wwylele2017-08-19 10:13:20 +0300
commit46c6973d2bde25a2a8ae9ac434660798fd1dfaee (patch)
tree3910b3b8b95de67f70a482f08351e807c532b784 /src
parentpica/regs: layout geometry shader configuration regs (diff)
downloadyuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.gz
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.xz
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.zip
pica/shader: extend UnitState for GS
Among four shader units in pica, a special unit can be configured to run both VS and GS program. GSUnitState represents this unit, which extends UnitState (which represents the other three normal units) with extra state for primitive emitting. It uses lots of raw pointers to represent internal structure in order to keep it standard layout type for JIT to access. This unit doesn't handle triangle winding (inverting) itself; instead, it calls a WindingSetter handler. This will be explained in the following commits
Diffstat (limited to 'src')
-rw-r--r--src/video_core/shader/shader.cpp38
-rw-r--r--src/video_core/shader/shader.h46
2 files changed, 84 insertions, 0 deletions
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 67ed19ba8..b12468d3a 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -82,6 +82,44 @@ void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) {
82 } 82 }
83} 83}
84 84
85UnitState::UnitState(GSEmitter* emitter) : emitter_ptr(emitter) {}
86
87GSEmitter::GSEmitter() {
88 handlers = new Handlers;
89}
90
91GSEmitter::~GSEmitter() {
92 delete handlers;
93}
94
95void GSEmitter::Emit(Math::Vec4<float24> (&vertex)[16]) {
96 ASSERT(vertex_id < 3);
97 std::copy(std::begin(vertex), std::end(vertex), buffer[vertex_id].begin());
98 if (prim_emit) {
99 if (winding)
100 handlers->winding_setter();
101 for (size_t i = 0; i < buffer.size(); ++i) {
102 AttributeBuffer output;
103 unsigned int output_i = 0;
104 for (unsigned int reg : Common::BitSet<u32>(output_mask)) {
105 output.attr[output_i++] = buffer[i][reg];
106 }
107 handlers->vertex_handler(output);
108 }
109 }
110}
111
112GSUnitState::GSUnitState() : UnitState(&emitter) {}
113
114void GSUnitState::SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter) {
115 emitter.handlers->vertex_handler = std::move(vertex_handler);
116 emitter.handlers->winding_setter = std::move(winding_setter);
117}
118
119void GSUnitState::ConfigOutput(const ShaderRegs& config) {
120 emitter.output_mask = config.output_mask;
121}
122
85MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); 123MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
86 124
87#ifdef ARCHITECTURE_x86_64 125#ifdef ARCHITECTURE_x86_64
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index e156f6aef..caec96043 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <functional>
9#include <type_traits> 10#include <type_traits>
10#include <nihstro/shader_bytecode.h> 11#include <nihstro/shader_bytecode.h>
11#include "common/assert.h" 12#include "common/assert.h"
@@ -31,6 +32,12 @@ struct AttributeBuffer {
31 alignas(16) Math::Vec4<float24> attr[16]; 32 alignas(16) Math::Vec4<float24> attr[16];
32}; 33};
33 34
35/// Handler type for receiving vertex outputs from vertex shader or geometry shader
36using VertexHandler = std::function<void(const AttributeBuffer&)>;
37
38/// Handler type for signaling to invert the vertex order of the next triangle
39using WindingSetter = std::function<void()>;
40
34struct OutputVertex { 41struct OutputVertex {
35 Math::Vec4<float24> pos; 42 Math::Vec4<float24> pos;
36 Math::Vec4<float24> quat; 43 Math::Vec4<float24> quat;
@@ -61,12 +68,36 @@ static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
61static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); 68static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
62 69
63/** 70/**
71 * This structure contains state information for primitive emitting in geometry shader.
72 */
73struct GSEmitter {
74 std::array<std::array<Math::Vec4<float24>, 16>, 3> buffer;
75 u8 vertex_id;
76 bool prim_emit;
77 bool winding;
78 u32 output_mask;
79
80 // Function objects are hidden behind a raw pointer to make the structure standard layout type,
81 // for JIT to use offsetof to access other members.
82 struct Handlers {
83 VertexHandler vertex_handler;
84 WindingSetter winding_setter;
85 } * handlers;
86
87 GSEmitter();
88 ~GSEmitter();
89 void Emit(Math::Vec4<float24> (&vertex)[16]);
90};
91static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
92
93/**
64 * This structure contains the state information that needs to be unique for a shader unit. The 3DS 94 * This structure contains the state information that needs to be unique for a shader unit. The 3DS
65 * has four shader units that process shaders in parallel. At the present, Citra only implements a 95 * has four shader units that process shaders in parallel. At the present, Citra only implements a
66 * single shader unit that processes all shaders serially. Putting the state information in a struct 96 * single shader unit that processes all shaders serially. Putting the state information in a struct
67 * here will make it easier for us to parallelize the shader processing later. 97 * here will make it easier for us to parallelize the shader processing later.
68 */ 98 */
69struct UnitState { 99struct UnitState {
100 explicit UnitState(GSEmitter* emitter = nullptr);
70 struct Registers { 101 struct Registers {
71 // The registers are accessed by the shader JIT using SSE instructions, and are therefore 102 // The registers are accessed by the shader JIT using SSE instructions, and are therefore
72 // required to be 16-byte aligned. 103 // required to be 16-byte aligned.
@@ -82,6 +113,8 @@ struct UnitState {
82 // TODO: How many bits do these actually have? 113 // TODO: How many bits do these actually have?
83 s32 address_registers[3]; 114 s32 address_registers[3];
84 115
116 GSEmitter* emitter_ptr;
117
85 static size_t InputOffset(const SourceRegister& reg) { 118 static size_t InputOffset(const SourceRegister& reg) {
86 switch (reg.GetRegisterType()) { 119 switch (reg.GetRegisterType()) {
87 case RegisterType::Input: 120 case RegisterType::Input:
@@ -125,6 +158,19 @@ struct UnitState {
125 void WriteOutput(const ShaderRegs& config, AttributeBuffer& output); 158 void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
126}; 159};
127 160
161/**
162 * This is an extended shader unit state that represents the special unit that can run both vertex
163 * shader and geometry shader. It contains an additional primitive emitter and utilities for
164 * geometry shader.
165 */
166struct GSUnitState : public UnitState {
167 GSUnitState();
168 void SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter);
169 void ConfigOutput(const ShaderRegs& config);
170
171 GSEmitter emitter;
172};
173
128struct ShaderSetup { 174struct ShaderSetup {
129 struct { 175 struct {
130 // The float uniforms are accessed by the shader JIT using SSE instructions, and are 176 // The float uniforms are accessed by the shader JIT using SSE instructions, and are