summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-01-28 12:34:31 -0800
committerGravatar Yuri Kunde Schlesner2017-02-04 13:59:11 -0800
commit8fca90b5d56892758a98a0ece15b5845009893e3 (patch)
tree16cc7c03687ec58c209c90e5d54f34a2eb9dcf74
parentVideoCore: Split lighting regs from Regs struct (diff)
downloadyuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.gz
yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.tar.xz
yuzu-8fca90b5d56892758a98a0ece15b5845009893e3.zip
VideoCore: Split geometry pipeline regs from Regs struct
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/command_processor.cpp51
-rw-r--r--src/video_core/pica.cpp2
-rw-r--r--src/video_core/pica.h230
-rw-r--r--src/video_core/primitive_assembly.cpp18
-rw-r--r--src/video_core/primitive_assembly.h9
-rw-r--r--src/video_core/regs_pipeline.h224
-rw-r--r--src/video_core/vertex_loader.cpp15
-rw-r--r--src/video_core/vertex_loader.h6
9 files changed, 292 insertions, 264 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 3c6ea42be..c8d2675ae 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -34,6 +34,7 @@ set(HEADERS
34 rasterizer_interface.h 34 rasterizer_interface.h
35 regs_framebuffer.h 35 regs_framebuffer.h
36 regs_lighting.h 36 regs_lighting.h
37 regs_pipeline.h
37 regs_rasterizer.h 38 regs_rasterizer.h
38 regs_texturing.h 39 regs_texturing.h
39 renderer_base.h 40 renderer_base.h
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index fa3432f60..c8064bf6a 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -74,23 +74,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
74 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); 74 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
75 break; 75 break;
76 76
77 case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): 77 case PICA_REG_INDEX(pipeline.triangle_topology):
78 g_state.primitive_assembler.Reconfigure(regs.triangle_topology); 78 g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
79 break; 79 break;
80 80
81 case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): 81 case PICA_REG_INDEX(pipeline.restart_primitive):
82 g_state.primitive_assembler.Reset(); 82 g_state.primitive_assembler.Reset();
83 break; 83 break;
84 84
85 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): 85 case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index):
86 g_state.immediate.current_attribute = 0; 86 g_state.immediate.current_attribute = 0;
87 default_attr_counter = 0; 87 default_attr_counter = 0;
88 break; 88 break;
89 89
90 // Load default vertex input attributes 90 // Load default vertex input attributes
91 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 91 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233):
92 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): 92 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234):
93 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): { 93 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): {
94 // TODO: Does actual hardware indeed keep an intermediate buffer or does 94 // TODO: Does actual hardware indeed keep an intermediate buffer or does
95 // it directly write the values? 95 // it directly write the values?
96 default_attr_write_buffer[default_attr_counter++] = value; 96 default_attr_write_buffer[default_attr_counter++] = value;
@@ -102,7 +102,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
102 if (default_attr_counter >= 3) { 102 if (default_attr_counter >= 3) {
103 default_attr_counter = 0; 103 default_attr_counter = 0;
104 104
105 auto& setup = regs.vs_default_attributes_setup; 105 auto& setup = regs.pipeline.vs_default_attributes_setup;
106 106
107 if (setup.index >= 16) { 107 if (setup.index >= 16) {
108 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); 108 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
@@ -137,7 +137,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
137 137
138 immediate_input.attr[immediate_attribute_id] = attribute; 138 immediate_input.attr[immediate_attribute_id] = attribute;
139 139
140 if (immediate_attribute_id < regs.max_input_attrib_index) { 140 if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) {
141 immediate_attribute_id += 1; 141 immediate_attribute_id += 1;
142 } else { 142 } else {
143 MICROPROFILE_SCOPE(GPU_Drawing); 143 MICROPROFILE_SCOPE(GPU_Drawing);
@@ -173,8 +173,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
173 break; 173 break;
174 } 174 }
175 175
176 case PICA_REG_INDEX(gpu_mode): 176 case PICA_REG_INDEX(pipeline.gpu_mode):
177 if (regs.gpu_mode == Regs::GPUMode::Configuring) { 177 if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
178 MICROPROFILE_SCOPE(GPU_Drawing); 178 MICROPROFILE_SCOPE(GPU_Drawing);
179 179
180 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring 180 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
@@ -186,19 +186,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
186 } 186 }
187 break; 187 break;
188 188
189 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): 189 case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
190 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): { 190 case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
191 unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); 191 unsigned index =
192 u32* head_ptr = 192 static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
193 (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); 193 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
194 regs.pipeline.command_buffer.GetPhysicalAddress(index));
194 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 195 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
195 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); 196 g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
196 break; 197 break;
197 } 198 }
198 199
199 // It seems like these trigger vertex rendering 200 // It seems like these trigger vertex rendering
200 case PICA_REG_INDEX(trigger_draw): 201 case PICA_REG_INDEX(pipeline.trigger_draw):
201 case PICA_REG_INDEX(trigger_draw_indexed): { 202 case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
202 MICROPROFILE_SCOPE(GPU_Drawing); 203 MICROPROFILE_SCOPE(GPU_Drawing);
203 204
204#if PICA_LOG_TEV 205#if PICA_LOG_TEV
@@ -210,13 +211,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
210 // Processes information about internal vertex attributes to figure out how a vertex is 211 // Processes information about internal vertex attributes to figure out how a vertex is
211 // loaded. 212 // loaded.
212 // Later, these can be compiled and cached. 213 // Later, these can be compiled and cached.
213 const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress(); 214 const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
214 VertexLoader loader(regs); 215 VertexLoader loader(regs.pipeline);
215 216
216 // Load vertices 217 // Load vertices
217 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); 218 bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
218 219
219 const auto& index_info = regs.index_array; 220 const auto& index_info = regs.pipeline.index_array;
220 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); 221 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
221 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8); 222 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
222 bool index_u16 = index_info.format != 0; 223 bool index_u16 = index_info.format != 0;
@@ -254,11 +255,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
254 255
255 shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); 256 shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset);
256 257
257 for (unsigned int index = 0; index < regs.num_vertices; ++index) { 258 for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) {
258 // Indexed rendering doesn't use the start offset 259 // Indexed rendering doesn't use the start offset
259 unsigned int vertex = 260 unsigned int vertex =
260 is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) 261 is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index])
261 : (index + regs.vertex_offset); 262 : (index + regs.pipeline.vertex_offset);
262 263
263 // -1 is a common special value used for primitive restart. Since it's unknown if 264 // -1 is a common special value used for primitive restart. Since it's unknown if
264 // the PICA supports it, and it would mess up the caching, guard against it here. 265 // the PICA supports it, and it would mess up the caching, guard against it here.
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index b4a77c632..6604ce83c 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -513,6 +513,6 @@ void State::Reset() {
513 Zero(gs); 513 Zero(gs);
514 Zero(cmd_list); 514 Zero(cmd_list);
515 Zero(immediate); 515 Zero(immediate);
516 primitive_assembler.Reconfigure(Regs::TriangleTopology::List); 516 primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List);
517} 517}
518} 518}
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 371bcdb84..765fa5dd4 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -20,6 +20,7 @@
20#include "common/vector_math.h" 20#include "common/vector_math.h"
21#include "video_core/regs_framebuffer.h" 21#include "video_core/regs_framebuffer.h"
22#include "video_core/regs_lighting.h" 22#include "video_core/regs_lighting.h"
23#include "video_core/regs_pipeline.h"
23#include "video_core/regs_rasterizer.h" 24#include "video_core/regs_rasterizer.h"
24#include "video_core/regs_texturing.h" 25#include "video_core/regs_texturing.h"
25 26
@@ -55,210 +56,7 @@ struct Regs {
55 TexturingRegs texturing; 56 TexturingRegs texturing;
56 FramebufferRegs framebuffer; 57 FramebufferRegs framebuffer;
57 LightingRegs lighting; 58 LightingRegs lighting;
58 59 PipelineRegs pipeline;
59 enum class VertexAttributeFormat : u64 {
60 BYTE = 0,
61 UBYTE = 1,
62 SHORT = 2,
63 FLOAT = 3,
64 };
65
66 struct {
67 BitField<0, 29, u32> base_address;
68
69 u32 GetPhysicalBaseAddress() const {
70 return DecodeAddressRegister(base_address);
71 }
72
73 // Descriptor for internal vertex attributes
74 union {
75 BitField<0, 2, VertexAttributeFormat> format0; // size of one element
76 BitField<2, 2, u64> size0; // number of elements minus 1
77 BitField<4, 2, VertexAttributeFormat> format1;
78 BitField<6, 2, u64> size1;
79 BitField<8, 2, VertexAttributeFormat> format2;
80 BitField<10, 2, u64> size2;
81 BitField<12, 2, VertexAttributeFormat> format3;
82 BitField<14, 2, u64> size3;
83 BitField<16, 2, VertexAttributeFormat> format4;
84 BitField<18, 2, u64> size4;
85 BitField<20, 2, VertexAttributeFormat> format5;
86 BitField<22, 2, u64> size5;
87 BitField<24, 2, VertexAttributeFormat> format6;
88 BitField<26, 2, u64> size6;
89 BitField<28, 2, VertexAttributeFormat> format7;
90 BitField<30, 2, u64> size7;
91 BitField<32, 2, VertexAttributeFormat> format8;
92 BitField<34, 2, u64> size8;
93 BitField<36, 2, VertexAttributeFormat> format9;
94 BitField<38, 2, u64> size9;
95 BitField<40, 2, VertexAttributeFormat> format10;
96 BitField<42, 2, u64> size10;
97 BitField<44, 2, VertexAttributeFormat> format11;
98 BitField<46, 2, u64> size11;
99
100 BitField<48, 12, u64> attribute_mask;
101
102 // number of total attributes minus 1
103 BitField<60, 4, u64> max_attribute_index;
104 };
105
106 inline VertexAttributeFormat GetFormat(int n) const {
107 VertexAttributeFormat formats[] = {format0, format1, format2, format3,
108 format4, format5, format6, format7,
109 format8, format9, format10, format11};
110 return formats[n];
111 }
112
113 inline int GetNumElements(int n) const {
114 u64 sizes[] = {size0, size1, size2, size3, size4, size5,
115 size6, size7, size8, size9, size10, size11};
116 return (int)sizes[n] + 1;
117 }
118
119 inline int GetElementSizeInBytes(int n) const {
120 return (GetFormat(n) == VertexAttributeFormat::FLOAT)
121 ? 4
122 : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
123 }
124
125 inline int GetStride(int n) const {
126 return GetNumElements(n) * GetElementSizeInBytes(n);
127 }
128
129 inline bool IsDefaultAttribute(int id) const {
130 return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
131 }
132
133 inline int GetNumTotalAttributes() const {
134 return (int)max_attribute_index + 1;
135 }
136
137 // Attribute loaders map the source vertex data to input attributes
138 // This e.g. allows to load different attributes from different memory locations
139 struct {
140 // Source attribute data offset from the base address
141 u32 data_offset;
142
143 union {
144 BitField<0, 4, u64> comp0;
145 BitField<4, 4, u64> comp1;
146 BitField<8, 4, u64> comp2;
147 BitField<12, 4, u64> comp3;
148 BitField<16, 4, u64> comp4;
149 BitField<20, 4, u64> comp5;
150 BitField<24, 4, u64> comp6;
151 BitField<28, 4, u64> comp7;
152 BitField<32, 4, u64> comp8;
153 BitField<36, 4, u64> comp9;
154 BitField<40, 4, u64> comp10;
155 BitField<44, 4, u64> comp11;
156
157 // bytes for a single vertex in this loader
158 BitField<48, 8, u64> byte_count;
159
160 BitField<60, 4, u64> component_count;
161 };
162
163 inline int GetComponent(int n) const {
164 u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
165 comp6, comp7, comp8, comp9, comp10, comp11};
166 return (int)components[n];
167 }
168 } attribute_loaders[12];
169 } vertex_attributes;
170
171 struct {
172 enum IndexFormat : u32 {
173 BYTE = 0,
174 SHORT = 1,
175 };
176
177 union {
178 BitField<0, 31, u32> offset; // relative to base attribute address
179 BitField<31, 1, IndexFormat> format;
180 };
181 } index_array;
182
183 // Number of vertices to render
184 u32 num_vertices;
185
186 INSERT_PADDING_WORDS(0x1);
187
188 // The index of the first vertex to render
189 u32 vertex_offset;
190
191 INSERT_PADDING_WORDS(0x3);
192
193 // These two trigger rendering of triangles
194 u32 trigger_draw;
195 u32 trigger_draw_indexed;
196
197 INSERT_PADDING_WORDS(0x2);
198
199 // These registers are used to setup the default "fall-back" vertex shader attributes
200 struct {
201 // Index of the current default attribute
202 u32 index;
203
204 // Writing to these registers sets the "current" default attribute.
205 u32 set_value[3];
206 } vs_default_attributes_setup;
207
208 INSERT_PADDING_WORDS(0x2);
209
210 struct {
211 // There are two channels that can be used to configure the next command buffer, which
212 // can be then executed by writing to the "trigger" registers. There are two reasons why a
213 // game might use this feature:
214 // 1) With this, an arbitrary number of additional command buffers may be executed in
215 // sequence without requiring any intervention of the CPU after the initial one is
216 // kicked off.
217 // 2) Games can configure these registers to provide a command list subroutine mechanism.
218
219 BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
220 BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
221 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
222
223 unsigned GetSize(unsigned index) const {
224 ASSERT(index < 2);
225 return 8 * size[index];
226 }
227
228 PAddr GetPhysicalAddress(unsigned index) const {
229 ASSERT(index < 2);
230 return (PAddr)(8 * addr[index]);
231 }
232 } command_buffer;
233
234 INSERT_PADDING_WORDS(4);
235
236 /// Number of input attributes to the vertex shader minus 1
237 BitField<0, 4, u32> max_input_attrib_index;
238
239 INSERT_PADDING_WORDS(2);
240
241 enum class GPUMode : u32 {
242 Drawing = 0,
243 Configuring = 1,
244 };
245
246 GPUMode gpu_mode;
247
248 INSERT_PADDING_WORDS(0x18);
249
250 enum class TriangleTopology : u32 {
251 List = 0,
252 Strip = 1,
253 Fan = 2,
254 Shader = 3, // Programmable setup unit implemented in a geometry shader
255 };
256
257 BitField<8, 2, TriangleTopology> triangle_topology;
258
259 u32 restart_primitive;
260
261 INSERT_PADDING_WORDS(0x20);
262 60
263 struct ShaderConfig { 61 struct ShaderConfig {
264 BitField<0, 16, u32> bool_uniforms; 62 BitField<0, 16, u32> bool_uniforms;
@@ -430,17 +228,19 @@ ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110);
430 228
431ASSERT_REG_POSITION(lighting, 0x140); 229ASSERT_REG_POSITION(lighting, 0x140);
432 230
433ASSERT_REG_POSITION(vertex_attributes, 0x200); 231ASSERT_REG_POSITION(pipeline, 0x200);
434ASSERT_REG_POSITION(index_array, 0x227); 232ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200);
435ASSERT_REG_POSITION(num_vertices, 0x228); 233ASSERT_REG_POSITION(pipeline.index_array, 0x227);
436ASSERT_REG_POSITION(vertex_offset, 0x22a); 234ASSERT_REG_POSITION(pipeline.num_vertices, 0x228);
437ASSERT_REG_POSITION(trigger_draw, 0x22e); 235ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a);
438ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 236ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e);
439ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 237ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f);
440ASSERT_REG_POSITION(command_buffer, 0x238); 238ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232);
441ASSERT_REG_POSITION(gpu_mode, 0x245); 239ASSERT_REG_POSITION(pipeline.command_buffer, 0x238);
442ASSERT_REG_POSITION(triangle_topology, 0x25e); 240ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245);
443ASSERT_REG_POSITION(restart_primitive, 0x25f); 241ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e);
242ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f);
243
444ASSERT_REG_POSITION(gs, 0x280); 244ASSERT_REG_POSITION(gs, 0x280);
445ASSERT_REG_POSITION(vs, 0x2b0); 245ASSERT_REG_POSITION(vs, 0x2b0);
446 246
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index e71ff5719..acd2ac5e2 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -3,14 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "video_core/pica.h"
7#include "video_core/primitive_assembly.h" 6#include "video_core/primitive_assembly.h"
7#include "video_core/regs_pipeline.h"
8#include "video_core/shader/shader.h" 8#include "video_core/shader/shader.h"
9 9
10namespace Pica { 10namespace Pica {
11 11
12template <typename VertexType> 12template <typename VertexType>
13PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology) 13PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology)
14 : topology(topology), buffer_index(0) {} 14 : topology(topology), buffer_index(0) {}
15 15
16template <typename VertexType> 16template <typename VertexType>
@@ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
18 TriangleHandler triangle_handler) { 18 TriangleHandler triangle_handler) {
19 switch (topology) { 19 switch (topology) {
20 // TODO: Figure out what's different with TriangleTopology::Shader. 20 // TODO: Figure out what's different with TriangleTopology::Shader.
21 case Regs::TriangleTopology::List: 21 case PipelineRegs::TriangleTopology::List:
22 case Regs::TriangleTopology::Shader: 22 case PipelineRegs::TriangleTopology::Shader:
23 if (buffer_index < 2) { 23 if (buffer_index < 2) {
24 buffer[buffer_index++] = vtx; 24 buffer[buffer_index++] = vtx;
25 } else { 25 } else {
@@ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
29 } 29 }
30 break; 30 break;
31 31
32 case Regs::TriangleTopology::Strip: 32 case PipelineRegs::TriangleTopology::Strip:
33 case Regs::TriangleTopology::Fan: 33 case PipelineRegs::TriangleTopology::Fan:
34 if (strip_ready) 34 if (strip_ready)
35 triangle_handler(buffer[0], buffer[1], vtx); 35 triangle_handler(buffer[0], buffer[1], vtx);
36 36
@@ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
38 38
39 strip_ready |= (buffer_index == 1); 39 strip_ready |= (buffer_index == 1);
40 40
41 if (topology == Regs::TriangleTopology::Strip) 41 if (topology == PipelineRegs::TriangleTopology::Strip)
42 buffer_index = !buffer_index; 42 buffer_index = !buffer_index;
43 else if (topology == Regs::TriangleTopology::Fan) 43 else if (topology == PipelineRegs::TriangleTopology::Fan)
44 buffer_index = 1; 44 buffer_index = 1;
45 break; 45 break;
46 46
@@ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() {
57} 57}
58 58
59template <typename VertexType> 59template <typename VertexType>
60void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) { 60void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) {
61 Reset(); 61 Reset();
62 this->topology = topology; 62 this->topology = topology;
63} 63}
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index 24da47382..e8eccdf27 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <functional> 7#include <functional>
8#include "video_core/pica.h" 8#include "video_core/regs_pipeline.h"
9 9
10namespace Pica { 10namespace Pica {
11 11
@@ -18,7 +18,8 @@ struct PrimitiveAssembler {
18 using TriangleHandler = 18 using TriangleHandler =
19 std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>; 19 std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>;
20 20
21 PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List); 21 PrimitiveAssembler(
22 PipelineRegs::TriangleTopology topology = PipelineRegs::TriangleTopology::List);
22 23
23 /* 24 /*
24 * Queues a vertex, builds primitives from the vertex queue according to the given 25 * Queues a vertex, builds primitives from the vertex queue according to the given
@@ -36,10 +37,10 @@ struct PrimitiveAssembler {
36 /** 37 /**
37 * Reconfigures the PrimitiveAssembler to use a different triangle topology. 38 * Reconfigures the PrimitiveAssembler to use a different triangle topology.
38 */ 39 */
39 void Reconfigure(Regs::TriangleTopology topology); 40 void Reconfigure(PipelineRegs::TriangleTopology topology);
40 41
41private: 42private:
42 Regs::TriangleTopology topology; 43 PipelineRegs::TriangleTopology topology;
43 44
44 int buffer_index; 45 int buffer_index;
45 VertexType buffer[2]; 46 VertexType buffer[2];
diff --git a/src/video_core/regs_pipeline.h b/src/video_core/regs_pipeline.h
new file mode 100644
index 000000000..5844a66ee
--- /dev/null
+++ b/src/video_core/regs_pipeline.h
@@ -0,0 +1,224 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13
14namespace Pica {
15
16struct PipelineRegs {
17 enum class VertexAttributeFormat : u64 {
18 BYTE = 0,
19 UBYTE = 1,
20 SHORT = 2,
21 FLOAT = 3,
22 };
23
24 struct {
25 BitField<0, 29, u32> base_address;
26
27 PAddr GetPhysicalBaseAddress() const {
28 return base_address * 8;
29 }
30
31 // Descriptor for internal vertex attributes
32 union {
33 BitField<0, 2, VertexAttributeFormat> format0; // size of one element
34 BitField<2, 2, u64> size0; // number of elements minus 1
35 BitField<4, 2, VertexAttributeFormat> format1;
36 BitField<6, 2, u64> size1;
37 BitField<8, 2, VertexAttributeFormat> format2;
38 BitField<10, 2, u64> size2;
39 BitField<12, 2, VertexAttributeFormat> format3;
40 BitField<14, 2, u64> size3;
41 BitField<16, 2, VertexAttributeFormat> format4;
42 BitField<18, 2, u64> size4;
43 BitField<20, 2, VertexAttributeFormat> format5;
44 BitField<22, 2, u64> size5;
45 BitField<24, 2, VertexAttributeFormat> format6;
46 BitField<26, 2, u64> size6;
47 BitField<28, 2, VertexAttributeFormat> format7;
48 BitField<30, 2, u64> size7;
49 BitField<32, 2, VertexAttributeFormat> format8;
50 BitField<34, 2, u64> size8;
51 BitField<36, 2, VertexAttributeFormat> format9;
52 BitField<38, 2, u64> size9;
53 BitField<40, 2, VertexAttributeFormat> format10;
54 BitField<42, 2, u64> size10;
55 BitField<44, 2, VertexAttributeFormat> format11;
56 BitField<46, 2, u64> size11;
57
58 BitField<48, 12, u64> attribute_mask;
59
60 // number of total attributes minus 1
61 BitField<60, 4, u64> max_attribute_index;
62 };
63
64 inline VertexAttributeFormat GetFormat(int n) const {
65 VertexAttributeFormat formats[] = {format0, format1, format2, format3,
66 format4, format5, format6, format7,
67 format8, format9, format10, format11};
68 return formats[n];
69 }
70
71 inline int GetNumElements(int n) const {
72 u64 sizes[] = {size0, size1, size2, size3, size4, size5,
73 size6, size7, size8, size9, size10, size11};
74 return (int)sizes[n] + 1;
75 }
76
77 inline int GetElementSizeInBytes(int n) const {
78 return (GetFormat(n) == VertexAttributeFormat::FLOAT)
79 ? 4
80 : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
81 }
82
83 inline int GetStride(int n) const {
84 return GetNumElements(n) * GetElementSizeInBytes(n);
85 }
86
87 inline bool IsDefaultAttribute(int id) const {
88 return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
89 }
90
91 inline int GetNumTotalAttributes() const {
92 return (int)max_attribute_index + 1;
93 }
94
95 // Attribute loaders map the source vertex data to input attributes
96 // This e.g. allows to load different attributes from different memory locations
97 struct {
98 // Source attribute data offset from the base address
99 u32 data_offset;
100
101 union {
102 BitField<0, 4, u64> comp0;
103 BitField<4, 4, u64> comp1;
104 BitField<8, 4, u64> comp2;
105 BitField<12, 4, u64> comp3;
106 BitField<16, 4, u64> comp4;
107 BitField<20, 4, u64> comp5;
108 BitField<24, 4, u64> comp6;
109 BitField<28, 4, u64> comp7;
110 BitField<32, 4, u64> comp8;
111 BitField<36, 4, u64> comp9;
112 BitField<40, 4, u64> comp10;
113 BitField<44, 4, u64> comp11;
114
115 // bytes for a single vertex in this loader
116 BitField<48, 8, u64> byte_count;
117
118 BitField<60, 4, u64> component_count;
119 };
120
121 inline int GetComponent(int n) const {
122 u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
123 comp6, comp7, comp8, comp9, comp10, comp11};
124 return (int)components[n];
125 }
126 } attribute_loaders[12];
127 } vertex_attributes;
128
129 struct {
130 enum IndexFormat : u32 {
131 BYTE = 0,
132 SHORT = 1,
133 };
134
135 union {
136 BitField<0, 31, u32> offset; // relative to base attribute address
137 BitField<31, 1, IndexFormat> format;
138 };
139 } index_array;
140
141 // Number of vertices to render
142 u32 num_vertices;
143
144 INSERT_PADDING_WORDS(0x1);
145
146 // The index of the first vertex to render
147 u32 vertex_offset;
148
149 INSERT_PADDING_WORDS(0x3);
150
151 // These two trigger rendering of triangles
152 u32 trigger_draw;
153 u32 trigger_draw_indexed;
154
155 INSERT_PADDING_WORDS(0x2);
156
157 // These registers are used to setup the default "fall-back" vertex shader attributes
158 struct {
159 // Index of the current default attribute
160 u32 index;
161
162 // Writing to these registers sets the "current" default attribute.
163 u32 set_value[3];
164 } vs_default_attributes_setup;
165
166 INSERT_PADDING_WORDS(0x2);
167
168 struct {
169 // There are two channels that can be used to configure the next command buffer, which can
170 // be then executed by writing to the "trigger" registers. There are two reasons why a game
171 // might use this feature:
172 // 1) With this, an arbitrary number of additional command buffers may be executed in
173 // sequence without requiring any intervention of the CPU after the initial one is
174 // kicked off.
175 // 2) Games can configure these registers to provide a command list subroutine mechanism.
176
177 BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
178 BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
179 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
180
181 unsigned GetSize(unsigned index) const {
182 ASSERT(index < 2);
183 return 8 * size[index];
184 }
185
186 PAddr GetPhysicalAddress(unsigned index) const {
187 ASSERT(index < 2);
188 return (PAddr)(8 * addr[index]);
189 }
190 } command_buffer;
191
192 INSERT_PADDING_WORDS(4);
193
194 /// Number of input attributes to the vertex shader minus 1
195 BitField<0, 4, u32> max_input_attrib_index;
196
197 INSERT_PADDING_WORDS(2);
198
199 enum class GPUMode : u32 {
200 Drawing = 0,
201 Configuring = 1,
202 };
203
204 GPUMode gpu_mode;
205
206 INSERT_PADDING_WORDS(0x18);
207
208 enum class TriangleTopology : u32 {
209 List = 0,
210 Strip = 1,
211 Fan = 2,
212 Shader = 3, // Programmable setup unit implemented in a geometry shader
213 };
214
215 BitField<8, 2, TriangleTopology> triangle_topology;
216
217 u32 restart_primitive;
218
219 INSERT_PADDING_WORDS(0x20);
220};
221
222static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size");
223
224} // namespace Pica
diff --git a/src/video_core/vertex_loader.cpp b/src/video_core/vertex_loader.cpp
index bf83b61ca..20e2370be 100644
--- a/src/video_core/vertex_loader.cpp
+++ b/src/video_core/vertex_loader.cpp
@@ -16,7 +16,7 @@
16 16
17namespace Pica { 17namespace Pica {
18 18
19void VertexLoader::Setup(const Pica::Regs& regs) { 19void VertexLoader::Setup(const PipelineRegs& regs) {
20 ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once."); 20 ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once.");
21 21
22 const auto& attribute_config = regs.vertex_attributes; 22 const auto& attribute_config = regs.vertex_attributes;
@@ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
85 memory_accesses.AddAccess( 85 memory_accesses.AddAccess(
86 source_addr, 86 source_addr,
87 vertex_attribute_elements[i] * 87 vertex_attribute_elements[i] *
88 ((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) 88 ((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT)
89 ? 4 89 ? 4
90 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) 90 : (vertex_attribute_formats[i] ==
91 PipelineRegs::VertexAttributeFormat::SHORT)
91 ? 2 92 ? 2
92 : 1)); 93 : 1));
93 } 94 }
94 95
95 switch (vertex_attribute_formats[i]) { 96 switch (vertex_attribute_formats[i]) {
96 case Regs::VertexAttributeFormat::BYTE: { 97 case PipelineRegs::VertexAttributeFormat::BYTE: {
97 const s8* srcdata = 98 const s8* srcdata =
98 reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr)); 99 reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
99 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 100 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -101,7 +102,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
101 } 102 }
102 break; 103 break;
103 } 104 }
104 case Regs::VertexAttributeFormat::UBYTE: { 105 case PipelineRegs::VertexAttributeFormat::UBYTE: {
105 const u8* srcdata = 106 const u8* srcdata =
106 reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr)); 107 reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
107 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 108 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -109,7 +110,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
109 } 110 }
110 break; 111 break;
111 } 112 }
112 case Regs::VertexAttributeFormat::SHORT: { 113 case PipelineRegs::VertexAttributeFormat::SHORT: {
113 const s16* srcdata = 114 const s16* srcdata =
114 reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr)); 115 reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
115 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 116 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -117,7 +118,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
117 } 118 }
118 break; 119 break;
119 } 120 }
120 case Regs::VertexAttributeFormat::FLOAT: { 121 case PipelineRegs::VertexAttributeFormat::FLOAT: {
121 const float* srcdata = 122 const float* srcdata =
122 reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr)); 123 reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
123 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 124 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
diff --git a/src/video_core/vertex_loader.h b/src/video_core/vertex_loader.h
index 51f3d45b4..7815715bc 100644
--- a/src/video_core/vertex_loader.h
+++ b/src/video_core/vertex_loader.h
@@ -17,11 +17,11 @@ struct AttributeBuffer;
17class VertexLoader { 17class VertexLoader {
18public: 18public:
19 VertexLoader() = default; 19 VertexLoader() = default;
20 explicit VertexLoader(const Pica::Regs& regs) { 20 explicit VertexLoader(const PipelineRegs& regs) {
21 Setup(regs); 21 Setup(regs);
22 } 22 }
23 23
24 void Setup(const Pica::Regs& regs); 24 void Setup(const PipelineRegs& regs);
25 void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, 25 void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input,
26 DebugUtils::MemoryAccessTracker& memory_accesses); 26 DebugUtils::MemoryAccessTracker& memory_accesses);
27 27
@@ -32,7 +32,7 @@ public:
32private: 32private:
33 std::array<u32, 16> vertex_attribute_sources; 33 std::array<u32, 16> vertex_attribute_sources;
34 std::array<u32, 16> vertex_attribute_strides{}; 34 std::array<u32, 16> vertex_attribute_strides{};
35 std::array<Regs::VertexAttributeFormat, 16> vertex_attribute_formats; 35 std::array<PipelineRegs::VertexAttributeFormat, 16> vertex_attribute_formats;
36 std::array<u32, 16> vertex_attribute_elements{}; 36 std::array<u32, 16> vertex_attribute_elements{};
37 std::array<bool, 16> vertex_attribute_is_default; 37 std::array<bool, 16> vertex_attribute_is_default;
38 int num_total_attributes = 0; 38 int num_total_attributes = 0;