summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/clipper.cpp178
-rw-r--r--src/video_core/clipper.h21
-rw-r--r--src/video_core/pica.h22
-rw-r--r--src/video_core/primitive_assembly.cpp7
-rw-r--r--src/video_core/video_core.vcxproj2
-rw-r--r--src/video_core/video_core.vcxproj.filters2
7 files changed, 230 insertions, 8 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index b06f14db0..828bf30fc 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,11 +1,13 @@
1set(SRCS command_processor.cpp 1set(SRCS clipper.cpp
2 command_processor.cpp
2 primitive_assembly.cpp 3 primitive_assembly.cpp
3 utils.cpp 4 utils.cpp
4 vertex_shader.cpp 5 vertex_shader.cpp
5 video_core.cpp 6 video_core.cpp
6 renderer_opengl/renderer_opengl.cpp) 7 renderer_opengl/renderer_opengl.cpp)
7 8
8set(HEADERS command_processor.h 9set(HEADERS clipper.h
10 command_processor.h
9 math.h 11 math.h
10 primitive_assembly.h 12 primitive_assembly.h
11 utils.h 13 utils.h
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
new file mode 100644
index 000000000..e9ab6242c
--- /dev/null
+++ b/src/video_core/clipper.cpp
@@ -0,0 +1,178 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "clipper.h"
8#include "pica.h"
9#include "vertex_shader.h"
10
11namespace Pica {
12
13namespace Clipper {
14
15struct ClippingEdge {
16public:
17 enum Type {
18 POS_X = 0,
19 NEG_X = 1,
20 POS_Y = 2,
21 NEG_Y = 3,
22 POS_Z = 4,
23 NEG_Z = 5,
24 };
25
26 ClippingEdge(Type type, float24 position) : type(type), pos(position) {}
27
28 bool IsInside(const OutputVertex& vertex) const {
29 switch (type) {
30 case POS_X: return vertex.pos.x <= pos * vertex.pos.w;
31 case NEG_X: return vertex.pos.x >= pos * vertex.pos.w;
32 case POS_Y: return vertex.pos.y <= pos * vertex.pos.w;
33 case NEG_Y: return vertex.pos.y >= pos * vertex.pos.w;
34
35 // TODO: Check z compares ... should be 0..1 instead?
36 case POS_Z: return vertex.pos.z <= pos * vertex.pos.w;
37
38 default:
39 case NEG_Z: return vertex.pos.z >= pos * vertex.pos.w;
40 }
41 }
42
43 bool IsOutSide(const OutputVertex& vertex) const {
44 return !IsInside(vertex);
45 }
46
47 OutputVertex GetIntersection(const OutputVertex& v0, const OutputVertex& v1) const {
48 auto dotpr = [this](const OutputVertex& vtx) {
49 switch (type) {
50 case POS_X: return vtx.pos.x - vtx.pos.w;
51 case NEG_X: return -vtx.pos.x - vtx.pos.w;
52 case POS_Y: return vtx.pos.y - vtx.pos.w;
53 case NEG_Y: return -vtx.pos.y - vtx.pos.w;
54
55 // TODO: Verify z clipping
56 case POS_Z: return vtx.pos.z - vtx.pos.w;
57
58 default:
59 case NEG_Z: return -vtx.pos.w;
60 }
61 };
62
63 float24 dp = dotpr(v0);
64 float24 dp_prev = dotpr(v1);
65 float24 factor = dp_prev / (dp_prev - dp);
66
67 return OutputVertex::Lerp(factor, v0, v1);
68 }
69
70private:
71 Type type;
72 float24 pos;
73};
74
75static void InitScreenCoordinates(OutputVertex& vtx)
76{
77 struct {
78 float24 halfsize_x;
79 float24 offset_x;
80 float24 halfsize_y;
81 float24 offset_y;
82 float24 zscale;
83 float24 offset_z;
84 } viewport;
85
86 viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x);
87 viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y);
88 viewport.offset_x = float24::FromFloat32(registers.viewport_corner.x);
89 viewport.offset_y = float24::FromFloat32(registers.viewport_corner.y);
90 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range);
91 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane);
92
93 // TODO: Not sure why the viewport width needs to be divided by 2 but the viewport height does not
94 vtx.screenpos[0] = (vtx.pos.x / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_x / float24::FromFloat32(2.0) + viewport.offset_x;
95 vtx.screenpos[1] = (vtx.pos.y / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y;
96 vtx.screenpos[2] = viewport.offset_z - vtx.pos.z / vtx.pos.w * viewport.zscale;
97}
98
99void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
100
101 // TODO (neobrain):
102 // The list of output vertices has some fixed maximum size,
103 // however I haven't taken the time to figure out what it is exactly.
104 // For now, we hence just assume a maximal size of 1000 vertices.
105 const size_t max_vertices = 1000;
106 std::vector<OutputVertex> buffer_vertices;
107 std::vector<OutputVertex*> output_list{ &v0, &v1, &v2 };
108
109 // Make sure to reserve space for all vertices.
110 // Without this, buffer reallocation would invalidate references.
111 buffer_vertices.reserve(max_vertices);
112
113 // Simple implementation of the Sutherland-Hodgman clipping algorithm.
114 // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here)
115 for (auto edge : { ClippingEdge(ClippingEdge::POS_X, float24::FromFloat32(+1.0)),
116 ClippingEdge(ClippingEdge::NEG_X, float24::FromFloat32(-1.0)),
117 ClippingEdge(ClippingEdge::POS_Y, float24::FromFloat32(+1.0)),
118 ClippingEdge(ClippingEdge::NEG_Y, float24::FromFloat32(-1.0)),
119 ClippingEdge(ClippingEdge::POS_Z, float24::FromFloat32(+1.0)),
120 ClippingEdge(ClippingEdge::NEG_Z, float24::FromFloat32(-1.0)) }) {
121
122 const std::vector<OutputVertex*> input_list = output_list;
123 output_list.clear();
124
125 const OutputVertex* reference_vertex = input_list.back();
126
127 for (const auto& vertex : input_list) {
128 // NOTE: This algorithm changes vertex order in some cases!
129 if (edge.IsInside(*vertex)) {
130 if (edge.IsOutSide(*reference_vertex)) {
131 buffer_vertices.push_back(edge.GetIntersection(*vertex, *reference_vertex));
132 output_list.push_back(&(buffer_vertices.back()));
133 }
134
135 output_list.push_back(vertex);
136 } else if (edge.IsInside(*reference_vertex)) {
137 buffer_vertices.push_back(edge.GetIntersection(*vertex, *reference_vertex));
138 output_list.push_back(&(buffer_vertices.back()));
139 }
140
141 reference_vertex = vertex;
142 }
143
144 // Need to have at least a full triangle to continue...
145 if (output_list.size() < 3)
146 return;
147 }
148
149 InitScreenCoordinates(*(output_list[0]));
150 InitScreenCoordinates(*(output_list[1]));
151
152 for (int i = 0; i < output_list.size() - 2; i ++) {
153 OutputVertex& vtx0 = *(output_list[0]);
154 OutputVertex& vtx1 = *(output_list[i+1]);
155 OutputVertex& vtx2 = *(output_list[i+2]);
156
157 InitScreenCoordinates(vtx2);
158
159 DEBUG_LOG(GPU,
160 "Triangle %d/%d (%d buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
161 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
162 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
163 i,output_list.size(), buffer_vertices.size(),
164 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(),
165 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
166 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(),
167 vtx0.screenpos.x.ToFloat32(), vtx0.screenpos.y.ToFloat32(), vtx0.screenpos.z.ToFloat32(),
168 vtx1.screenpos.x.ToFloat32(), vtx1.screenpos.y.ToFloat32(), vtx1.screenpos.z.ToFloat32(),
169 vtx2.screenpos.x.ToFloat32(), vtx2.screenpos.y.ToFloat32(), vtx2.screenpos.z.ToFloat32());
170
171 // TODO: Send triangle to rasterizer
172 }
173}
174
175
176} // namespace
177
178} // namespace
diff --git a/src/video_core/clipper.h b/src/video_core/clipper.h
new file mode 100644
index 000000000..14d31ca1e
--- /dev/null
+++ b/src/video_core/clipper.h
@@ -0,0 +1,21 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Pica {
8
9namespace VertexShader {
10 struct OutputVertex;
11}
12
13namespace Clipper {
14
15using VertexShader::OutputVertex;
16
17void ProcessTriangle(OutputVertex& v0, OutputVertex& v1, OutputVertex& v2);
18
19} // namespace
20
21} // namespace
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 6bbd3ce33..1ced0d323 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -50,7 +50,12 @@ struct Regs {
50 INSERT_PADDING_WORDS(0x1); 50 INSERT_PADDING_WORDS(0x1);
51 BitField<0, 24, u32> viewport_size_y; 51 BitField<0, 24, u32> viewport_size_y;
52 52
53 INSERT_PADDING_WORDS(0xc); 53 INSERT_PADDING_WORDS(0x9);
54
55 BitField<0, 24, u32> viewport_depth_range; // float24
56 BitField<0, 24, u32> viewport_depth_far_plane; // float24
57
58 INSERT_PADDING_WORDS(0x1);
54 59
55 union { 60 union {
56 // Maps components of output vertex attributes to semantics 61 // Maps components of output vertex attributes to semantics
@@ -82,7 +87,14 @@ struct Regs {
82 BitField<24, 5, Semantic> map_w; 87 BitField<24, 5, Semantic> map_w;
83 } vs_output_attributes[7]; 88 } vs_output_attributes[7];
84 89
85 INSERT_PADDING_WORDS(0x1a9); 90 INSERT_PADDING_WORDS(0x11);
91
92 union {
93 BitField< 0, 16, u32> x;
94 BitField<16, 16, u32> y;
95 } viewport_corner;
96
97 INSERT_PADDING_WORDS(0x197);
86 98
87 struct { 99 struct {
88 enum class Format : u64 { 100 enum class Format : u64 {
@@ -340,6 +352,9 @@ struct Regs {
340 352
341 ADD_FIELD(viewport_size_x); 353 ADD_FIELD(viewport_size_x);
342 ADD_FIELD(viewport_size_y); 354 ADD_FIELD(viewport_size_y);
355 ADD_FIELD(viewport_depth_range);
356 ADD_FIELD(viewport_depth_far_plane);
357 ADD_FIELD(viewport_corner);
343 ADD_FIELD(vertex_attributes); 358 ADD_FIELD(vertex_attributes);
344 ADD_FIELD(index_array); 359 ADD_FIELD(index_array);
345 ADD_FIELD(num_vertices); 360 ADD_FIELD(num_vertices);
@@ -391,8 +406,11 @@ private:
391 406
392ASSERT_REG_POSITION(viewport_size_x, 0x41); 407ASSERT_REG_POSITION(viewport_size_x, 0x41);
393ASSERT_REG_POSITION(viewport_size_y, 0x43); 408ASSERT_REG_POSITION(viewport_size_y, 0x43);
409ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
410ASSERT_REG_POSITION(viewport_depth_far_plane, 0x4e);
394ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); 411ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
395ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); 412ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
413ASSERT_REG_POSITION(viewport_corner, 0x68);
396ASSERT_REG_POSITION(vertex_attributes, 0x200); 414ASSERT_REG_POSITION(vertex_attributes, 0x200);
397ASSERT_REG_POSITION(index_array, 0x227); 415ASSERT_REG_POSITION(index_array, 0x227);
398ASSERT_REG_POSITION(num_vertices, 0x228); 416ASSERT_REG_POSITION(num_vertices, 0x228);
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index b2196d13c..2354ffb99 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "clipper.h"
5#include "pica.h" 6#include "pica.h"
6#include "primitive_assembly.h" 7#include "primitive_assembly.h"
7#include "vertex_shader.h" 8#include "vertex_shader.h"
@@ -23,8 +24,7 @@ void SubmitVertex(OutputVertex& vtx)
23 } else { 24 } else {
24 buffer_index = 0; 25 buffer_index = 0;
25 26
26 // TODO 27 Clipper::ProcessTriangle(buffer[0], buffer[1], vtx);
27 // Clipper::ProcessTriangle(buffer[0], buffer[1], vtx);
28 } 28 }
29 break; 29 break;
30 30
@@ -32,8 +32,7 @@ void SubmitVertex(OutputVertex& vtx)
32 if (buffer_index == 2) { 32 if (buffer_index == 2) {
33 buffer_index = 0; 33 buffer_index = 0;
34 34
35 // TODO 35 Clipper::ProcessTriangle(buffer[0], buffer[1], vtx);
36 // Clipper::ProcessTriangle(buffer[0], buffer[1], vtx);
37 36
38 buffer[1] = vtx; 37 buffer[1] = vtx;
39 } else { 38 } else {
diff --git a/src/video_core/video_core.vcxproj b/src/video_core/video_core.vcxproj
index 9cf3b0858..99ab63dce 100644
--- a/src/video_core/video_core.vcxproj
+++ b/src/video_core/video_core.vcxproj
@@ -20,6 +20,7 @@
20 </ItemGroup> 20 </ItemGroup>
21 <ItemGroup> 21 <ItemGroup>
22 <ClCompile Include="renderer_opengl\renderer_opengl.cpp" /> 22 <ClCompile Include="renderer_opengl\renderer_opengl.cpp" />
23 <ClCompile Include="clipper.cpp" />
23 <ClCompile Include="command_processor.cpp" /> 24 <ClCompile Include="command_processor.cpp" />
24 <ClCompile Include="primitive_assembly.cpp" /> 25 <ClCompile Include="primitive_assembly.cpp" />
25 <ClCompile Include="utils.cpp" /> 26 <ClCompile Include="utils.cpp" />
@@ -27,6 +28,7 @@
27 <ClCompile Include="video_core.cpp" /> 28 <ClCompile Include="video_core.cpp" />
28 </ItemGroup> 29 </ItemGroup>
29 <ItemGroup> 30 <ItemGroup>
31 <ClInclude Include="clipper.h" />
30 <ClInclude Include="command_processor.h" /> 32 <ClInclude Include="command_processor.h" />
31 <ClInclude Include="gpu_debugger.h" /> 33 <ClInclude Include="gpu_debugger.h" />
32 <ClInclude Include="math.h" /> 34 <ClInclude Include="math.h" />
diff --git a/src/video_core/video_core.vcxproj.filters b/src/video_core/video_core.vcxproj.filters
index 9da20b284..5222f2fa0 100644
--- a/src/video_core/video_core.vcxproj.filters
+++ b/src/video_core/video_core.vcxproj.filters
@@ -9,6 +9,7 @@
9 <ClCompile Include="renderer_opengl\renderer_opengl.cpp"> 9 <ClCompile Include="renderer_opengl\renderer_opengl.cpp">
10 <Filter>renderer_opengl</Filter> 10 <Filter>renderer_opengl</Filter>
11 </ClCompile> 11 </ClCompile>
12 <ClCompile Include="clipper.cpp" />
12 <ClCompile Include="command_processor.cpp" /> 13 <ClCompile Include="command_processor.cpp" />
13 <ClCompile Include="primitive_assembly.cpp" /> 14 <ClCompile Include="primitive_assembly.cpp" />
14 <ClCompile Include="utils.cpp" /> 15 <ClCompile Include="utils.cpp" />
@@ -19,6 +20,7 @@
19 <ClInclude Include="renderer_opengl\renderer_opengl.h"> 20 <ClInclude Include="renderer_opengl\renderer_opengl.h">
20 <Filter>renderer_opengl</Filter> 21 <Filter>renderer_opengl</Filter>
21 </ClInclude> 22 </ClInclude>
23 <ClInclude Include="clipper.h" />
22 <ClInclude Include="command_processor.h" /> 24 <ClInclude Include="command_processor.h" />
23 <ClInclude Include="gpu_debugger.h" /> 25 <ClInclude Include="gpu_debugger.h" />
24 <ClInclude Include="math.h" /> 26 <ClInclude Include="math.h" />