summaryrefslogtreecommitdiff
path: root/src/core/hw/gpu.cpp
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2014-07-16 11:24:09 +0200
committerGravatar Tony Wasserka2014-07-23 00:33:08 +0200
commit75775e9ef41248592cb2c27ae69737e46499e705 (patch)
tree9bff36e351d33fd3dcf40ccfb17e23f4916a23a3 /src/core/hw/gpu.cpp
parentGPU: Make framebuffer code format-aware. (diff)
downloadyuzu-75775e9ef41248592cb2c27ae69737e46499e705.tar.gz
yuzu-75775e9ef41248592cb2c27ae69737e46499e705.tar.xz
yuzu-75775e9ef41248592cb2c27ae69737e46499e705.zip
GPU: Make use of RegisterSet.
Diffstat (limited to 'src/core/hw/gpu.cpp')
-rw-r--r--src/core/hw/gpu.cpp342
1 files changed, 101 insertions, 241 deletions
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 31989f445..372e4f4cc 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -15,38 +15,48 @@
15 15
16namespace GPU { 16namespace GPU {
17 17
18Registers g_regs; 18RegisterSet<u32, Regs> g_regs;
19 19
20u64 g_last_ticks = 0; ///< Last CPU ticks 20u64 g_last_ticks = 0; ///< Last CPU ticks
21 21
22/** 22/**
23 * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM 23 * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
24 * @param 24 * @param
25 */ 25 */
26void SetFramebufferLocation(const FramebufferLocation mode) { 26void SetFramebufferLocation(const FramebufferLocation mode) {
27 switch (mode) { 27 switch (mode) {
28 case FRAMEBUFFER_LOCATION_FCRAM: 28 case FRAMEBUFFER_LOCATION_FCRAM:
29 g_regs.framebuffer_top_left_1 = PADDR_TOP_LEFT_FRAME1; 29 {
30 g_regs.framebuffer_top_left_2 = PADDR_TOP_LEFT_FRAME2; 30 auto& framebuffer_top = g_regs.Get<Regs::FramebufferTop>();
31 g_regs.framebuffer_top_right_1 = PADDR_TOP_RIGHT_FRAME1; 31 auto& framebuffer_sub = g_regs.Get<Regs::FramebufferBottom>();
32 g_regs.framebuffer_top_right_2 = PADDR_TOP_RIGHT_FRAME2; 32
33 g_regs.framebuffer_sub_left_1 = PADDR_SUB_FRAME1; 33 framebuffer_top.data.address_left1 = PADDR_TOP_LEFT_FRAME1;
34 //g_regs.framebuffer_sub_left_2 = unknown; 34 framebuffer_top.data.address_left2 = PADDR_TOP_LEFT_FRAME2;
35 g_regs.framebuffer_sub_right_1 = PADDR_SUB_FRAME2; 35 framebuffer_top.data.address_right1 = PADDR_TOP_RIGHT_FRAME1;
36 //g_regs.framebufferr_sub_right_2 = unknown; 36 framebuffer_top.data.address_right2 = PADDR_TOP_RIGHT_FRAME2;
37 framebuffer_sub.data.address_left1 = PADDR_SUB_FRAME1;
38 //framebuffer_sub.data.address_left2 = unknown;
39 framebuffer_sub.data.address_right1 = PADDR_SUB_FRAME2;
40 //framebuffer_sub.data.address_right2 = unknown;
37 break; 41 break;
42 }
38 43
39 case FRAMEBUFFER_LOCATION_VRAM: 44 case FRAMEBUFFER_LOCATION_VRAM:
40 g_regs.framebuffer_top_left_1 = PADDR_VRAM_TOP_LEFT_FRAME1; 45 {
41 g_regs.framebuffer_top_left_2 = PADDR_VRAM_TOP_LEFT_FRAME2; 46 auto& framebuffer_top = g_regs.Get<Regs::FramebufferTop>();
42 g_regs.framebuffer_top_right_1 = PADDR_VRAM_TOP_RIGHT_FRAME1; 47 auto& framebuffer_sub = g_regs.Get<Regs::FramebufferBottom>();
43 g_regs.framebuffer_top_right_2 = PADDR_VRAM_TOP_RIGHT_FRAME2; 48
44 g_regs.framebuffer_sub_left_1 = PADDR_VRAM_SUB_FRAME1; 49 framebuffer_top.data.address_left1 = PADDR_VRAM_TOP_LEFT_FRAME1;
45 //g_regs.framebuffer_sub_left_2 = unknown; 50 framebuffer_top.data.address_left2 = PADDR_VRAM_TOP_LEFT_FRAME2;
46 g_regs.framebuffer_sub_right_1 = PADDR_VRAM_SUB_FRAME2; 51 framebuffer_top.data.address_right1 = PADDR_VRAM_TOP_RIGHT_FRAME1;
47 //g_regs.framebufferr_sub_right_2 = unknown; 52 framebuffer_top.data.address_right2 = PADDR_VRAM_TOP_RIGHT_FRAME2;
53 framebuffer_sub.data.address_left1 = PADDR_VRAM_SUB_FRAME1;
54 //framebuffer_sub.data.address_left2 = unknown;
55 framebuffer_sub.data.address_right1 = PADDR_VRAM_SUB_FRAME2;
56 //framebuffer_sub.data.address_right2 = unknown;
48 break; 57 break;
49 } 58 }
59 }
50} 60}
51 61
52/** 62/**
@@ -87,219 +97,73 @@ const u8* GetFramebufferPointer(const u32 address) {
87} 97}
88 98
89template <typename T> 99template <typename T>
90inline void Read(T &var, const u32 addr) { 100inline void Read(T &var, const u32 raw_addr) {
91 switch (addr) { 101 u32 addr = raw_addr - 0x1EF00000;
92 case Registers::MemoryFillStart1: 102 int index = addr / 4;
93 case Registers::MemoryFillStart2:
94 var = g_regs.memory_fill[(addr - Registers::MemoryFillStart1) / 0x10].address_start;
95 break;
96
97 case Registers::MemoryFillEnd1:
98 case Registers::MemoryFillEnd2:
99 var = g_regs.memory_fill[(addr - Registers::MemoryFillEnd1) / 0x10].address_end;
100 break;
101
102 case Registers::MemoryFillSize1:
103 case Registers::MemoryFillSize2:
104 var = g_regs.memory_fill[(addr - Registers::MemoryFillSize1) / 0x10].size;
105 break;
106
107 case Registers::MemoryFillValue1:
108 case Registers::MemoryFillValue2:
109 var = g_regs.memory_fill[(addr - Registers::MemoryFillValue1) / 0x10].value;
110 break;
111
112 case Registers::FramebufferTopSize:
113 var = g_regs.top_framebuffer.size;
114 break;
115
116 case Registers::FramebufferTopLeft1:
117 var = g_regs.framebuffer_top_left_1;
118 break;
119
120 case Registers::FramebufferTopLeft2:
121 var = g_regs.framebuffer_top_left_2;
122 break;
123
124 case Registers::FramebufferTopFormat:
125 var = g_regs.top_framebuffer.format;
126 break;
127
128 case Registers::FramebufferTopSwapBuffers:
129 var = g_regs.top_framebuffer.active_fb;
130 break;
131
132 case Registers::FramebufferTopStride:
133 var = g_regs.top_framebuffer.stride;
134 break;
135
136 case Registers::FramebufferTopRight1:
137 var = g_regs.framebuffer_top_right_1;
138 break;
139
140 case Registers::FramebufferTopRight2:
141 var = g_regs.framebuffer_top_right_2;
142 break;
143
144 case Registers::FramebufferSubSize:
145 var = g_regs.sub_framebuffer.size;
146 break;
147
148 case Registers::FramebufferSubLeft1:
149 var = g_regs.framebuffer_sub_left_1;
150 break;
151
152 case Registers::FramebufferSubRight1:
153 var = g_regs.framebuffer_sub_right_1;
154 break;
155
156 case Registers::FramebufferSubFormat:
157 var = g_regs.sub_framebuffer.format;
158 break;
159
160 case Registers::FramebufferSubSwapBuffers:
161 var = g_regs.sub_framebuffer.active_fb;
162 break;
163
164 case Registers::FramebufferSubStride:
165 var = g_regs.sub_framebuffer.stride;
166 break;
167
168 case Registers::FramebufferSubLeft2:
169 var = g_regs.framebuffer_sub_left_2;
170 break;
171
172 case Registers::FramebufferSubRight2:
173 var = g_regs.framebuffer_sub_right_2;
174 break;
175
176 case Registers::DisplayInputBufferAddr:
177 var = g_regs.display_transfer.input_address;
178 break;
179 103
180 case Registers::DisplayOutputBufferAddr: 104 // Reads other than u32 are untested, so I'd rather have them abort than silently fail
181 var = g_regs.display_transfer.output_address; 105 if (index >= Regs::NumIds || !std::is_same<T,u32>::value)
182 break; 106 {
183
184 case Registers::DisplayOutputBufferSize:
185 var = g_regs.display_transfer.output_size;
186 break;
187
188 case Registers::DisplayInputBufferSize:
189 var = g_regs.display_transfer.input_size;
190 break;
191
192 case Registers::DisplayTransferFlags:
193 var = g_regs.display_transfer.flags;
194 break;
195
196 // Not sure if this is supposed to be readable
197 case Registers::DisplayTriggerTransfer:
198 var = g_regs.display_transfer.trigger;
199 break;
200
201 case Registers::CommandListSize:
202 var = g_regs.command_list_size;
203 break;
204
205 case Registers::CommandListAddress:
206 var = g_regs.command_list_address;
207 break;
208
209 case Registers::ProcessCommandList:
210 var = g_regs.command_processing_enabled;
211 break;
212
213 default:
214 ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); 107 ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
215 break; 108 return;
216 } 109 }
110
111 var = g_regs[static_cast<Regs::Id>(addr / 4)];
217} 112}
218 113
219template <typename T> 114template <typename T>
220inline void Write(u32 addr, const T data) { 115inline void Write(u32 addr, const T data) {
221 switch (static_cast<Registers::Id>(addr)) { 116 addr -= 0x1EF00000;
222 case Registers::MemoryFillStart1: 117 int index = addr / 4;
223 case Registers::MemoryFillStart2:
224 g_regs.memory_fill[(addr - Registers::MemoryFillStart1) / 0x10].address_start = data;
225 break;
226 118
227 case Registers::MemoryFillEnd1: 119 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
228 case Registers::MemoryFillEnd2: 120 if (index >= Regs::NumIds || !std::is_same<T,u32>::value)
229 g_regs.memory_fill[(addr - Registers::MemoryFillEnd1) / 0x10].address_end = data; 121 {
230 break; 122 ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
123 return;
124 }
231 125
232 case Registers::MemoryFillSize1: 126 g_regs[static_cast<Regs::Id>(index)] = data;
233 case Registers::MemoryFillSize2: 127
234 g_regs.memory_fill[(addr - Registers::MemoryFillSize1) / 0x10].size = data; 128 switch (static_cast<Regs::Id>(index)) {
235 break;
236 129
237 case Registers::MemoryFillValue1: 130 // Memory fills are triggered once the fill value is written.
238 case Registers::MemoryFillValue2: 131 // NOTE: This is not verified.
132 case Regs::MemoryFill + 3:
133 case Regs::MemoryFill + 7:
239 { 134 {
240 Registers::MemoryFillConfig& config = g_regs.memory_fill[(addr - Registers::MemoryFillValue1) / 0x10]; 135 const auto& config = g_regs.Get<Regs::MemoryFill>(static_cast<Regs::Id>(index - 3));
241 config.value = data;
242 136
243 // TODO: Not sure if this check should be done at GSP level instead 137 // TODO: Not sure if this check should be done at GSP level instead
244 if (config.address_start) { 138 if (config.data.address_start) {
245 // TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all 139 // TODO: Not sure if this algorithm is correct, particularly because it doesn't use the size member at all
246 u32* start = (u32*)Memory::GetPointer(config.GetStartAddress()); 140 u32* start = (u32*)Memory::GetPointer(config.data.GetStartAddress());
247 u32* end = (u32*)Memory::GetPointer(config.GetEndAddress()); 141 u32* end = (u32*)Memory::GetPointer(config.data.GetEndAddress());
248 for (u32* ptr = start; ptr < end; ++ptr) 142 for (u32* ptr = start; ptr < end; ++ptr)
249 *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation 143 *ptr = bswap32(config.data.value); // TODO: This is just a workaround to missing framebuffer format emulation
250 144
251 DEBUG_LOG(GPU, "MemoryFill from %x to %x", config.GetStartAddress(), config.GetEndAddress()); 145 DEBUG_LOG(GPU, "MemoryFill from %x to %x", config.data.GetStartAddress(), config.data.GetEndAddress());
252 } 146 }
253 break; 147 break;
254 } 148 }
255 149
256 // TODO: Framebuffer registers!! 150 case Regs::DisplayTransfer + 6:
257 case Registers::FramebufferTopSwapBuffers: 151 {
258 g_regs.top_framebuffer.active_fb = data; 152 const auto& config = g_regs.Get<Regs::DisplayTransfer>();
259 // TODO: Not sure if this should only be done upon a change! 153 if (config.data.trigger & 1) {
260 break; 154 u8* source_pointer = Memory::GetPointer(config.data.GetPhysicalInputAddress());
261 155 u8* dest_pointer = Memory::GetPointer(config.data.GetPhysicalOutputAddress());
262 case Registers::FramebufferSubSwapBuffers:
263 g_regs.sub_framebuffer.active_fb = data;
264 // TODO: Not sure if this should only be done upon a change!
265 break;
266
267 case Registers::DisplayInputBufferAddr:
268 g_regs.display_transfer.input_address = data;
269 break;
270
271 case Registers::DisplayOutputBufferAddr:
272 g_regs.display_transfer.output_address = data;
273 break;
274
275 case Registers::DisplayOutputBufferSize:
276 g_regs.display_transfer.output_size = data;
277 break;
278
279 case Registers::DisplayInputBufferSize:
280 g_regs.display_transfer.input_size = data;
281 break;
282
283 case Registers::DisplayTransferFlags:
284 g_regs.display_transfer.flags = data;
285 break;
286
287 case Registers::DisplayTriggerTransfer:
288 g_regs.display_transfer.trigger = data;
289 if (g_regs.display_transfer.trigger & 1) {
290 u8* source_pointer = Memory::GetPointer(g_regs.display_transfer.GetPhysicalInputAddress());
291 u8* dest_pointer = Memory::GetPointer(g_regs.display_transfer.GetPhysicalOutputAddress());
292 156
293 for (int y = 0; y < g_regs.display_transfer.output_height; ++y) { 157 for (int y = 0; y < config.data.output_height; ++y) {
294 // TODO: Why does the register seem to hold twice the framebuffer width? 158 // TODO: Why does the register seem to hold twice the framebuffer width?
295 for (int x = 0; x < g_regs.display_transfer.output_width / 2; ++x) { 159 for (int x = 0; x < config.data.output_width / 2; ++x) {
296 int source[4] = { 0, 0, 0, 0}; // rgba; 160 int source[4] = { 0, 0, 0, 0}; // rgba;
297 161
298 switch (g_regs.display_transfer.input_format) { 162 switch (config.data.input_format) {
299 case Registers::FramebufferFormat::RGBA8: 163 case Regs::FramebufferFormat::RGBA8:
300 { 164 {
301 // TODO: Most likely got the component order messed up. 165 // TODO: Most likely got the component order messed up.
302 u8* srcptr = source_pointer + x * 4 + y * g_regs.display_transfer.input_width * 4 / 2; 166 u8* srcptr = source_pointer + x * 4 + y * config.data.input_width * 4 / 2;
303 source[0] = srcptr[0]; // blue 167 source[0] = srcptr[0]; // blue
304 source[1] = srcptr[1]; // green 168 source[1] = srcptr[1]; // green
305 source[2] = srcptr[2]; // red 169 source[2] = srcptr[2]; // red
@@ -308,15 +172,15 @@ inline void Write(u32 addr, const T data) {
308 } 172 }
309 173
310 default: 174 default:
311 ERROR_LOG(GPU, "Unknown source framebuffer format %x", (int)g_regs.display_transfer.input_format.Value()); 175 ERROR_LOG(GPU, "Unknown source framebuffer format %x", config.data.input_format.Value());
312 break; 176 break;
313 } 177 }
314 178
315 switch (g_regs.display_transfer.output_format) { 179 switch (config.data.output_format) {
316 /*case Registers::FramebufferFormat::RGBA8: 180 /*case Regs::FramebufferFormat::RGBA8:
317 { 181 {
318 // TODO: Untested 182 // TODO: Untested
319 u8* dstptr = (u32*)(dest_pointer + x * 4 + y * g_regs.display_transfer.output_width * 4); 183 u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.data.output_width * 4);
320 dstptr[0] = source[0]; 184 dstptr[0] = source[0];
321 dstptr[1] = source[1]; 185 dstptr[1] = source[1];
322 dstptr[2] = source[2]; 186 dstptr[2] = source[2];
@@ -324,9 +188,9 @@ inline void Write(u32 addr, const T data) {
324 break; 188 break;
325 }*/ 189 }*/
326 190
327 case Registers::FramebufferFormat::RGB8: 191 case Regs::FramebufferFormat::RGB8:
328 { 192 {
329 u8* dstptr = dest_pointer + x * 3 + y * g_regs.display_transfer.output_width * 3 / 2; 193 u8* dstptr = dest_pointer + x * 3 + y * config.data.output_width * 3 / 2;
330 dstptr[0] = source[0]; // blue 194 dstptr[0] = source[0]; // blue
331 dstptr[1] = source[1]; // green 195 dstptr[1] = source[1]; // green
332 dstptr[2] = source[2]; // red 196 dstptr[2] = source[2]; // red
@@ -334,40 +198,34 @@ inline void Write(u32 addr, const T data) {
334 } 198 }
335 199
336 default: 200 default:
337 ERROR_LOG(GPU, "Unknown destination framebuffer format %x", static_cast<int>(g_regs.display_transfer.output_format.Value())); 201 ERROR_LOG(GPU, "Unknown destination framebuffer format %x", config.data.output_format.Value());
338 break; 202 break;
339 } 203 }
340 } 204 }
341 } 205 }
342 206
343 DEBUG_LOG(GPU, "DisplayTriggerTransfer: %x bytes from %x(%xx%x)-> %x(%xx%x), dst format %x", 207 DEBUG_LOG(GPU, "DisplayTriggerTransfer: %x bytes from %x(%xx%x)-> %x(%xx%x), dst format %x",
344 g_regs.display_transfer.output_height * g_regs.display_transfer.output_width * 4, 208 config.data.output_height * config.data.output_width * 4,
345 g_regs.display_transfer.GetPhysicalInputAddress(), (int)g_regs.display_transfer.input_width, (int)g_regs.display_transfer.input_height, 209 config.data.GetPhysicalInputAddress(), (int)config.data.input_width, (int)config.data.input_height,
346 g_regs.display_transfer.GetPhysicalOutputAddress(), (int)g_regs.display_transfer.output_width, (int)g_regs.display_transfer.output_height, 210 config.data.GetPhysicalOutputAddress(), (int)config.data.output_width, (int)config.data.output_height,
347 (int)g_regs.display_transfer.output_format.Value()); 211 config.data.output_format.Value());
348 } 212 }
349 break; 213 break;
214 }
350 215
351 case Registers::CommandListSize: 216 case Regs::CommandProcessor + 4:
352 g_regs.command_list_size = data; 217 {
353 break; 218 const auto& config = g_regs.Get<Regs::CommandProcessor>();
354 219 if (config.data.trigger & 1)
355 case Registers::CommandListAddress:
356 g_regs.command_list_address = data;
357 break;
358
359 case Registers::ProcessCommandList:
360 g_regs.command_processing_enabled = data;
361 if (g_regs.command_processing_enabled & 1)
362 { 220 {
363 // u32* buffer = (u32*)Memory::GetPointer(g_regs.command_list_address << 3); 221 // u32* buffer = (u32*)Memory::GetPointer(config.data.address << 3);
364 ERROR_LOG(GPU, "Beginning %x bytes of commands from address %x", g_regs.command_list_size, g_regs.command_list_address << 3); 222 ERROR_LOG(GPU, "Beginning %x bytes of commands from address %x", config.data.size, config.data.address << 3);
365 // TODO: Process command list! 223 // TODO: Process command list!
366 } 224 }
367 break; 225 break;
226 }
368 227
369 default: 228 default:
370 ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
371 break; 229 break;
372 } 230 }
373} 231}
@@ -402,18 +260,20 @@ void Init() {
402// SetFramebufferLocation(FRAMEBUFFER_LOCATION_FCRAM); 260// SetFramebufferLocation(FRAMEBUFFER_LOCATION_FCRAM);
403 SetFramebufferLocation(FRAMEBUFFER_LOCATION_VRAM); 261 SetFramebufferLocation(FRAMEBUFFER_LOCATION_VRAM);
404 262
263 auto& framebuffer_top = g_regs.Get<Regs::FramebufferTop>();
264 auto& framebuffer_sub = g_regs.Get<Regs::FramebufferBottom>();
405 // TODO: Width should be 240 instead? 265 // TODO: Width should be 240 instead?
406 g_regs.top_framebuffer.width = 480; 266 framebuffer_top.data.width = 480;
407 g_regs.top_framebuffer.height = 400; 267 framebuffer_top.data.height = 400;
408 g_regs.top_framebuffer.stride = 480*3; 268 framebuffer_top.data.stride = 480*3;
409 g_regs.top_framebuffer.color_format = Registers::FramebufferFormat::RGB8; 269 framebuffer_top.data.color_format = Regs::FramebufferFormat::RGB8;
410 g_regs.top_framebuffer.active_fb = 0; 270 framebuffer_top.data.active_fb = 0;
411 271
412 g_regs.sub_framebuffer.width = 480; 272 framebuffer_sub.data.width = 480;
413 g_regs.sub_framebuffer.height = 400; 273 framebuffer_sub.data.height = 400;
414 g_regs.sub_framebuffer.stride = 480*3; 274 framebuffer_sub.data.stride = 480*3;
415 g_regs.sub_framebuffer.color_format = Registers::FramebufferFormat::RGB8; 275 framebuffer_sub.data.color_format = Regs::FramebufferFormat::RGB8;
416 g_regs.sub_framebuffer.active_fb = 0; 276 framebuffer_sub.data.active_fb = 0;
417 277
418 NOTICE_LOG(GPU, "initialized OK"); 278 NOTICE_LOG(GPU, "initialized OK");
419} 279}