summaryrefslogtreecommitdiff
path: root/src/video_core/swrasterizer/framebuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/swrasterizer/framebuffer.cpp')
-rw-r--r--src/video_core/swrasterizer/framebuffer.cpp259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/video_core/swrasterizer/framebuffer.cpp b/src/video_core/swrasterizer/framebuffer.cpp
new file mode 100644
index 000000000..4b31eda89
--- /dev/null
+++ b/src/video_core/swrasterizer/framebuffer.cpp
@@ -0,0 +1,259 @@
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/vector_math.h"
12#include "core/hw/gpu.h"
13#include "core/memory.h"
14#include "video_core/pica_state.h"
15#include "video_core/regs_framebuffer.h"
16#include "video_core/swrasterizer/framebuffer.h"
17#include "video_core/utils.h"
18
19namespace Pica {
20namespace Rasterizer {
21
22void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
23 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
24 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
25
26 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
27 // NOTE: The framebuffer height register contains the actual FB height minus one.
28 y = framebuffer.height - y;
29
30 const u32 coarse_y = y & ~7;
31 u32 bytes_per_pixel =
32 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
33 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
34 coarse_y * framebuffer.width * bytes_per_pixel;
35 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
36
37 switch (framebuffer.color_format) {
38 case FramebufferRegs::ColorFormat::RGBA8:
39 Color::EncodeRGBA8(color, dst_pixel);
40 break;
41
42 case FramebufferRegs::ColorFormat::RGB8:
43 Color::EncodeRGB8(color, dst_pixel);
44 break;
45
46 case FramebufferRegs::ColorFormat::RGB5A1:
47 Color::EncodeRGB5A1(color, dst_pixel);
48 break;
49
50 case FramebufferRegs::ColorFormat::RGB565:
51 Color::EncodeRGB565(color, dst_pixel);
52 break;
53
54 case FramebufferRegs::ColorFormat::RGBA4:
55 Color::EncodeRGBA4(color, dst_pixel);
56 break;
57
58 default:
59 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
60 framebuffer.color_format.Value());
61 UNIMPLEMENTED();
62 }
63}
64
65const Math::Vec4<u8> GetPixel(int x, int y) {
66 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
67 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
68
69 y = framebuffer.height - y;
70
71 const u32 coarse_y = y & ~7;
72 u32 bytes_per_pixel =
73 GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
74 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
75 coarse_y * framebuffer.width * bytes_per_pixel;
76 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
77
78 switch (framebuffer.color_format) {
79 case FramebufferRegs::ColorFormat::RGBA8:
80 return Color::DecodeRGBA8(src_pixel);
81
82 case FramebufferRegs::ColorFormat::RGB8:
83 return Color::DecodeRGB8(src_pixel);
84
85 case FramebufferRegs::ColorFormat::RGB5A1:
86 return Color::DecodeRGB5A1(src_pixel);
87
88 case FramebufferRegs::ColorFormat::RGB565:
89 return Color::DecodeRGB565(src_pixel);
90
91 case FramebufferRegs::ColorFormat::RGBA4:
92 return Color::DecodeRGBA4(src_pixel);
93
94 default:
95 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x",
96 framebuffer.color_format.Value());
97 UNIMPLEMENTED();
98 }
99
100 return {0, 0, 0, 0};
101}
102
103u32 GetDepth(int x, int y) {
104 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
105 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
106 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
107
108 y = framebuffer.height - y;
109
110 const u32 coarse_y = y & ~7;
111 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
112 u32 stride = framebuffer.width * bytes_per_pixel;
113
114 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
115 u8* src_pixel = depth_buffer + src_offset;
116
117 switch (framebuffer.depth_format) {
118 case FramebufferRegs::DepthFormat::D16:
119 return Color::DecodeD16(src_pixel);
120 case FramebufferRegs::DepthFormat::D24:
121 return Color::DecodeD24(src_pixel);
122 case FramebufferRegs::DepthFormat::D24S8:
123 return Color::DecodeD24S8(src_pixel).x;
124 default:
125 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
126 UNIMPLEMENTED();
127 return 0;
128 }
129}
130
131u8 GetStencil(int x, int y) {
132 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
133 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
134 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
135
136 y = framebuffer.height - y;
137
138 const u32 coarse_y = y & ~7;
139 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
140 u32 stride = framebuffer.width * bytes_per_pixel;
141
142 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
143 u8* src_pixel = depth_buffer + src_offset;
144
145 switch (framebuffer.depth_format) {
146 case FramebufferRegs::DepthFormat::D24S8:
147 return Color::DecodeD24S8(src_pixel).y;
148
149 default:
150 LOG_WARNING(
151 HW_GPU,
152 "GetStencil called for function which doesn't have a stencil component (format %u)",
153 framebuffer.depth_format);
154 return 0;
155 }
156}
157
158void SetDepth(int x, int y, u32 value) {
159 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
160 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
161 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
162
163 y = framebuffer.height - y;
164
165 const u32 coarse_y = y & ~7;
166 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
167 u32 stride = framebuffer.width * bytes_per_pixel;
168
169 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
170 u8* dst_pixel = depth_buffer + dst_offset;
171
172 switch (framebuffer.depth_format) {
173 case FramebufferRegs::DepthFormat::D16:
174 Color::EncodeD16(value, dst_pixel);
175 break;
176
177 case FramebufferRegs::DepthFormat::D24:
178 Color::EncodeD24(value, dst_pixel);
179 break;
180
181 case FramebufferRegs::DepthFormat::D24S8:
182 Color::EncodeD24X8(value, dst_pixel);
183 break;
184
185 default:
186 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
187 UNIMPLEMENTED();
188 break;
189 }
190}
191
192void SetStencil(int x, int y, u8 value) {
193 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
194 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
195 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
196
197 y = framebuffer.height - y;
198
199 const u32 coarse_y = y & ~7;
200 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
201 u32 stride = framebuffer.width * bytes_per_pixel;
202
203 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
204 u8* dst_pixel = depth_buffer + dst_offset;
205
206 switch (framebuffer.depth_format) {
207 case Pica::FramebufferRegs::DepthFormat::D16:
208 case Pica::FramebufferRegs::DepthFormat::D24:
209 // Nothing to do
210 break;
211
212 case Pica::FramebufferRegs::DepthFormat::D24S8:
213 Color::EncodeX24S8(value, dst_pixel);
214 break;
215
216 default:
217 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
218 UNIMPLEMENTED();
219 break;
220 }
221}
222
223u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
224 switch (action) {
225 case FramebufferRegs::StencilAction::Keep:
226 return old_stencil;
227
228 case FramebufferRegs::StencilAction::Zero:
229 return 0;
230
231 case FramebufferRegs::StencilAction::Replace:
232 return ref;
233
234 case FramebufferRegs::StencilAction::Increment:
235 // Saturated increment
236 return std::min<u8>(old_stencil, 254) + 1;
237
238 case FramebufferRegs::StencilAction::Decrement:
239 // Saturated decrement
240 return std::max<u8>(old_stencil, 1) - 1;
241
242 case FramebufferRegs::StencilAction::Invert:
243 return ~old_stencil;
244
245 case FramebufferRegs::StencilAction::IncrementWrap:
246 return old_stencil + 1;
247
248 case FramebufferRegs::StencilAction::DecrementWrap:
249 return old_stencil - 1;
250
251 default:
252 LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
253 UNIMPLEMENTED();
254 return 0;
255 }
256}
257
258} // namespace Rasterizer
259} // namespace Pica