Threaded 2D: share work with the main thread instead of waiting

This commit is contained in:
Sean Maas 2021-05-05 12:12:10 -04:00
parent b49fb0ad84
commit 61687755cc
2 changed files with 41 additions and 22 deletions

View file

@ -27,7 +27,7 @@ Gpu::Gpu(Core *core): core(core)
{ {
// Mark the thread as not drawing to start // Mark the thread as not drawing to start
ready.store(true); ready.store(true);
drawing.store(false); drawing.store(0);
// Prepare tasks to be used with the scheduler // Prepare tasks to be used with the scheduler
gbaScanline240Task = std::bind(&Gpu::gbaScanline240, this); gbaScanline240Task = std::bind(&Gpu::gbaScanline240, this);
@ -110,12 +110,13 @@ void Gpu::gbaScanline240()
{ {
if (thread) if (thread)
{ {
// Wait for the scanline to finish drawing // Wait for the thread to finish the scanline
while (drawing.load()) std::this_thread::yield(); while (drawing.load() != 0)
std::this_thread::yield();
} }
else else
{ {
// Draw visible scanlines // Draw the current scanline
core->gpu2D[0].drawGbaScanline(vCount); core->gpu2D[0].drawGbaScanline(vCount);
} }
@ -206,9 +207,9 @@ void Gpu::gbaScanline308()
} }
} }
// Signal that the next scanline has started // Signal that the next scanline should start drawing
if (vCount < 160 && thread) if (vCount < 160 && thread)
drawing.store(true); drawing.store(1);
// Check if the current scanline matches the V-counter // Check if the current scanline matches the V-counter
if (vCount == (dispStat[1] >> 8)) if (vCount == (dispStat[1] >> 8))
@ -236,12 +237,26 @@ void Gpu::scanline256()
{ {
if (thread) if (thread)
{ {
// Wait for the scanlines to finish drawing // Make sure the thread has started before changing the state
while (drawing.load()) std::this_thread::yield(); while (drawing.load() == 1)
std::this_thread::yield();
switch (drawing.exchange(3))
{
case 2:
// Draw engine B's scanline if it hasn't started yet (and purposely fall through)
core->gpu2D[1].drawScanline(vCount);
case 3:
// Wait for the thread to finish the scanlines
while (drawing.load() != 0)
std::this_thread::yield();
break;
}
} }
else else
{ {
// Draw visible scanlines // Draw the current scanlines
core->gpu2D[0].drawScanline(vCount); core->gpu2D[0].drawScanline(vCount);
core->gpu2D[1].drawScanline(vCount); core->gpu2D[1].drawScanline(vCount);
} }
@ -461,9 +476,9 @@ void Gpu::scanline355()
} }
} }
// Signal that the next scanline has started // Signal that the next scanline should start drawing
if (vCount < 192 && thread) if (vCount < 192 && thread)
drawing.store(true); drawing.store(1);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@ -495,18 +510,18 @@ void Gpu::drawGbaThreaded()
{ {
while (running) while (running)
{ {
// Wait until the next scanline starts // Wait until the next scanline should start
while (!drawing.load()) while (drawing.load() != 1)
{ {
if (!running) return; if (!running) return;
std::this_thread::yield(); std::this_thread::yield();
} }
// Draw the scanline // Draw the current scanline
core->gpu2D[0].drawGbaScanline(vCount); core->gpu2D[0].drawGbaScanline(vCount);
// Signal that the scanline is finished // Signal that the scanline is finished
drawing.store(false); drawing.store(0);
} }
} }
@ -514,19 +529,23 @@ void Gpu::drawThreaded()
{ {
while (running) while (running)
{ {
// Wait until the next scanline starts // Wait until the next scanline should start
while (!drawing.load()) while (drawing.load() != 1)
{ {
if (!running) return; if (!running) return;
std::this_thread::yield(); std::this_thread::yield();
} }
// Draw the scanlines // Draw engine A's scanline
drawing.store(2);
core->gpu2D[0].drawScanline(vCount); core->gpu2D[0].drawScanline(vCount);
core->gpu2D[1].drawScanline(vCount);
// Signal that the scanline is finished // Draw engine B's scanline if it hasn't started yet
drawing.store(false); if (drawing.exchange(3) == 2)
core->gpu2D[1].drawScanline(vCount);
// Signal that the scanlines are finished
drawing.store(0);
} }
} }

View file

@ -60,7 +60,7 @@ class Gpu
std::mutex mutex; std::mutex mutex;
bool running = false; bool running = false;
std::atomic<bool> drawing; std::atomic<int> drawing;
std::thread *thread = nullptr; std::thread *thread = nullptr;
bool displayCapture = false; bool displayCapture = false;