summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt16
-rw-r--r--src/video_core/renderer_base.cpp2
-rw-r--r--src/video_core/swrasterizer/clipper.cpp (renamed from src/video_core/clipper.cpp)4
-rw-r--r--src/video_core/swrasterizer/clipper.h (renamed from src/video_core/clipper.h)0
-rw-r--r--src/video_core/swrasterizer/framebuffer.cpp358
-rw-r--r--src/video_core/swrasterizer/framebuffer.h29
-rw-r--r--src/video_core/swrasterizer/rasterizer.cpp (renamed from src/video_core/rasterizer.cpp)555
-rw-r--r--src/video_core/swrasterizer/rasterizer.h (renamed from src/video_core/rasterizer.h)0
-rw-r--r--src/video_core/swrasterizer/swrasterizer.cpp (renamed from src/video_core/swrasterizer.cpp)4
-rw-r--r--src/video_core/swrasterizer/swrasterizer.h (renamed from src/video_core/swrasterizer.h)0
-rw-r--r--src/video_core/swrasterizer/texturing.cpp228
-rw-r--r--src/video_core/swrasterizer/texturing.h28
12 files changed, 661 insertions, 563 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 11bc61e14..5317719e8 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,10 +1,8 @@
1set(SRCS 1set(SRCS
2 clipper.cpp
3 command_processor.cpp 2 command_processor.cpp
4 debug_utils/debug_utils.cpp 3 debug_utils/debug_utils.cpp
5 pica.cpp 4 pica.cpp
6 primitive_assembly.cpp 5 primitive_assembly.cpp
7 rasterizer.cpp
8 regs.cpp 6 regs.cpp
9 renderer_base.cpp 7 renderer_base.cpp
10 renderer_opengl/gl_rasterizer.cpp 8 renderer_opengl/gl_rasterizer.cpp
@@ -15,7 +13,11 @@ set(SRCS
15 renderer_opengl/renderer_opengl.cpp 13 renderer_opengl/renderer_opengl.cpp
16 shader/shader.cpp 14 shader/shader.cpp
17 shader/shader_interpreter.cpp 15 shader/shader_interpreter.cpp
18 swrasterizer.cpp 16 swrasterizer/clipper.cpp
17 swrasterizer/framebuffer.cpp
18 swrasterizer/rasterizer.cpp
19 swrasterizer/swrasterizer.cpp
20 swrasterizer/texturing.cpp
19 texture/etc1.cpp 21 texture/etc1.cpp
20 texture/texture_decode.cpp 22 texture/texture_decode.cpp
21 vertex_loader.cpp 23 vertex_loader.cpp
@@ -23,7 +25,6 @@ set(SRCS
23 ) 25 )
24 26
25set(HEADERS 27set(HEADERS
26 clipper.h
27 command_processor.h 28 command_processor.h
28 debug_utils/debug_utils.h 29 debug_utils/debug_utils.h
29 gpu_debugger.h 30 gpu_debugger.h
@@ -31,7 +32,6 @@ set(HEADERS
31 pica_state.h 32 pica_state.h
32 pica_types.h 33 pica_types.h
33 primitive_assembly.h 34 primitive_assembly.h
34 rasterizer.h
35 rasterizer_interface.h 35 rasterizer_interface.h
36 regs.h 36 regs.h
37 regs_framebuffer.h 37 regs_framebuffer.h
@@ -52,7 +52,11 @@ set(HEADERS
52 shader/debug_data.h 52 shader/debug_data.h
53 shader/shader.h 53 shader/shader.h
54 shader/shader_interpreter.h 54 shader/shader_interpreter.h
55 swrasterizer.h 55 swrasterizer/clipper.h
56 swrasterizer/framebuffer.h
57 swrasterizer/rasterizer.h
58 swrasterizer/swrasterizer.h
59 swrasterizer/texturing.h
56 texture/etc1.h 60 texture/etc1.h
57 texture/texture_decode.h 61 texture/texture_decode.h
58 utils.h 62 utils.h
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index fd38175b3..f6ece5c4b 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -6,7 +6,7 @@
6#include <memory> 6#include <memory>
7#include "video_core/renderer_base.h" 7#include "video_core/renderer_base.h"
8#include "video_core/renderer_opengl/gl_rasterizer.h" 8#include "video_core/renderer_opengl/gl_rasterizer.h"
9#include "video_core/swrasterizer.h" 9#include "video_core/swrasterizer/swrasterizer.h"
10#include "video_core/video_core.h" 10#include "video_core/video_core.h"
11 11
12void RendererBase::RefreshRasterizerSetting() { 12void RendererBase::RefreshRasterizerSetting() {
diff --git a/src/video_core/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp
index 1e8e751ba..2d80822d9 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/swrasterizer/clipper.cpp
@@ -11,11 +11,11 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/vector_math.h" 13#include "common/vector_math.h"
14#include "video_core/clipper.h"
15#include "video_core/pica_state.h" 14#include "video_core/pica_state.h"
16#include "video_core/pica_types.h" 15#include "video_core/pica_types.h"
17#include "video_core/rasterizer.h"
18#include "video_core/shader/shader.h" 16#include "video_core/shader/shader.h"
17#include "video_core/swrasterizer/clipper.h"
18#include "video_core/swrasterizer/rasterizer.h"
19 19
20using Pica::Rasterizer::Vertex; 20using Pica::Rasterizer::Vertex;
21 21
diff --git a/src/video_core/clipper.h b/src/video_core/swrasterizer/clipper.h
index b51af0af9..b51af0af9 100644
--- a/src/video_core/clipper.h
+++ b/src/video_core/swrasterizer/clipper.h
diff --git a/src/video_core/swrasterizer/framebuffer.cpp b/src/video_core/swrasterizer/framebuffer.cpp
new file mode 100644
index 000000000..7de3aac75
--- /dev/null
+++ b/src/video_core/swrasterizer/framebuffer.cpp
@@ -0,0 +1,358 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/assert.h"
8#include "common/color.h"
9#include "common/common_types.h"
10#include "common/logging/log.h"
11#include "common/math_util.h"
12#include "common/vector_math.h"
13#include "core/hw/gpu.h"
14#include "core/memory.h"
15#include "video_core/pica_state.h"
16#include "video_core/regs_framebuffer.h"
17#include "video_core/swrasterizer/framebuffer.h"
18#include "video_core/utils.h"
19
20namespace Pica {
21namespace Rasterizer {
22
23void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
24 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
25 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
26
27 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
28 // NOTE: The framebuffer height register contains the actual FB height minus one.
29 y = framebuffer.height - y;
30
31 const u32 coarse_y = y & ~7;
32 u32 bytes_per_pixel =
33 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
34 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
35 coarse_y * framebuffer.width * bytes_per_pixel;
36 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
37
38 switch (framebuffer.color_format) {
39 case FramebufferRegs::ColorFormat::RGBA8:
40 Color::EncodeRGBA8(color, dst_pixel);
41 break;
42
43 case FramebufferRegs::ColorFormat::RGB8:
44 Color::EncodeRGB8(color, dst_pixel);
45 break;
46
47 case FramebufferRegs::ColorFormat::RGB5A1:
48 Color::EncodeRGB5A1(color, dst_pixel);
49 break;
50
51 case FramebufferRegs::ColorFormat::RGB565:
52 Color::EncodeRGB565(color, dst_pixel);
53 break;
54
55 case FramebufferRegs::ColorFormat::RGBA4:
56 Color::EncodeRGBA4(color, dst_pixel);
57 break;
58
59 default:
60 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
61 framebuffer.color_format.Value());
62 UNIMPLEMENTED();
63 }
64}
65
66const Math::Vec4<u8> GetPixel(int x, int y) {
67 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
68 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
69
70 y = framebuffer.height - y;
71
72 const u32 coarse_y = y & ~7;
73 u32 bytes_per_pixel =
74 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
75 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
76 coarse_y * framebuffer.width * bytes_per_pixel;
77 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
78
79 switch (framebuffer.color_format) {
80 case FramebufferRegs::ColorFormat::RGBA8:
81 return Color::DecodeRGBA8(src_pixel);
82
83 case FramebufferRegs::ColorFormat::RGB8:
84 return Color::DecodeRGB8(src_pixel);
85
86 case FramebufferRegs::ColorFormat::RGB5A1:
87 return Color::DecodeRGB5A1(src_pixel);
88
89 case FramebufferRegs::ColorFormat::RGB565:
90 return Color::DecodeRGB565(src_pixel);
91
92 case FramebufferRegs::ColorFormat::RGBA4:
93 return Color::DecodeRGBA4(src_pixel);
94
95 default:
96 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
97 framebuffer.color_format.Value());
98 UNIMPLEMENTED();
99 }
100
101 return {0, 0, 0, 0};
102}
103
104u32 GetDepth(int x, int y) {
105 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
106 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
107 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
108
109 y = framebuffer.height - y;
110
111 const u32 coarse_y = y & ~7;
112 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
113 u32 stride = framebuffer.width * bytes_per_pixel;
114
115 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
116 u8* src_pixel = depth_buffer + src_offset;
117
118 switch (framebuffer.depth_format) {
119 case FramebufferRegs::DepthFormat::D16:
120 return Color::DecodeD16(src_pixel);
121 case FramebufferRegs::DepthFormat::D24:
122 return Color::DecodeD24(src_pixel);
123 case FramebufferRegs::DepthFormat::D24S8:
124 return Color::DecodeD24S8(src_pixel).x;
125 default:
126 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
127 UNIMPLEMENTED();
128 return 0;
129 }
130}
131
132u8 GetStencil(int x, int y) {
133 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
134 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
135 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
136
137 y = framebuffer.height - y;
138
139 const u32 coarse_y = y & ~7;
140 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
141 u32 stride = framebuffer.width * bytes_per_pixel;
142
143 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
144 u8* src_pixel = depth_buffer + src_offset;
145
146 switch (framebuffer.depth_format) {
147 case FramebufferRegs::DepthFormat::D24S8:
148 return Color::DecodeD24S8(src_pixel).y;
149
150 default:
151 LOG_WARNING(
152 HW_GPU,
153 "GetStencil called for function which doesn't have a stencil component (format %u)",
154 framebuffer.depth_format);
155 return 0;
156 }
157}
158
159void SetDepth(int x, int y, u32 value) {
160 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
161 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
162 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
163
164 y = framebuffer.height - y;
165
166 const u32 coarse_y = y & ~7;
167 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
168 u32 stride = framebuffer.width * bytes_per_pixel;
169
170 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
171 u8* dst_pixel = depth_buffer + dst_offset;
172
173 switch (framebuffer.depth_format) {
174 case FramebufferRegs::DepthFormat::D16:
175 Color::EncodeD16(value, dst_pixel);
176 break;
177
178 case FramebufferRegs::DepthFormat::D24:
179 Color::EncodeD24(value, dst_pixel);
180 break;
181
182 case FramebufferRegs::DepthFormat::D24S8:
183 Color::EncodeD24X8(value, dst_pixel);
184 break;
185
186 default:
187 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
188 UNIMPLEMENTED();
189 break;
190 }
191}
192
193void SetStencil(int x, int y, u8 value) {
194 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
195 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
196 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
197
198 y = framebuffer.height - y;
199
200 const u32 coarse_y = y & ~7;
201 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
202 u32 stride = framebuffer.width * bytes_per_pixel;
203
204 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
205 u8* dst_pixel = depth_buffer + dst_offset;
206
207 switch (framebuffer.depth_format) {
208 case Pica::FramebufferRegs::DepthFormat::D16:
209 case Pica::FramebufferRegs::DepthFormat::D24:
210 // Nothing to do
211 break;
212
213 case Pica::FramebufferRegs::DepthFormat::D24S8:
214 Color::EncodeX24S8(value, dst_pixel);
215 break;
216
217 default:
218 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
219 UNIMPLEMENTED();
220 break;
221 }
222}
223
224u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
225 switch (action) {
226 case FramebufferRegs::StencilAction::Keep:
227 return old_stencil;
228
229 case FramebufferRegs::StencilAction::Zero:
230 return 0;
231
232 case FramebufferRegs::StencilAction::Replace:
233 return ref;
234
235 case FramebufferRegs::StencilAction::Increment:
236 // Saturated increment
237 return std::min<u8>(old_stencil, 254) + 1;
238
239 case FramebufferRegs::StencilAction::Decrement:
240 // Saturated decrement
241 return std::max<u8>(old_stencil, 1) - 1;
242
243 case FramebufferRegs::StencilAction::Invert:
244 return ~old_stencil;
245
246 case FramebufferRegs::StencilAction::IncrementWrap:
247 return old_stencil + 1;
248
249 case FramebufferRegs::StencilAction::DecrementWrap:
250 return old_stencil - 1;
251
252 default:
253 LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
254 UNIMPLEMENTED();
255 return 0;
256 }
257}
258
259Math::Vec4<u8> EvaluateBlendEquation(const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
260 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
261 FramebufferRegs::BlendEquation equation) {
262 Math::Vec4<int> result;
263
264 auto src_result = (src * srcfactor).Cast<int>();
265 auto dst_result = (dest * destfactor).Cast<int>();
266
267 switch (equation) {
268 case FramebufferRegs::BlendEquation::Add:
269 result = (src_result + dst_result) / 255;
270 break;
271
272 case FramebufferRegs::BlendEquation::Subtract:
273 result = (src_result - dst_result) / 255;
274 break;
275
276 case FramebufferRegs::BlendEquation::ReverseSubtract:
277 result = (dst_result - src_result) / 255;
278 break;
279
280 // TODO: How do these two actually work? OpenGL doesn't include the blend factors in the
281 // min/max computations, but is this what the 3DS actually does?
282 case FramebufferRegs::BlendEquation::Min:
283 result.r() = std::min(src.r(), dest.r());
284 result.g() = std::min(src.g(), dest.g());
285 result.b() = std::min(src.b(), dest.b());
286 result.a() = std::min(src.a(), dest.a());
287 break;
288
289 case FramebufferRegs::BlendEquation::Max:
290 result.r() = std::max(src.r(), dest.r());
291 result.g() = std::max(src.g(), dest.g());
292 result.b() = std::max(src.b(), dest.b());
293 result.a() = std::max(src.a(), dest.a());
294 break;
295
296 default:
297 LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation);
298 UNIMPLEMENTED();
299 }
300
301 return Math::Vec4<u8>(MathUtil::Clamp(result.r(), 0, 255), MathUtil::Clamp(result.g(), 0, 255),
302 MathUtil::Clamp(result.b(), 0, 255), MathUtil::Clamp(result.a(), 0, 255));
303};
304
305u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op) {
306 switch (op) {
307 case FramebufferRegs::LogicOp::Clear:
308 return 0;
309
310 case FramebufferRegs::LogicOp::And:
311 return src & dest;
312
313 case FramebufferRegs::LogicOp::AndReverse:
314 return src & ~dest;
315
316 case FramebufferRegs::LogicOp::Copy:
317 return src;
318
319 case FramebufferRegs::LogicOp::Set:
320 return 255;
321
322 case FramebufferRegs::LogicOp::CopyInverted:
323 return ~src;
324
325 case FramebufferRegs::LogicOp::NoOp:
326 return dest;
327
328 case FramebufferRegs::LogicOp::Invert:
329 return ~dest;
330
331 case FramebufferRegs::LogicOp::Nand:
332 return ~(src & dest);
333
334 case FramebufferRegs::LogicOp::Or:
335 return src | dest;
336
337 case FramebufferRegs::LogicOp::Nor:
338 return ~(src | dest);
339
340 case FramebufferRegs::LogicOp::Xor:
341 return src ^ dest;
342
343 case FramebufferRegs::LogicOp::Equiv:
344 return ~(src ^ dest);
345
346 case FramebufferRegs::LogicOp::AndInverted:
347 return ~src & dest;
348
349 case FramebufferRegs::LogicOp::OrReverse:
350 return src | ~dest;
351
352 case FramebufferRegs::LogicOp::OrInverted:
353 return ~src | dest;
354 }
355};
356
357} // namespace Rasterizer
358} // namespace Pica
diff --git a/src/video_core/swrasterizer/framebuffer.h b/src/video_core/swrasterizer/framebuffer.h
new file mode 100644
index 000000000..4a32a4979
--- /dev/null
+++ b/src/video_core/swrasterizer/framebuffer.h
@@ -0,0 +1,29 @@
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 "common/common_types.h"
8#include "common/vector_math.h"
9#include "video_core/regs_framebuffer.h"
10
11namespace Pica {
12namespace Rasterizer {
13
14void DrawPixel(int x, int y, const Math::Vec4<u8>& color);
15const Math::Vec4<u8> GetPixel(int x, int y);
16u32 GetDepth(int x, int y);
17u8 GetStencil(int x, int y);
18void SetDepth(int x, int y, u32 value);
19void SetStencil(int x, int y, u8 value);
20u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref);
21
22Math::Vec4<u8> EvaluateBlendEquation(const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
23 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
24 FramebufferRegs::BlendEquation equation);
25
26u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op);
27
28} // namespace Rasterizer
29} // namespace Pica
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index 83a08ebd7..7557fcb89 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -18,254 +18,19 @@
18#include "video_core/debug_utils/debug_utils.h" 18#include "video_core/debug_utils/debug_utils.h"
19#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
20#include "video_core/pica_types.h" 20#include "video_core/pica_types.h"
21#include "video_core/rasterizer.h"
22#include "video_core/regs_framebuffer.h" 21#include "video_core/regs_framebuffer.h"
23#include "video_core/regs_rasterizer.h" 22#include "video_core/regs_rasterizer.h"
24#include "video_core/regs_texturing.h" 23#include "video_core/regs_texturing.h"
25#include "video_core/shader/shader.h" 24#include "video_core/shader/shader.h"
25#include "video_core/swrasterizer/framebuffer.h"
26#include "video_core/swrasterizer/rasterizer.h"
27#include "video_core/swrasterizer/texturing.h"
26#include "video_core/texture/texture_decode.h" 28#include "video_core/texture/texture_decode.h"
27#include "video_core/utils.h" 29#include "video_core/utils.h"
28 30
29namespace Pica { 31namespace Pica {
30
31namespace Rasterizer { 32namespace Rasterizer {
32 33
33static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
34 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
35 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
36
37 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
38 // NOTE: The framebuffer height register contains the actual FB height minus one.
39 y = framebuffer.height - y;
40
41 const u32 coarse_y = y & ~7;
42 u32 bytes_per_pixel =
43 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
44 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
45 coarse_y * framebuffer.width * bytes_per_pixel;
46 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
47
48 switch (framebuffer.color_format) {
49 case FramebufferRegs::ColorFormat::RGBA8:
50 Color::EncodeRGBA8(color, dst_pixel);
51 break;
52
53 case FramebufferRegs::ColorFormat::RGB8:
54 Color::EncodeRGB8(color, dst_pixel);
55 break;
56
57 case FramebufferRegs::ColorFormat::RGB5A1:
58 Color::EncodeRGB5A1(color, dst_pixel);
59 break;
60
61 case FramebufferRegs::ColorFormat::RGB565:
62 Color::EncodeRGB565(color, dst_pixel);
63 break;
64
65 case FramebufferRegs::ColorFormat::RGBA4:
66 Color::EncodeRGBA4(color, dst_pixel);
67 break;
68
69 default:
70 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
71 framebuffer.color_format.Value());
72 UNIMPLEMENTED();
73 }
74}
75
76static const Math::Vec4<u8> GetPixel(int x, int y) {
77 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
78 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
79
80 y = framebuffer.height - y;
81
82 const u32 coarse_y = y & ~7;
83 u32 bytes_per_pixel =
84 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
85 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
86 coarse_y * framebuffer.width * bytes_per_pixel;
87 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
88
89 switch (framebuffer.color_format) {
90 case FramebufferRegs::ColorFormat::RGBA8:
91 return Color::DecodeRGBA8(src_pixel);
92
93 case FramebufferRegs::ColorFormat::RGB8:
94 return Color::DecodeRGB8(src_pixel);
95
96 case FramebufferRegs::ColorFormat::RGB5A1:
97 return Color::DecodeRGB5A1(src_pixel);
98
99 case FramebufferRegs::ColorFormat::RGB565:
100 return Color::DecodeRGB565(src_pixel);
101
102 case FramebufferRegs::ColorFormat::RGBA4:
103 return Color::DecodeRGBA4(src_pixel);
104
105 default:
106 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
107 framebuffer.color_format.Value());
108 UNIMPLEMENTED();
109 }
110
111 return {0, 0, 0, 0};
112}
113
114static u32 GetDepth(int x, int y) {
115 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
116 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
117 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
118
119 y = framebuffer.height - y;
120
121 const u32 coarse_y = y & ~7;
122 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
123 u32 stride = framebuffer.width * bytes_per_pixel;
124
125 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
126 u8* src_pixel = depth_buffer + src_offset;
127
128 switch (framebuffer.depth_format) {
129 case FramebufferRegs::DepthFormat::D16:
130 return Color::DecodeD16(src_pixel);
131 case FramebufferRegs::DepthFormat::D24:
132 return Color::DecodeD24(src_pixel);
133 case FramebufferRegs::DepthFormat::D24S8:
134 return Color::DecodeD24S8(src_pixel).x;
135 default:
136 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
137 UNIMPLEMENTED();
138 return 0;
139 }
140}
141
142static u8 GetStencil(int x, int y) {
143 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
144 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
145 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
146
147 y = framebuffer.height - y;
148
149 const u32 coarse_y = y & ~7;
150 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
151 u32 stride = framebuffer.width * bytes_per_pixel;
152
153 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
154 u8* src_pixel = depth_buffer + src_offset;
155
156 switch (framebuffer.depth_format) {
157 case FramebufferRegs::DepthFormat::D24S8:
158 return Color::DecodeD24S8(src_pixel).y;
159
160 default:
161 LOG_WARNING(
162 HW_GPU,
163 "GetStencil called for function which doesn't have a stencil component (format %u)",
164 framebuffer.depth_format);
165 return 0;
166 }
167}
168
169static void SetDepth(int x, int y, u32 value) {
170 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
171 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
172 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
173
174 y = framebuffer.height - y;
175
176 const u32 coarse_y = y & ~7;
177 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
178 u32 stride = framebuffer.width * bytes_per_pixel;
179
180 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
181 u8* dst_pixel = depth_buffer + dst_offset;
182
183 switch (framebuffer.depth_format) {
184 case FramebufferRegs::DepthFormat::D16:
185 Color::EncodeD16(value, dst_pixel);
186 break;
187
188 case FramebufferRegs::DepthFormat::D24:
189 Color::EncodeD24(value, dst_pixel);
190 break;
191
192 case FramebufferRegs::DepthFormat::D24S8:
193 Color::EncodeD24X8(value, dst_pixel);
194 break;
195
196 default:
197 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
198 UNIMPLEMENTED();
199 break;
200 }
201}
202
203static void SetStencil(int x, int y, u8 value) {
204 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
205 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
206 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
207
208 y = framebuffer.height - y;
209
210 const u32 coarse_y = y & ~7;
211 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
212 u32 stride = framebuffer.width * bytes_per_pixel;
213
214 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
215 u8* dst_pixel = depth_buffer + dst_offset;
216
217 switch (framebuffer.depth_format) {
218 case Pica::FramebufferRegs::DepthFormat::D16:
219 case Pica::FramebufferRegs::DepthFormat::D24:
220 // Nothing to do
221 break;
222
223 case Pica::FramebufferRegs::DepthFormat::D24S8:
224 Color::EncodeX24S8(value, dst_pixel);
225 break;
226
227 default:
228 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
229 UNIMPLEMENTED();
230 break;
231 }
232}
233
234static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
235 switch (action) {
236 case FramebufferRegs::StencilAction::Keep:
237 return old_stencil;
238
239 case FramebufferRegs::StencilAction::Zero:
240 return 0;
241
242 case FramebufferRegs::StencilAction::Replace:
243 return ref;
244
245 case FramebufferRegs::StencilAction::Increment:
246 // Saturated increment
247 return std::min<u8>(old_stencil, 254) + 1;
248
249 case FramebufferRegs::StencilAction::Decrement:
250 // Saturated decrement
251 return std::max<u8>(old_stencil, 1) - 1;
252
253 case FramebufferRegs::StencilAction::Invert:
254 return ~old_stencil;
255
256 case FramebufferRegs::StencilAction::IncrementWrap:
257 return old_stencil + 1;
258
259 case FramebufferRegs::StencilAction::DecrementWrap:
260 return old_stencil - 1;
261
262 default:
263 LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
264 UNIMPLEMENTED();
265 return 0;
266 }
267}
268
269// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values 34// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
270struct Fix12P4 { 35struct Fix12P4 {
271 Fix12P4() {} 36 Fix12P4() {}
@@ -539,34 +304,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
539 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height))) 304 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
540 .ToFloat32(); 305 .ToFloat32();
541 306
542 static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
543 int val, unsigned size) {
544 switch (mode) {
545 case TexturingRegs::TextureConfig::ClampToEdge:
546 val = std::max(val, 0);
547 val = std::min(val, (int)size - 1);
548 return val;
549
550 case TexturingRegs::TextureConfig::ClampToBorder:
551 return val;
552
553 case TexturingRegs::TextureConfig::Repeat:
554 return (int)((unsigned)val % size);
555
556 case TexturingRegs::TextureConfig::MirroredRepeat: {
557 unsigned int coord = ((unsigned)val % (2 * size));
558 if (coord >= size)
559 coord = 2 * size - 1 - coord;
560 return (int)coord;
561 }
562
563 default:
564 LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x", (int)mode);
565 UNIMPLEMENTED();
566 return 0;
567 }
568 };
569
570 if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder && 307 if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder &&
571 (s < 0 || static_cast<u32>(s) >= texture.config.width)) || 308 (s < 0 || static_cast<u32>(s) >= texture.config.width)) ||
572 (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder && 309 (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder &&
@@ -615,9 +352,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
615 ++tev_stage_index) { 352 ++tev_stage_index) {
616 const auto& tev_stage = tev_stages[tev_stage_index]; 353 const auto& tev_stage = tev_stages[tev_stage_index];
617 using Source = TexturingRegs::TevStageConfig::Source; 354 using Source = TexturingRegs::TevStageConfig::Source;
618 using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
619 using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
620 using Operation = TexturingRegs::TevStageConfig::Operation;
621 355
622 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 356 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
623 switch (source) { 357 switch (source) {
@@ -657,187 +391,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
657 } 391 }
658 }; 392 };
659 393
660 static auto GetColorModifier = [](ColorModifier factor,
661 const Math::Vec4<u8>& values) -> Math::Vec3<u8> {
662 switch (factor) {
663 case ColorModifier::SourceColor:
664 return values.rgb();
665
666 case ColorModifier::OneMinusSourceColor:
667 return (Math::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>();
668
669 case ColorModifier::SourceAlpha:
670 return values.aaa();
671
672 case ColorModifier::OneMinusSourceAlpha:
673 return (Math::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>();
674
675 case ColorModifier::SourceRed:
676 return values.rrr();
677
678 case ColorModifier::OneMinusSourceRed:
679 return (Math::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>();
680
681 case ColorModifier::SourceGreen:
682 return values.ggg();
683
684 case ColorModifier::OneMinusSourceGreen:
685 return (Math::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>();
686
687 case ColorModifier::SourceBlue:
688 return values.bbb();
689
690 case ColorModifier::OneMinusSourceBlue:
691 return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>();
692 }
693 };
694
695 static auto GetAlphaModifier = [](AlphaModifier factor,
696 const Math::Vec4<u8>& values) -> u8 {
697 switch (factor) {
698 case AlphaModifier::SourceAlpha:
699 return values.a();
700
701 case AlphaModifier::OneMinusSourceAlpha:
702 return 255 - values.a();
703
704 case AlphaModifier::SourceRed:
705 return values.r();
706
707 case AlphaModifier::OneMinusSourceRed:
708 return 255 - values.r();
709
710 case AlphaModifier::SourceGreen:
711 return values.g();
712
713 case AlphaModifier::OneMinusSourceGreen:
714 return 255 - values.g();
715
716 case AlphaModifier::SourceBlue:
717 return values.b();
718
719 case AlphaModifier::OneMinusSourceBlue:
720 return 255 - values.b();
721 }
722 };
723
724 static auto ColorCombine = [](Operation op,
725 const Math::Vec3<u8> input[3]) -> Math::Vec3<u8> {
726 switch (op) {
727 case Operation::Replace:
728 return input[0];
729
730 case Operation::Modulate:
731 return ((input[0] * input[1]) / 255).Cast<u8>();
732
733 case Operation::Add: {
734 auto result = input[0] + input[1];
735 result.r() = std::min(255, result.r());
736 result.g() = std::min(255, result.g());
737 result.b() = std::min(255, result.b());
738 return result.Cast<u8>();
739 }
740
741 case Operation::AddSigned: {
742 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to
743 // (byte) 128 is correct
744 auto result = input[0].Cast<int>() + input[1].Cast<int>() -
745 Math::MakeVec<int>(128, 128, 128);
746 result.r() = MathUtil::Clamp<int>(result.r(), 0, 255);
747 result.g() = MathUtil::Clamp<int>(result.g(), 0, 255);
748 result.b() = MathUtil::Clamp<int>(result.b(), 0, 255);
749 return result.Cast<u8>();
750 }
751
752 case Operation::Lerp:
753 return ((input[0] * input[2] +
754 input[1] *
755 (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) /
756 255)
757 .Cast<u8>();
758
759 case Operation::Subtract: {
760 auto result = input[0].Cast<int>() - input[1].Cast<int>();
761 result.r() = std::max(0, result.r());
762 result.g() = std::max(0, result.g());
763 result.b() = std::max(0, result.b());
764 return result.Cast<u8>();
765 }
766
767 case Operation::MultiplyThenAdd: {
768 auto result = (input[0] * input[1] + 255 * input[2].Cast<int>()) / 255;
769 result.r() = std::min(255, result.r());
770 result.g() = std::min(255, result.g());
771 result.b() = std::min(255, result.b());
772 return result.Cast<u8>();
773 }
774
775 case Operation::AddThenMultiply: {
776 auto result = input[0] + input[1];
777 result.r() = std::min(255, result.r());
778 result.g() = std::min(255, result.g());
779 result.b() = std::min(255, result.b());
780 result = (result * input[2].Cast<int>()) / 255;
781 return result.Cast<u8>();
782 }
783 case Operation::Dot3_RGB: {
784 // Not fully accurate.
785 // Worst case scenario seems to yield a +/-3 error
786 // Some HW results indicate that the per-component computation can't have a
787 // higher precision than 1/256,
788 // while dot3_rgb( (0x80,g0,b0),(0x7F,g1,b1) ) and dot3_rgb(
789 // (0x80,g0,b0),(0x80,g1,b1) ) give different results
790 int result =
791 ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 +
792 ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 +
793 ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256;
794 result = std::max(0, std::min(255, result));
795 return {(u8)result, (u8)result, (u8)result};
796 }
797 default:
798 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d", (int)op);
799 UNIMPLEMENTED();
800 return {0, 0, 0};
801 }
802 };
803
804 static auto AlphaCombine = [](Operation op, const std::array<u8, 3>& input) -> u8 {
805 switch (op) {
806 case Operation::Replace:
807 return input[0];
808
809 case Operation::Modulate:
810 return input[0] * input[1] / 255;
811
812 case Operation::Add:
813 return std::min(255, input[0] + input[1]);
814
815 case Operation::AddSigned: {
816 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to
817 // (byte) 128 is correct
818 auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
819 return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
820 }
821
822 case Operation::Lerp:
823 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
824
825 case Operation::Subtract:
826 return std::max(0, (int)input[0] - (int)input[1]);
827
828 case Operation::MultiplyThenAdd:
829 return std::min(255, (input[0] * input[1] + 255 * input[2]) / 255);
830
831 case Operation::AddThenMultiply:
832 return (std::min(255, (input[0] + input[1])) * input[2]) / 255;
833
834 default:
835 LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d", (int)op);
836 UNIMPLEMENTED();
837 return 0;
838 }
839 };
840
841 // color combiner 394 // color combiner
842 // NOTE: Not sure if the alpha combiner might use the color output of the previous 395 // NOTE: Not sure if the alpha combiner might use the color output of the previous
843 // stage as input. Hence, we currently don't directly write the result to 396 // stage as input. Hence, we currently don't directly write the result to
@@ -1152,56 +705,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1152 return combiner_output[channel]; 705 return combiner_output[channel];
1153 }; 706 };
1154 707
1155 static auto EvaluateBlendEquation = [](
1156 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
1157 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
1158 FramebufferRegs::BlendEquation equation) {
1159
1160 Math::Vec4<int> result;
1161
1162 auto src_result = (src * srcfactor).Cast<int>();
1163 auto dst_result = (dest * destfactor).Cast<int>();
1164
1165 switch (equation) {
1166 case FramebufferRegs::BlendEquation::Add:
1167 result = (src_result + dst_result) / 255;
1168 break;
1169
1170 case FramebufferRegs::BlendEquation::Subtract:
1171 result = (src_result - dst_result) / 255;
1172 break;
1173
1174 case FramebufferRegs::BlendEquation::ReverseSubtract:
1175 result = (dst_result - src_result) / 255;
1176 break;
1177
1178 // TODO: How do these two actually work?
1179 // OpenGL doesn't include the blend factors in the min/max computations,
1180 // but is this what the 3DS actually does?
1181 case FramebufferRegs::BlendEquation::Min:
1182 result.r() = std::min(src.r(), dest.r());
1183 result.g() = std::min(src.g(), dest.g());
1184 result.b() = std::min(src.b(), dest.b());
1185 result.a() = std::min(src.a(), dest.a());
1186 break;
1187
1188 case FramebufferRegs::BlendEquation::Max:
1189 result.r() = std::max(src.r(), dest.r());
1190 result.g() = std::max(src.g(), dest.g());
1191 result.b() = std::max(src.b(), dest.b());
1192 result.a() = std::max(src.a(), dest.a());
1193 break;
1194
1195 default:
1196 LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation);
1197 UNIMPLEMENTED();
1198 }
1199
1200 return Math::Vec4<u8>(
1201 MathUtil::Clamp(result.r(), 0, 255), MathUtil::Clamp(result.g(), 0, 255),
1202 MathUtil::Clamp(result.b(), 0, 255), MathUtil::Clamp(result.a(), 0, 255));
1203 };
1204
1205 auto srcfactor = Math::MakeVec(LookupFactor(0, params.factor_source_rgb), 708 auto srcfactor = Math::MakeVec(LookupFactor(0, params.factor_source_rgb),
1206 LookupFactor(1, params.factor_source_rgb), 709 LookupFactor(1, params.factor_source_rgb),
1207 LookupFactor(2, params.factor_source_rgb), 710 LookupFactor(2, params.factor_source_rgb),
@@ -1218,58 +721,6 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1218 dstfactor, params.blend_equation_a) 721 dstfactor, params.blend_equation_a)
1219 .a(); 722 .a();
1220 } else { 723 } else {
1221 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 {
1222 switch (op) {
1223 case FramebufferRegs::LogicOp::Clear:
1224 return 0;
1225
1226 case FramebufferRegs::LogicOp::And:
1227 return src & dest;
1228
1229 case FramebufferRegs::LogicOp::AndReverse:
1230 return src & ~dest;
1231
1232 case FramebufferRegs::LogicOp::Copy:
1233 return src;
1234
1235 case FramebufferRegs::LogicOp::Set:
1236 return 255;
1237
1238 case FramebufferRegs::LogicOp::CopyInverted:
1239 return ~src;
1240
1241 case FramebufferRegs::LogicOp::NoOp:
1242 return dest;
1243
1244 case FramebufferRegs::LogicOp::Invert:
1245 return ~dest;
1246
1247 case FramebufferRegs::LogicOp::Nand:
1248 return ~(src & dest);
1249
1250 case FramebufferRegs::LogicOp::Or:
1251 return src | dest;
1252
1253 case FramebufferRegs::LogicOp::Nor:
1254 return ~(src | dest);
1255
1256 case FramebufferRegs::LogicOp::Xor:
1257 return src ^ dest;
1258
1259 case FramebufferRegs::LogicOp::Equiv:
1260 return ~(src ^ dest);
1261
1262 case FramebufferRegs::LogicOp::AndInverted:
1263 return ~src & dest;
1264
1265 case FramebufferRegs::LogicOp::OrReverse:
1266 return src | ~dest;
1267
1268 case FramebufferRegs::LogicOp::OrInverted:
1269 return ~src | dest;
1270 }
1271 };
1272
1273 blend_output = 724 blend_output =
1274 Math::MakeVec(LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op), 725 Math::MakeVec(LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
1275 LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op), 726 LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
diff --git a/src/video_core/rasterizer.h b/src/video_core/swrasterizer/rasterizer.h
index 3a72ac343..3a72ac343 100644
--- a/src/video_core/rasterizer.h
+++ b/src/video_core/swrasterizer/rasterizer.h
diff --git a/src/video_core/swrasterizer.cpp b/src/video_core/swrasterizer/swrasterizer.cpp
index 9cd21f72b..402b705dd 100644
--- a/src/video_core/swrasterizer.cpp
+++ b/src/video_core/swrasterizer/swrasterizer.cpp
@@ -2,8 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "video_core/clipper.h" 5#include "video_core/swrasterizer/clipper.h"
6#include "video_core/swrasterizer.h" 6#include "video_core/swrasterizer/swrasterizer.h"
7 7
8namespace VideoCore { 8namespace VideoCore {
9 9
diff --git a/src/video_core/swrasterizer.h b/src/video_core/swrasterizer/swrasterizer.h
index 6d42d7409..6d42d7409 100644
--- a/src/video_core/swrasterizer.h
+++ b/src/video_core/swrasterizer/swrasterizer.h
diff --git a/src/video_core/swrasterizer/texturing.cpp b/src/video_core/swrasterizer/texturing.cpp
new file mode 100644
index 000000000..eb18e4ba4
--- /dev/null
+++ b/src/video_core/swrasterizer/texturing.cpp
@@ -0,0 +1,228 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/assert.h"
8#include "common/common_types.h"
9#include "common/math_util.h"
10#include "common/vector_math.h"
11#include "video_core/regs_texturing.h"
12#include "video_core/swrasterizer/texturing.h"
13
14namespace Pica {
15namespace Rasterizer {
16
17using TevStageConfig = TexturingRegs::TevStageConfig;
18
19int GetWrappedTexCoord(TexturingRegs::TextureConfig::WrapMode mode, int val, unsigned size) {
20 switch (mode) {
21 case TexturingRegs::TextureConfig::ClampToEdge:
22 val = std::max(val, 0);
23 val = std::min(val, (int)size - 1);
24 return val;
25
26 case TexturingRegs::TextureConfig::ClampToBorder:
27 return val;
28
29 case TexturingRegs::TextureConfig::Repeat:
30 return (int)((unsigned)val % size);
31
32 case TexturingRegs::TextureConfig::MirroredRepeat: {
33 unsigned int coord = ((unsigned)val % (2 * size));
34 if (coord >= size)
35 coord = 2 * size - 1 - coord;
36 return (int)coord;
37 }
38
39 default:
40 LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x", (int)mode);
41 UNIMPLEMENTED();
42 return 0;
43 }
44};
45
46Math::Vec3<u8> GetColorModifier(TevStageConfig::ColorModifier factor,
47 const Math::Vec4<u8>& values) {
48 using ColorModifier = TevStageConfig::ColorModifier;
49
50 switch (factor) {
51 case ColorModifier::SourceColor:
52 return values.rgb();
53
54 case ColorModifier::OneMinusSourceColor:
55 return (Math::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>();
56
57 case ColorModifier::SourceAlpha:
58 return values.aaa();
59
60 case ColorModifier::OneMinusSourceAlpha:
61 return (Math::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>();
62
63 case ColorModifier::SourceRed:
64 return values.rrr();
65
66 case ColorModifier::OneMinusSourceRed:
67 return (Math::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>();
68
69 case ColorModifier::SourceGreen:
70 return values.ggg();
71
72 case ColorModifier::OneMinusSourceGreen:
73 return (Math::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>();
74
75 case ColorModifier::SourceBlue:
76 return values.bbb();
77
78 case ColorModifier::OneMinusSourceBlue:
79 return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>();
80 }
81};
82
83u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Math::Vec4<u8>& values) {
84 using AlphaModifier = TevStageConfig::AlphaModifier;
85
86 switch (factor) {
87 case AlphaModifier::SourceAlpha:
88 return values.a();
89
90 case AlphaModifier::OneMinusSourceAlpha:
91 return 255 - values.a();
92
93 case AlphaModifier::SourceRed:
94 return values.r();
95
96 case AlphaModifier::OneMinusSourceRed:
97 return 255 - values.r();
98
99 case AlphaModifier::SourceGreen:
100 return values.g();
101
102 case AlphaModifier::OneMinusSourceGreen:
103 return 255 - values.g();
104
105 case AlphaModifier::SourceBlue:
106 return values.b();
107
108 case AlphaModifier::OneMinusSourceBlue:
109 return 255 - values.b();
110 }
111};
112
113Math::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Math::Vec3<u8> input[3]) {
114 using Operation = TevStageConfig::Operation;
115
116 switch (op) {
117 case Operation::Replace:
118 return input[0];
119
120 case Operation::Modulate:
121 return ((input[0] * input[1]) / 255).Cast<u8>();
122
123 case Operation::Add: {
124 auto result = input[0] + input[1];
125 result.r() = std::min(255, result.r());
126 result.g() = std::min(255, result.g());
127 result.b() = std::min(255, result.b());
128 return result.Cast<u8>();
129 }
130
131 case Operation::AddSigned: {
132 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to
133 // (byte) 128 is correct
134 auto result =
135 input[0].Cast<int>() + input[1].Cast<int>() - Math::MakeVec<int>(128, 128, 128);
136 result.r() = MathUtil::Clamp<int>(result.r(), 0, 255);
137 result.g() = MathUtil::Clamp<int>(result.g(), 0, 255);
138 result.b() = MathUtil::Clamp<int>(result.b(), 0, 255);
139 return result.Cast<u8>();
140 }
141
142 case Operation::Lerp:
143 return ((input[0] * input[2] +
144 input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) /
145 255)
146 .Cast<u8>();
147
148 case Operation::Subtract: {
149 auto result = input[0].Cast<int>() - input[1].Cast<int>();
150 result.r() = std::max(0, result.r());
151 result.g() = std::max(0, result.g());
152 result.b() = std::max(0, result.b());
153 return result.Cast<u8>();
154 }
155
156 case Operation::MultiplyThenAdd: {
157 auto result = (input[0] * input[1] + 255 * input[2].Cast<int>()) / 255;
158 result.r() = std::min(255, result.r());
159 result.g() = std::min(255, result.g());
160 result.b() = std::min(255, result.b());
161 return result.Cast<u8>();
162 }
163
164 case Operation::AddThenMultiply: {
165 auto result = input[0] + input[1];
166 result.r() = std::min(255, result.r());
167 result.g() = std::min(255, result.g());
168 result.b() = std::min(255, result.b());
169 result = (result * input[2].Cast<int>()) / 255;
170 return result.Cast<u8>();
171 }
172 case Operation::Dot3_RGB: {
173 // Not fully accurate. Worst case scenario seems to yield a +/-3 error. Some HW results
174 // indicate that the per-component computation can't have a higher precision than 1/256,
175 // while dot3_rgb((0x80,g0,b0), (0x7F,g1,b1)) and dot3_rgb((0x80,g0,b0), (0x80,g1,b1)) give
176 // different results.
177 int result = ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 +
178 ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 +
179 ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256;
180 result = std::max(0, std::min(255, result));
181 return {(u8)result, (u8)result, (u8)result};
182 }
183 default:
184 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d", (int)op);
185 UNIMPLEMENTED();
186 return {0, 0, 0};
187 }
188};
189
190u8 AlphaCombine(TevStageConfig::Operation op, const std::array<u8, 3>& input) {
191 switch (op) {
192 using Operation = TevStageConfig::Operation;
193 case Operation::Replace:
194 return input[0];
195
196 case Operation::Modulate:
197 return input[0] * input[1] / 255;
198
199 case Operation::Add:
200 return std::min(255, input[0] + input[1]);
201
202 case Operation::AddSigned: {
203 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
204 auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
205 return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
206 }
207
208 case Operation::Lerp:
209 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
210
211 case Operation::Subtract:
212 return std::max(0, (int)input[0] - (int)input[1]);
213
214 case Operation::MultiplyThenAdd:
215 return std::min(255, (input[0] * input[1] + 255 * input[2]) / 255);
216
217 case Operation::AddThenMultiply:
218 return (std::min(255, (input[0] + input[1])) * input[2]) / 255;
219
220 default:
221 LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d", (int)op);
222 UNIMPLEMENTED();
223 return 0;
224 }
225};
226
227} // namespace Rasterizer
228} // namespace Pica
diff --git a/src/video_core/swrasterizer/texturing.h b/src/video_core/swrasterizer/texturing.h
new file mode 100644
index 000000000..24f74a5a3
--- /dev/null
+++ b/src/video_core/swrasterizer/texturing.h
@@ -0,0 +1,28 @@
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 "common/common_types.h"
8#include "common/vector_math.h"
9#include "video_core/regs_texturing.h"
10
11namespace Pica {
12namespace Rasterizer {
13
14int GetWrappedTexCoord(TexturingRegs::TextureConfig::WrapMode mode, int val, unsigned size);
15
16Math::Vec3<u8> GetColorModifier(TexturingRegs::TevStageConfig::ColorModifier factor,
17 const Math::Vec4<u8>& values);
18
19u8 GetAlphaModifier(TexturingRegs::TevStageConfig::AlphaModifier factor,
20 const Math::Vec4<u8>& values);
21
22Math::Vec3<u8> ColorCombine(TexturingRegs::TevStageConfig::Operation op,
23 const Math::Vec3<u8> input[3]);
24
25u8 AlphaCombine(TexturingRegs::TevStageConfig::Operation op, const std::array<u8, 3>& input);
26
27} // namespace Rasterizer
28} // namespace Pica