summaryrefslogtreecommitdiff
path: root/src/core/hw/gpu.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2014-08-31 00:53:07 -0400
committerGravatar bunnei2014-08-31 00:53:07 -0400
commit76372feb1959c0f53d02c2278ef4a14b794a808d (patch)
tree2c25fd17b90fac39fa1b1de238b7ffc15a01abae /src/core/hw/gpu.cpp
parentMerge pull request #82 from yuriks/addr-types (diff)
parentGPU: Improve frame synchronization, increases compatibility with both homebre... (diff)
downloadyuzu-76372feb1959c0f53d02c2278ef4a14b794a808d.tar.gz
yuzu-76372feb1959c0f53d02c2278ef4a14b794a808d.tar.xz
yuzu-76372feb1959c0f53d02c2278ef4a14b794a808d.zip
Merge pull request #84 from bunnei/fix-hw-synchronization
Fix GPU/HW synchronization
Diffstat (limited to 'src/core/hw/gpu.cpp')
-rw-r--r--src/core/hw/gpu.cpp44
1 files changed, 31 insertions, 13 deletions
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index f1f3e7ab3..8709b8eb7 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -24,6 +24,7 @@ Regs g_regs;
24 24
25u32 g_cur_line = 0; ///< Current vertical screen line 25u32 g_cur_line = 0; ///< Current vertical screen line
26u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line 26u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
27u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
27 28
28template <typename T> 29template <typename T>
29inline void Read(T &var, const u32 raw_addr) { 30inline void Read(T &var, const u32 raw_addr) {
@@ -179,27 +180,44 @@ void Update() {
179 auto& framebuffer_top = g_regs.framebuffer_config[0]; 180 auto& framebuffer_top = g_regs.framebuffer_config[0];
180 u64 current_ticks = Core::g_app_core->GetTicks(); 181 u64 current_ticks = Core::g_app_core->GetTicks();
181 182
182 // Synchronize line... 183 // Update the frame after a certain number of CPU ticks have elapsed. This assumes that the
183 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) { 184 // active frame in memory is always complete to render. There also may be issues with this
184 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); 185 // becoming out-of-synch with GSP synchrinization code (as follows). At this time, this seems to
185 g_cur_line++; 186 // be the most effective solution for both homebrew and retail applications. With retail, this
186 g_last_line_ticks = current_ticks; 187 // could be moved below (and probably would guarantee more accurate synchronization). However,
187 } 188 // primitive homebrew relies on a vertical blank interrupt to happen inevitably (regardless of a
189 // threading reschedule).
188 190
189 // Synchronize frame... 191 if ((current_ticks - g_last_frame_ticks) > GPU::kFrameTicks) {
190 if (g_cur_line >= framebuffer_top.height) {
191 g_cur_line = 0;
192 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
193 VideoCore::g_renderer->SwapBuffers(); 192 VideoCore::g_renderer->SwapBuffers();
194 Kernel::WaitCurrentThread(WAITTYPE_VBLANK); 193 g_last_frame_ticks = current_ticks;
195 HLE::Reschedule(__func__); 194 }
195
196 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical
197 // blank, we need to simulate it. Based on testing, it seems that retail applications work more
198 // accurately when this is signalled between thread switches.
199
200 if (HLE::g_reschedule) {
201
202 // Synchronize line...
203 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) {
204 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
205 g_cur_line++;
206 g_last_line_ticks = current_ticks;
207 }
208
209 // Synchronize frame...
210 if (g_cur_line >= framebuffer_top.height) {
211 g_cur_line = 0;
212 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
213 }
196 } 214 }
197} 215}
198 216
199/// Initialize hardware 217/// Initialize hardware
200void Init() { 218void Init() {
201 g_cur_line = 0; 219 g_cur_line = 0;
202 g_last_line_ticks = Core::g_app_core->GetTicks(); 220 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
203 221
204 auto& framebuffer_top = g_regs.framebuffer_config[0]; 222 auto& framebuffer_top = g_regs.framebuffer_config[0];
205 auto& framebuffer_sub = g_regs.framebuffer_config[1]; 223 auto& framebuffer_sub = g_regs.framebuffer_config[1];