Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fifo: Run/sync with the GPU on command processor register access #7214

Open
wants to merge 1 commit into
base: master
from

Conversation

3 participants
@stenzek
Copy link
Contributor

stenzek commented Jul 5, 2018

In Dolphin, we don't emulate the CPU and GPU in lock-step, for performance reasons. The CPU drives events, with the GPU emulation being one of these events which is fired periodically. This is the behavior in single core mode. Dual-core mode is completely non-deterministic here, and runs whenever Fifo::RunGpu() is called. Thus, I am mainly concerned about single-core mode.

Due to the GPU only being run every 1000 cycles or so, to a game, if it polled the command processor registers (for example, the read pointer, or distance), the GPU would appear to be stalled. Testing would suggest this is what causes FIFO resets/unknown opcodes in games such as F-Zero GX, and Rogue Squadron 3.

To work around this, each time these registers are accessed, we run the GPU for its time quantum. This way, to a game, the GPU is making progress (as it would on the console). While this isn't necessarily accurate to the hardware in terms of cycles executed, we don't really emulate GPU timings anyway, so executing a few extra GPU cycles doesn't really have any impact.

In dual core, it syncs with the GPU thread, and ensures that the GPU thread isn't too far behind. Again, this is not deterministic, but dual core isn't to begin with, and has numerous stability issues as a result.

Long-term, I'm planning on refactoring the FIFO in a way which resembles the current state of deterministic dual core - read from memory on the CPU thread, but process the commands on the GPU thread. This will lead to determinism for command processor behavior (e.g. FIFO breakpoints, hi/low watermark interrupts), except EFB copies to RAM, and BP token interrupts.

However, this is a much more significant task, with far larger chances of regressions, so I pulled this change out to fix RS3, in the meantime, at least. And perhaps new motivation to make full MMU faster ;).

@@ -490,6 +490,21 @@ static int RunGpuOnCpu(int ticks)
return -available_ticks + GPU_TIME_SLOT_SIZE;
}

void SyncGPUForRegisterAccess()
{
if (SConfig::GetInstance().bCPUThread && !s_use_deterministic_gpu_thread)

This comment has been minimized.

Copy link
@stenzek

stenzek Jul 5, 2018

Author Contributor

TODO: Make sure this doesn't break deterministic dual core.

@JMC47

This comment has been minimized.

Copy link
Contributor

JMC47 commented Jul 5, 2018

This gets Rogue Squadron III in-game again on Single Core only.

F-Zero GX no longer throws Unknown Opcodes all the time at boot on Single Core.

Gladius now reaches in-game (SyncGPU Dualcore only) but seems to randomly crash.

Planet 51 and Datel Discs (confirmed fixed in the bigger change mentioned in the text) remain broken with this subset of changes.

@degasus

This comment has been minimized.

Copy link
Member

degasus commented Jul 5, 2018

I honestly doubt that those 1000 cycles trigger a GPU reset. IIRC those GPU resets aren't because of executing the GPU only every 1000 cycles, they appeared because we've started to only execute the GPU if we have more ticks available. I think we need much faster feedback (in terms of eg interrupts), but we don't need it to execute the command buffer that fast.

else
{
// Single core - run the GPU on the CPU thread.
RunGpuOnCpu(GPU_TIME_SLOT_SIZE);

This comment has been minimized.

Copy link
@degasus

degasus Jul 5, 2018

Member

May you test what happens if you use RunGpuOnCpu(0); here?

@stenzek

This comment has been minimized.

Copy link
Contributor Author

stenzek commented Jul 5, 2018

@degasus I'm thinking it's more because the game is polling the CP registers (e.g. distance) and it appears to be stalled, than the GPU being too slow/fast. But I haven't checked the disassembly of said games to say for sure.

{
// Dual core - kick the GPU, wait for completion.
RunGpu();
s_gpu_mainloop.Wait();

This comment has been minimized.

Copy link
@degasus

degasus Jul 5, 2018

Member

This is a bit gross.
RunGpu() shall only be called on queuing new work for the GPU thread, or if you explicitly want the thread to wake up.
Also if the game idles in such an infinity loop, this will run terrible slow.
What do you think about calling WaitForGpuThread() instead, maybe only if SyncGpu is enabled?

But I see how such a hack may improve the stability. This tries to emulate an infinite fast GPU by blocking on the first state lookup. But please drop the RunGpu() command.

@stenzek stenzek force-pushed the stenzek:cp-access-sync branch 2 times, most recently from 3d80308 to 944c53d Jul 13, 2018

@stenzek

This comment has been minimized.

Copy link
Contributor Author

stenzek commented Jul 13, 2018

As noted on IRC, RunGpuOnCpu(0) still breaks RS3. I've dropped RunGpu, however.

@stenzek

This comment has been minimized.

Copy link
Contributor Author

stenzek commented Aug 29, 2018

Closing for now, as I've been working on a larger rewrite to Dolphin's fifo implementation.

@stenzek stenzek closed this Aug 29, 2018

@stenzek stenzek reopened this Jan 4, 2019

@stenzek stenzek force-pushed the stenzek:cp-access-sync branch from 944c53d to 980cb85 Jan 4, 2019

@JMC47

This comment has been minimized.

Copy link
Contributor

JMC47 commented Jan 4, 2019

This allows Rogue Squadron III to reach in-game still (it did randomly hang on me once while loading a level, but not since.)

F-Zero GX's bootup unknown opcode on single core is gone as well. That appears to be the only noticeable changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.