diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp index 0bb14d14..a641b88d 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp @@ -261,6 +261,9 @@ namespace skyline::gpu::interconnect::maxwell3d { auto[blockMapping, blockOffset]{ctx.channelCtx.asCtx->gmmu.LookupBlock(engine->programRegion + engine->pipeline.programOffset)}; + if (!trapExecutionLock) + trapExecutionLock.emplace(trapMutex); + // Skip looking up the mirror if it is the same as the one used for the previous update if (!mirrorBlock.valid() || !mirrorBlock.contains(blockMapping)) { auto mirrorIt{mirrorMap.find(blockMapping.data())}; @@ -272,11 +275,13 @@ namespace skyline::gpu::interconnect::maxwell3d { auto trapHandle{ctx.nce.CreateTrap(blockMapping, [mutex = &trapMutex]() { std::scoped_lock lock{*mutex}; return; - }, []() { return true; }, [dirty = &newIt.first->second->dirty, mutex = &trapMutex]() { + }, []() { return true; }, [entry = newIt.first->second.get(), mutex = &trapMutex]() { std::unique_lock lock{*mutex, std::try_to_lock}; if (!lock) return false; - *dirty = true; + + if (++entry->trapCount <= MirrorEntry::SkipTrapThreshold) + entry->dirty = true; return true; })}; @@ -292,14 +297,18 @@ namespace skyline::gpu::interconnect::maxwell3d { mirrorBlock = blockMapping; } - if (!trapExecutionLock) - trapExecutionLock.emplace(trapMutex); + if (entry->trapCount > MirrorEntry::SkipTrapThreshold && entry->channelSequenceNumber != ctx.channelCtx.channelSequenceNumber) { + entry->channelSequenceNumber = ctx.channelCtx.channelSequenceNumber; + entry->dirty = true; + } // If the mirror entry has been written to, clear its shader binary cache and retrap to catch any future writes if (entry->dirty) { entry->cache.clear(); entry->dirty = false; - ctx.nce.TrapRegions(*entry->trap, true); + + if (entry->trapCount <= MirrorEntry::SkipTrapThreshold) + ctx.nce.TrapRegions(*entry->trap, true); } else if (auto it{entry->cache.find(blockMapping.data() + blockOffset)}; it != entry->cache.end()) { binary = it->second.binary; hash = it->second.hash; @@ -336,7 +345,9 @@ namespace skyline::gpu::interconnect::maxwell3d { if (!trapExecutionLock) trapExecutionLock.emplace(trapMutex); - if (entry && entry->dirty) + if (entry && entry->trapCount > MirrorEntry::SkipTrapThreshold && entry->channelSequenceNumber != ctx.channelCtx.channelSequenceNumber) + return true; + else if (entry && entry->dirty) return true; return false; @@ -627,4 +638,4 @@ namespace skyline::gpu::interconnect::maxwell3d { std::shared_ptr PipelineState::GetDepthRenderTargetForClear(InterconnectContext &ctx) { return depthRenderTarget.UpdateGet(ctx, packedState).view; } -} \ No newline at end of file +} diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h index 0b0f1c15..58987e2a 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h @@ -81,7 +81,11 @@ namespace skyline::gpu::interconnect::maxwell3d { span mirror; tsl::robin_map cache; std::optional trap; - bool dirty{}; + + static constexpr u32 SkipTrapThreshold{20}; //!< Threshold for the number of times a mirror trap needs to be hit before we fallback to always hashing + u32 trapCount{}; //!< The number of times the trap has been hit, used to avoid trapping in cases where the constant retraps would harm performance + size_t channelSequenceNumber{}; //!< For the case where `trapCount > SkipTrapThreshold`, the memory sequence number number used to clear the cache after every access + bool dirty{}; //!< If the trap has been hit and the cache needs to be cleared MirrorEntry(span alignedMirror) : mirror{alignedMirror} {} };