mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
SoftGPU: Keep a tile's tail off the drawing threads' cache line
A tile's head and busy flag, which the drawing threads write, shared a cache line with its tail, which the emulation thread writes for every item it hands the tile. And a drawing thread waiting for work read every tile's head and tail again and again. Now the tail has a line of its own, and a waiting thread watches one counter that DistributeItems bumps, looking at the tiles only when it changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
061038e0bb
commit
ce83a7d366
2 files changed
+20
-7
No files matched your search
@@ -673,6 +673,7 @@ void BinManager::DistributeItems() {
|
||||
void BinManager::DistributeItems(size_t end) {
|
||||
undistributed_ = 0;
|
||||
|
||||
bool any = false;
|
||||
while (distributePos_ != end) {
|
||||
const size_t index = distributePos_;
|
||||
const BinItem &item = queue_[index];
|
||||
@@ -701,7 +702,10 @@ void BinManager::DistributeItems(size_t end) {
|
||||
}
|
||||
}
|
||||
distributePos_ = index + 1 == QUEUED_PRIMS ? 0 : index + 1;
|
||||
any = true;
|
||||
}
|
||||
if (any)
|
||||
distributed_.store(distributed_.load(std::memory_order_relaxed) + 1, std::memory_order_release);
|
||||
}
|
||||
|
||||
void BinManager::ResetTiles() {
|
||||
@@ -784,17 +788,23 @@ void BinManager::MakeRoom() {
|
||||
// A drawing thread out of work stays a moment for more before its task ends: waking it again costs the
|
||||
// emulation thread a system call (about 15 us under WSL2, where lingering made God of War and Wipeout 4-8%
|
||||
// faster). Not while that thread waits for the drawing to finish.
|
||||
// It looks at the tiles again only when distributed_ says there's new work: reading their heads and tails over
|
||||
// and over took cache lines from the emulation thread, which writes the tails.
|
||||
void BinManager::LingerForWork(int start) {
|
||||
double until = time_now_d() + LINGER_SECONDS;
|
||||
while (!waitingForIdle_.load(std::memory_order_relaxed)) {
|
||||
// Read before the look at the tiles, so work distributed during it isn't missed.
|
||||
const uint32_t seen = distributed_.load(std::memory_order_acquire);
|
||||
if (ProcessTiles(start)) {
|
||||
until = time_now_d() + LINGER_SECONDS;
|
||||
continue;
|
||||
}
|
||||
if (time_now_d() >= until)
|
||||
break;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
std::this_thread::yield();
|
||||
while (distributed_.load(std::memory_order_acquire) == seen && !waitingForIdle_.load(std::memory_order_relaxed)) {
|
||||
if (time_now_d() >= until)
|
||||
return;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -313,10 +313,11 @@ private:
|
||||
int tilesX_ = TILES_X;
|
||||
int tilesY_ = TILES_Y;
|
||||
struct Tile {
|
||||
// Indices into queue_, as a ring: head_ is how many have been drawn, tail_ how many were pushed.
|
||||
std::atomic<uint32_t> head;
|
||||
std::atomic<uint32_t> tail;
|
||||
// Indices into queue_, as a ring: head_ is how many have been drawn, tail_ how many were pushed. The
|
||||
// drawing threads write head and busy, this thread tail, so they're on separate cache lines.
|
||||
alignas(64) std::atomic<uint32_t> head;
|
||||
std::atomic<bool> busy;
|
||||
alignas(64) std::atomic<uint32_t> tail;
|
||||
uint16_t items[QUEUED_PRIMS];
|
||||
};
|
||||
Tile *tiles_ = nullptr;
|
||||
@@ -325,6 +326,8 @@ private:
|
||||
// The tiles given work since the last flush, for the threads to look through.
|
||||
uint16_t activeTiles_[TILES_X * TILES_Y];
|
||||
std::atomic<int> activeCount_{ 0 };
|
||||
// Counts DistributeItems calls that gave the tiles work, for threads waiting for some (LingerForWork).
|
||||
std::atomic<uint32_t> distributed_{ 0 };
|
||||
// The emulation thread is waiting for the drawing threads to finish (LingerForWork).
|
||||
std::atomic<bool> waitingForIdle_{ false };
|
||||
bool tileActive_[TILES_X * TILES_Y]{};
|
||||
|
||||
Reference in new issue
Block a user