summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/core/hle/service/gsp.cpp49
-rw-r--r--src/core/hw/gpu.cpp342
-rw-r--r--src/core/hw/gpu.h136
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp54
4 files changed, 228 insertions, 353 deletions
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp
index 5baa7a7a2..053c7dd2c 100644
--- a/src/core/hle/service/gsp.cpp
+++ b/src/core/hle/service/gsp.cpp
@@ -139,8 +139,8 @@ void RegisterInterruptRelayQueue(Service::Interface* self) {
139 139
140 Kernel::SetEventLocked(g_event, false); 140 Kernel::SetEventLocked(g_event, false);
141 141
142 // Hack - This function will permanently set the state of the GSP event such that GPU command 142 // Hack - This function will permanently set the state of the GSP event such that GPU command
143 // synchronization barriers always passthrough. Correct solution would be to set this after the 143 // synchronization barriers always passthrough. Correct solution would be to set this after the
144 // GPU as processed all queued up commands, but due to the emulator being single-threaded they 144 // GPU as processed all queued up commands, but due to the emulator being single-threaded they
145 // will always be ready. 145 // will always be ready.
146 Kernel::SetPermanentLock(g_event, true); 146 Kernel::SetPermanentLock(g_event, true);
@@ -153,6 +153,12 @@ void RegisterInterruptRelayQueue(Service::Interface* self) {
153 153
154/// This triggers handling of the GX command written to the command buffer in shared memory. 154/// This triggers handling of the GX command written to the command buffer in shared memory.
155void TriggerCmdReqQueue(Service::Interface* self) { 155void TriggerCmdReqQueue(Service::Interface* self) {
156
157 // Utility function to convert register ID to address
158 auto WriteGPURegister = [](u32 id, u32 data) {
159 GPU::Write<u32>(0x1EF00000 + 4 * id, data);
160 };
161
156 GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id); 162 GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id);
157 u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20)); 163 u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20));
158 164
@@ -164,9 +170,9 @@ void TriggerCmdReqQueue(Service::Interface* self) {
164 break; 170 break;
165 171
166 case GXCommandId::SET_COMMAND_LIST_LAST: 172 case GXCommandId::SET_COMMAND_LIST_LAST:
167 GPU::Write<u32>(GPU::Registers::CommandListAddress, cmd_buff[1] >> 3); 173 WriteGPURegister(GPU::Regs::CommandProcessor + 2, cmd_buff[1] >> 3); // command list data address
168 GPU::Write<u32>(GPU::Registers::CommandListSize, cmd_buff[2] >> 3); 174 WriteGPURegister(GPU::Regs::CommandProcessor, cmd_buff[2] >> 3); // command list address
169 GPU::Write<u32>(GPU::Registers::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this 175 WriteGPURegister(GPU::Regs::CommandProcessor + 4, 1); // TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
170 176
171 // TODO: Move this to GPU 177 // TODO: Move this to GPU
172 // TODO: Not sure what units the size is measured in 178 // TODO: Not sure what units the size is measured in
@@ -174,27 +180,28 @@ void TriggerCmdReqQueue(Service::Interface* self) {
174 break; 180 break;
175 181
176 case GXCommandId::SET_MEMORY_FILL: 182 case GXCommandId::SET_MEMORY_FILL:
177 GPU::Write<u32>(GPU::Registers::MemoryFillStart1, cmd_buff[1] >> 3); 183 WriteGPURegister(GPU::Regs::MemoryFill, cmd_buff[1] >> 3); // Start 1
178 GPU::Write<u32>(GPU::Registers::MemoryFillEnd1, cmd_buff[3] >> 3); 184 WriteGPURegister(GPU::Regs::MemoryFill + 1, cmd_buff[3] >> 3); // End 1
179 GPU::Write<u32>(GPU::Registers::MemoryFillSize1, cmd_buff[3] - cmd_buff[1]); 185 WriteGPURegister(GPU::Regs::MemoryFill + 2, cmd_buff[3] - cmd_buff[1]); // Size 1
180 GPU::Write<u32>(GPU::Registers::MemoryFillValue1, cmd_buff[2]); 186 WriteGPURegister(GPU::Regs::MemoryFill + 3, cmd_buff[2]); // Value 1
181 GPU::Write<u32>(GPU::Registers::MemoryFillStart2, cmd_buff[4] >> 3); 187
182 GPU::Write<u32>(GPU::Registers::MemoryFillEnd2, cmd_buff[6] >> 3); 188 WriteGPURegister(GPU::Regs::MemoryFill + 4, cmd_buff[4] >> 3); // Start 2
183 GPU::Write<u32>(GPU::Registers::MemoryFillSize2, cmd_buff[6] - cmd_buff[4]); 189 WriteGPURegister(GPU::Regs::MemoryFill + 5, cmd_buff[6] >> 3); // End 2
184 GPU::Write<u32>(GPU::Registers::MemoryFillValue2, cmd_buff[5]); 190 WriteGPURegister(GPU::Regs::MemoryFill + 6, cmd_buff[6] - cmd_buff[4]); // Size 2
191 WriteGPURegister(GPU::Regs::MemoryFill + 7, cmd_buff[5]); // Value 2
185 break; 192 break;
186 193
187 // TODO: Check if texture copies are implemented correctly.. 194 // TODO: Check if texture copies are implemented correctly..
188 case GXCommandId::SET_DISPLAY_TRANSFER: 195 case GXCommandId::SET_DISPLAY_TRANSFER:
189 case GXCommandId::SET_TEXTURE_COPY: 196 case GXCommandId::SET_TEXTURE_COPY:
190 GPU::Write<u32>(GPU::Registers::DisplayInputBufferAddr, cmd_buff[1] >> 3); 197 WriteGPURegister(GPU::Regs::DisplayTransfer, cmd_buff[1] >> 3); // input buffer address
191 GPU::Write<u32>(GPU::Registers::DisplayOutputBufferAddr, cmd_buff[2] >> 3); 198 WriteGPURegister(GPU::Regs::DisplayTransfer + 1, cmd_buff[2] >> 3); // output buffer address
192 GPU::Write<u32>(GPU::Registers::DisplayInputBufferSize, cmd_buff[3]); 199 WriteGPURegister(GPU::Regs::DisplayTransfer + 3, cmd_buff[3]); // input buffer size
193 GPU::Write<u32>(GPU::Registers::DisplayOutputBufferSize, cmd_buff[4]); 200 WriteGPURegister(GPU::Regs::DisplayTransfer + 2, cmd_buff[4]); // output buffer size
194 GPU::Write<u32>(GPU::Registers::DisplayTransferFlags, cmd_buff[5]); 201 WriteGPURegister(GPU::Regs::DisplayTransfer + 4, cmd_buff[5]); // transfer flags
195 202
196 // TODO: GPU::Registers::DisplayTriggerTransfer should be ORed with 1 for texture copies? 203 // TODO: Should this only be ORed with 1 for texture copies?
197 GPU::Write<u32>(GPU::Registers::DisplayTriggerTransfer, 1); 204 WriteGPURegister(GPU::Regs::DisplayTransfer + 6, 1); // trigger transfer
198 break; 205 break;
199 206
200 case GXCommandId::SET_COMMAND_LIST_FIRST: 207 case GXCommandId::SET_COMMAND_LIST_FIRST:
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}
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index b66cf4a37..ce524bd02 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -6,54 +6,31 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/register_set.h"
9 10
10namespace GPU { 11namespace GPU {
11 12
12static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second 13static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
13static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame 14static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
14 15
15struct Registers { 16// MMIO region 0x1EFxxxxx
17struct Regs {
16 enum Id : u32 { 18 enum Id : u32 {
17 MemoryFillStart1 = 0x1EF00010, 19 MemoryFill = 0x00004, // + 5,6,7; second block at 8-11
18 MemoryFillEnd1 = 0x1EF00014, 20
19 MemoryFillSize1 = 0x1EF00018, 21 FramebufferTop = 0x00117, // + 11a,11b,11c,11d(?),11e...126
20 MemoryFillValue1 = 0x1EF0001C, 22 FramebufferBottom = 0x00157, // + 15a,15b,15c,15d(?),15e...166
21 MemoryFillStart2 = 0x1EF00020, 23
22 MemoryFillEnd2 = 0x1EF00024, 24 DisplayTransfer = 0x00300, // + 301,302,303,304,305,306
23 MemoryFillSize2 = 0x1EF00028, 25
24 MemoryFillValue2 = 0x1EF0002C, 26 CommandProcessor = 0x00638, // + 63a,63c
25 27
26 FramebufferTopSize = 0x1EF0045C, 28 NumIds = 0x01000
27 FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left
28 FramebufferTopLeft2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left
29 FramebufferTopFormat = 0x1EF00470,
30 FramebufferTopSwapBuffers = 0x1EF00478,
31 FramebufferTopStride = 0x1EF00490, // framebuffer row stride?
32 FramebufferTopRight1 = 0x1EF00494, // Main LCD, first framebuffer for 3D right
33 FramebufferTopRight2 = 0x1EF00498, // Main LCD, second framebuffer for 3D right
34
35 FramebufferSubSize = 0x1EF0055C,
36 FramebufferSubLeft1 = 0x1EF00568, // Sub LCD, first framebuffer
37 FramebufferSubLeft2 = 0x1EF0056C, // Sub LCD, second framebuffer
38 FramebufferSubFormat = 0x1EF00570,
39 FramebufferSubSwapBuffers = 0x1EF00578,
40 FramebufferSubStride = 0x1EF00590, // framebuffer row stride?
41 FramebufferSubRight1 = 0x1EF00594, // Sub LCD, unused first framebuffer
42 FramebufferSubRight2 = 0x1EF00598, // Sub LCD, unused second framebuffer
43
44 DisplayInputBufferAddr = 0x1EF00C00,
45 DisplayOutputBufferAddr = 0x1EF00C04,
46 DisplayOutputBufferSize = 0x1EF00C08,
47 DisplayInputBufferSize = 0x1EF00C0C,
48 DisplayTransferFlags = 0x1EF00C10,
49 // Unknown??
50 DisplayTriggerTransfer = 0x1EF00C18,
51
52 CommandListSize = 0x1EF018E0,
53 CommandListAddress = 0x1EF018E8,
54 ProcessCommandList = 0x1EF018F0,
55 }; 29 };
56 30
31 template<Id id>
32 union Struct;
33
57 enum class FramebufferFormat : u32 { 34 enum class FramebufferFormat : u32 {
58 RGBA8 = 0, 35 RGBA8 = 0,
59 RGB8 = 1, 36 RGB8 = 1,
@@ -62,7 +39,11 @@ struct Registers {
62 RGBA4 = 4, 39 RGBA4 = 4,
63 }; 40 };
64 41
65 struct MemoryFillConfig { 42};
43
44template<>
45union Regs::Struct<Regs::MemoryFill> {
46 struct {
66 u32 address_start; 47 u32 address_start;
67 u32 address_end; // ? 48 u32 address_end; // ?
68 u32 size; 49 u32 size;
@@ -75,21 +56,15 @@ struct Registers {
75 inline u32 GetEndAddress() const { 56 inline u32 GetEndAddress() const {
76 return address_end * 8; 57 return address_end * 8;
77 } 58 }
78 }; 59 } data;
79 60};
80 MemoryFillConfig memory_fill[2]; 61static_assert(sizeof(Regs::Struct<Regs::MemoryFill>) == 0x10, "Structure size and register block length don't match");
81 62
82 // TODO: Move these into the framebuffer struct 63template<>
83 u32 framebuffer_top_left_1; 64union Regs::Struct<Regs::FramebufferTop> {
84 u32 framebuffer_top_left_2; 65 using Format = Regs::FramebufferFormat;
85 u32 framebuffer_top_right_1;
86 u32 framebuffer_top_right_2;
87 u32 framebuffer_sub_left_1;
88 u32 framebuffer_sub_left_2;
89 u32 framebuffer_sub_right_1;
90 u32 framebuffer_sub_right_2;
91 66
92 struct FrameBufferConfig { 67 struct {
93 union { 68 union {
94 u32 size; 69 u32 size;
95 70
@@ -97,22 +72,43 @@ struct Registers {
97 BitField<16, 16, u32> height; 72 BitField<16, 16, u32> height;
98 }; 73 };
99 74
75 u32 pad0[2];
76
77 u32 address_left1;
78 u32 address_left2;
79
100 union { 80 union {
101 u32 format; 81 u32 format;
102 82
103 BitField< 0, 3, FramebufferFormat> color_format; 83 BitField< 0, 3, Format> color_format;
104 }; 84 };
105 85
86 u32 pad1;
87
106 union { 88 union {
107 u32 active_fb; 89 u32 active_fb;
108 90
109 BitField<0, 1, u32> second_fb_active; 91 BitField<0, 1, u32> second_fb_active;
110 }; 92 };
111 93
94 u32 pad2[5];
95
112 u32 stride; 96 u32 stride;
113 }; 97
114 FrameBufferConfig top_framebuffer; 98 u32 address_right1;
115 FrameBufferConfig sub_framebuffer; 99 u32 address_right2;
100 } data;
101};
102template<>
103union Regs::Struct<Regs::FramebufferBottom> {
104 using Type = decltype(Regs::Struct<Regs::FramebufferTop>::data);
105 Type data;
106};
107static_assert(sizeof(Regs::Struct<Regs::FramebufferTop>) == 0x40, "Structure size and register block length don't match");
108
109template<>
110union Regs::Struct<Regs::DisplayTransfer> {
111 using Format = Regs::FramebufferFormat;
116 112
117 struct { 113 struct {
118 u32 input_address; 114 u32 input_address;
@@ -144,21 +140,31 @@ struct Registers {
144 u32 flags; 140 u32 flags;
145 141
146 BitField< 0, 1, u32> flip_data; 142 BitField< 0, 1, u32> flip_data;
147 BitField< 8, 3, FramebufferFormat> input_format; 143 BitField< 8, 3, Format> input_format;
148 BitField<12, 3, FramebufferFormat> output_format; 144 BitField<12, 3, Format> output_format;
149 BitField<16, 1, u32> output_tiled; 145 BitField<16, 1, u32> output_tiled;
150 }; 146 };
151 147
152 u32 unknown; 148 u32 unknown;
153 u32 trigger; 149 u32 trigger;
154 } display_transfer; 150 } data;
151};
152static_assert(sizeof(Regs::Struct<Regs::DisplayTransfer>) == 0x1C, "Structure size and register block length don't match");
155 153
156 u32 command_list_size; 154template<>
157 u32 command_list_address; 155union Regs::Struct<Regs::CommandProcessor> {
158 u32 command_processing_enabled; 156 struct {
157 u32 size;
158 u32 pad0;
159 u32 address;
160 u32 pad1;
161 u32 trigger;
162 } data;
159}; 163};
164static_assert(sizeof(Regs::Struct<Regs::CommandProcessor>) == 0x14, "Structure size and register block length don't match");
165
160 166
161extern Registers g_regs; 167extern RegisterSet<u32, Regs> g_regs;
162 168
163enum { 169enum {
164 TOP_ASPECT_X = 0x5, 170 TOP_ASPECT_X = 0x5,
@@ -208,7 +214,7 @@ enum FramebufferLocation {
208 214
209/** 215/**
210 * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM 216 * Sets whether the framebuffers are in the GSP heap (FCRAM) or VRAM
211 * @param 217 * @param
212 */ 218 */
213void SetFramebufferLocation(const FramebufferLocation mode); 219void SetFramebufferLocation(const FramebufferLocation mode);
214 220
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 047c69185..8d9d61ae8 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -12,8 +12,8 @@
12 12
13/// RendererOpenGL constructor 13/// RendererOpenGL constructor
14RendererOpenGL::RendererOpenGL() { 14RendererOpenGL::RendererOpenGL() {
15 memset(m_fbo, 0, sizeof(m_fbo)); 15 memset(m_fbo, 0, sizeof(m_fbo));
16 memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); 16 memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo));
17 memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); 17 memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers));
18 18
19 m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); 19 m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
@@ -35,7 +35,7 @@ void RendererOpenGL::SwapBuffers() {
35 m_render_window->MakeCurrent(); 35 m_render_window->MakeCurrent();
36 36
37 // EFB->XFB copy 37 // EFB->XFB copy
38 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some 38 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some
39 // register write We're also treating both framebuffers as a single one in OpenGL. 39 // register write We're also treating both framebuffers as a single one in OpenGL.
40 common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); 40 common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height);
41 RenderXFB(framebuffer_size, framebuffer_size); 41 RenderXFB(framebuffer_size, framebuffer_size);
@@ -71,24 +71,26 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) {
71 } 71 }
72} 72}
73 73
74/** 74/**
75 * Renders external framebuffer (XFB) 75 * Renders external framebuffer (XFB)
76 * @param src_rect Source rectangle in XFB to copy 76 * @param src_rect Source rectangle in XFB to copy
77 * @param dst_rect Destination rectangle in output framebuffer to copy to 77 * @param dst_rect Destination rectangle in output framebuffer to copy to
78 */ 78 */
79void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { 79void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) {
80 80
81 const u32 active_fb_top = (GPU::g_regs.top_framebuffer.active_fb == 1) 81 const auto& framebuffer_top = GPU::g_regs.Get<GPU::Regs::FramebufferTop>();
82 ? GPU::g_regs.framebuffer_top_left_2 82 const auto& framebuffer_sub = GPU::g_regs.Get<GPU::Regs::FramebufferBottom>();
83 : GPU::g_regs.framebuffer_top_left_1; 83 const u32 active_fb_top = (framebuffer_top.data.active_fb == 1)
84 const u32 active_fb_sub = (GPU::g_regs.sub_framebuffer.active_fb == 1) 84 ? framebuffer_top.data.address_left2
85 ? GPU::g_regs.framebuffer_sub_left_2 85 : framebuffer_top.data.address_left1;
86 : GPU::g_regs.framebuffer_sub_left_1; 86 const u32 active_fb_sub = (framebuffer_sub.data.active_fb == 1)
87 ? framebuffer_sub.data.address_left2
88 : framebuffer_sub.data.address_left1;
87 89
88 DEBUG_LOG(GPU, "RenderXFB: %x bytes from %x(%xx%x), fmt %x", 90 DEBUG_LOG(GPU, "RenderXFB: %x bytes from %x(%xx%x), fmt %x",
89 GPU::g_regs.top_framebuffer.stride * GPU::g_regs.top_framebuffer.height, 91 framebuffer_top.data.stride * framebuffer_top.data.height,
90 GPU::GetFramebufferAddr(GPU::g_regs.framebuffer_top_left_1), (int)GPU::g_regs.top_framebuffer.width, 92 GPU::GetFramebufferAddr(active_fb_top), (int)framebuffer_top.data.width,
91 (int)GPU::g_regs.top_framebuffer.height, (int)GPU::g_regs.top_framebuffer.format); 93 (int)framebuffer_top.data.height, (int)framebuffer_top.data.format);
92 94
93 // TODO: This should consider the GPU registers for framebuffer width, height and stride. 95 // TODO: This should consider the GPU registers for framebuffer width, height and stride.
94 FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_top), m_xfb_top_flipped); 96 FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_top), m_xfb_top_flipped);
@@ -112,7 +114,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect&
112 glReadBuffer(GL_COLOR_ATTACHMENT0); 114 glReadBuffer(GL_COLOR_ATTACHMENT0);
113 115
114 // Blit 116 // Blit
115 glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, 117 glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_,
116 dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, 118 dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_,
117 GL_COLOR_BUFFER_BIT, GL_LINEAR); 119 GL_COLOR_BUFFER_BIT, GL_LINEAR);
118 120
@@ -138,7 +140,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect&
138 140
139 // Blit 141 // Blit
140 int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; 142 int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2;
141 glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, 143 glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight,
142 offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, 144 offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0,
143 GL_COLOR_BUFFER_BIT, GL_LINEAR); 145 GL_COLOR_BUFFER_BIT, GL_LINEAR);
144 146
@@ -147,7 +149,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect&
147 149
148/// Initialize the FBO 150/// Initialize the FBO
149void RendererOpenGL::InitFramebuffer() { 151void RendererOpenGL::InitFramebuffer() {
150 // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as 152 // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as
151 // separate framebuffers 153 // separate framebuffers
152 154
153 // Init the FBOs 155 // Init the FBOs
@@ -160,12 +162,12 @@ void RendererOpenGL::InitFramebuffer() {
160 for (int i = 0; i < kMaxFramebuffers; i++) { 162 for (int i = 0; i < kMaxFramebuffers; i++) {
161 // Generate color buffer storage 163 // Generate color buffer storage
162 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); 164 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]);
163 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, 165 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth,
164 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); 166 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
165 167
166 // Generate depth buffer storage 168 // Generate depth buffer storage
167 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); 169 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]);
168 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, 170 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth,
169 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); 171 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
170 172
171 // Attach the buffers 173 // Attach the buffers
@@ -181,7 +183,7 @@ void RendererOpenGL::InitFramebuffer() {
181 } else { 183 } else {
182 ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); 184 ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer");
183 exit(1); 185 exit(1);
184 } 186 }
185 } 187 }
186 glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) 188 glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s)
187 189
@@ -189,8 +191,8 @@ void RendererOpenGL::InitFramebuffer() {
189 // ------------------------------- 191 // -------------------------------
190 192
191 // Create XFB textures 193 // Create XFB textures
192 glGenTextures(1, &m_xfb_texture_top); 194 glGenTextures(1, &m_xfb_texture_top);
193 glGenTextures(1, &m_xfb_texture_bottom); 195 glGenTextures(1, &m_xfb_texture_bottom);
194 196
195 // Alocate video memorry for XFB textures 197 // Alocate video memorry for XFB textures
196 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); 198 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top);
@@ -206,13 +208,13 @@ void RendererOpenGL::InitFramebuffer() {
206 // Create the FBO and attach color/depth textures 208 // Create the FBO and attach color/depth textures
207 glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer 209 glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer
208 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); 210 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top);
209 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 211 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
210 m_xfb_texture_top, 0); 212 m_xfb_texture_top, 0);
211 glBindFramebuffer(GL_FRAMEBUFFER, 0); 213 glBindFramebuffer(GL_FRAMEBUFFER, 0);
212 214
213 glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer 215 glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer
214 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); 216 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom);
215 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 217 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
216 m_xfb_texture_bottom, 0); 218 m_xfb_texture_bottom, 0);
217 glBindFramebuffer(GL_FRAMEBUFFER, 0); 219 glBindFramebuffer(GL_FRAMEBUFFER, 0);
218} 220}
@@ -228,7 +230,7 @@ void RendererOpenGL::RenderFramebuffer() {
228 glReadBuffer(GL_COLOR_ATTACHMENT0); 230 glReadBuffer(GL_COLOR_ATTACHMENT0);
229 231
230 // Blit 232 // Blit
231 glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, 233 glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width,
232 m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); 234 m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
233 235
234 // Update the FPS count 236 // Update the FPS count
@@ -244,7 +246,7 @@ void RendererOpenGL::RenderFramebuffer() {
244void RendererOpenGL::UpdateFramerate() { 246void RendererOpenGL::UpdateFramerate() {
245} 247}
246 248
247/** 249/**
248 * Set the emulator window to use for renderer 250 * Set the emulator window to use for renderer
249 * @param window EmuWindow handle to emulator window to use for rendering 251 * @param window EmuWindow handle to emulator window to use for rendering
250 */ 252 */
@@ -278,7 +280,7 @@ void RendererOpenGL::Init() {
278 280
279 GLenum err = glewInit(); 281 GLenum err = glewInit();
280 if (GLEW_OK != err) { 282 if (GLEW_OK != err) {
281 ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", 283 ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...",
282 glewGetErrorString(err)); 284 glewGetErrorString(err));
283 exit(-1); 285 exit(-1);
284 } 286 }