mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 19:21:55 +01:00
Keep shader trap lock held for the duration of an execution
Avoids constant relocking on the GPFIFO thread (~0.5% of total time)
This commit is contained in:
parent
314a9bccbc
commit
751e3356e1
@ -236,7 +236,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [blockMapping, blockOffset]{ctx.channelCtx.asCtx->gmmu.LookupBlock(engine->programRegion + engine->pipeline.programOffset)};
|
auto[blockMapping, blockOffset]{ctx.channelCtx.asCtx->gmmu.LookupBlock(engine->programRegion + engine->pipeline.programOffset)};
|
||||||
|
|
||||||
// Skip looking up the mirror if it is the same as the one used for the previous update
|
// Skip looking up the mirror if it is the same as the one used for the previous update
|
||||||
if (!mirrorBlock.valid() || !mirrorBlock.contains(blockMapping)) {
|
if (!mirrorBlock.valid() || !mirrorBlock.contains(blockMapping)) {
|
||||||
@ -246,8 +246,13 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
auto newIt{mirrorMap.emplace(blockMapping.data(), std::make_unique<MirrorEntry>(ctx.memory.CreateMirror(blockMapping)))};
|
auto newIt{mirrorMap.emplace(blockMapping.data(), std::make_unique<MirrorEntry>(ctx.memory.CreateMirror(blockMapping)))};
|
||||||
|
|
||||||
// We need to create the trap after allocating the entry so that we have an `invalid` pointer we can pass in
|
// We need to create the trap after allocating the entry so that we have an `invalid` pointer we can pass in
|
||||||
auto trapHandle{ctx.nce.CreateTrap(blockMapping, [](){}, [](){ return true; }, [dirty = &newIt.first->second->dirty, mutex = &trapMutex](){
|
auto trapHandle{ctx.nce.CreateTrap(blockMapping, [mutex = &trapMutex]() {
|
||||||
std::scoped_lock lock{*mutex}; // Don't use lock callback here since we need trapMutex to be always locked on accesses to prevent UAFs
|
std::scoped_lock lock{*mutex};
|
||||||
|
return;
|
||||||
|
}, []() { return true; }, [dirty = &newIt.first->second->dirty, mutex = &trapMutex]() {
|
||||||
|
std::unique_lock lock{*mutex, std::try_to_lock};
|
||||||
|
if (!lock)
|
||||||
|
return false;
|
||||||
*dirty = true;
|
*dirty = true;
|
||||||
return true;
|
return true;
|
||||||
})};
|
})};
|
||||||
@ -264,6 +269,9 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
mirrorBlock = blockMapping;
|
mirrorBlock = blockMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!trapExecutionLock)
|
||||||
|
trapExecutionLock.emplace(trapMutex);
|
||||||
|
|
||||||
// If the mirror entry has been written to, clear its shader binary cache and retrap to catch any future writes
|
// If the mirror entry has been written to, clear its shader binary cache and retrap to catch any future writes
|
||||||
if (entry->dirty) {
|
if (entry->dirty) {
|
||||||
entry->cache.clear();
|
entry->cache.clear();
|
||||||
@ -300,15 +308,20 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
entry->cache.insert({blockMapping.data() + blockOffset, CacheEntry{binary, hash}});
|
entry->cache.insert({blockMapping.data() + blockOffset, CacheEntry{binary, hash}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this needs to be checked every draw irresspective of pipeline dirtiness
|
|
||||||
bool PipelineStageState::Refresh(InterconnectContext &ctx) {
|
bool PipelineStageState::Refresh(InterconnectContext &ctx) {
|
||||||
std::scoped_lock lock{trapMutex};
|
if (!trapExecutionLock)
|
||||||
|
trapExecutionLock.emplace(trapMutex);
|
||||||
|
|
||||||
if (entry && entry->dirty)
|
if (entry && entry->dirty)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PipelineStageState::PurgeCaches() {
|
||||||
|
trapExecutionLock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
PipelineStageState::~PipelineStageState() {
|
PipelineStageState::~PipelineStageState() {
|
||||||
std::scoped_lock lock{trapMutex};
|
std::scoped_lock lock{trapMutex};
|
||||||
//for (const auto &mirror : mirrorMap)
|
//for (const auto &mirror : mirrorMap)
|
||||||
@ -575,6 +588,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
|
|
||||||
void PipelineState::PurgeCaches() {
|
void PipelineState::PurgeCaches() {
|
||||||
pipeline = nullptr;
|
pipeline = nullptr;
|
||||||
|
for (auto &stage : pipelineStages)
|
||||||
|
stage.MarkDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TextureView> PipelineState::GetColorRenderTargetForClear(InterconnectContext &ctx, size_t index) {
|
std::shared_ptr<TextureView> PipelineState::GetColorRenderTargetForClear(InterconnectContext &ctx, size_t index) {
|
||||||
|
@ -55,7 +55,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
void Flush(InterconnectContext &ctx, PackedPipelineState &packedState);
|
void Flush(InterconnectContext &ctx, PackedPipelineState &packedState);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PipelineStageState : dirty::RefreshableManualDirty {
|
class PipelineStageState : dirty::RefreshableManualDirty, dirty::CachedManualDirty {
|
||||||
public:
|
public:
|
||||||
struct EngineRegisters {
|
struct EngineRegisters {
|
||||||
const engine::Pipeline &pipeline;
|
const engine::Pipeline &pipeline;
|
||||||
@ -80,6 +80,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
tsl::robin_map<u8 *, CacheEntry> cache;
|
tsl::robin_map<u8 *, CacheEntry> cache;
|
||||||
std::optional<nce::NCE::TrapHandle> trap;
|
std::optional<nce::NCE::TrapHandle> trap;
|
||||||
bool dirty{};
|
bool dirty{};
|
||||||
|
|
||||||
MirrorEntry(span<u8> alignedMirror) : mirror{alignedMirror} {}
|
MirrorEntry(span<u8> alignedMirror) : mirror{alignedMirror} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,7 +88,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
engine::Pipeline::Shader::Type shaderType;
|
engine::Pipeline::Shader::Type shaderType;
|
||||||
|
|
||||||
tsl::robin_map<u8 *, std::unique_ptr<MirrorEntry>> mirrorMap;
|
tsl::robin_map<u8 *, std::unique_ptr<MirrorEntry>> mirrorMap;
|
||||||
SpinLock trapMutex; //!< Protects accesses from trap handlers to the mirror map
|
std::mutex trapMutex; //!< Protects accesses from trap handlers to the mirror map
|
||||||
|
std::optional<std::scoped_lock<std::mutex>> trapExecutionLock;
|
||||||
MirrorEntry *entry{};
|
MirrorEntry *entry{};
|
||||||
span<u8> mirrorBlock{}; //!< Guest mapped memory block corresponding to `entry`
|
span<u8> mirrorBlock{}; //!< Guest mapped memory block corresponding to `entry`
|
||||||
|
|
||||||
@ -102,6 +104,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
|
|||||||
void Flush(InterconnectContext &ctx);
|
void Flush(InterconnectContext &ctx);
|
||||||
|
|
||||||
bool Refresh(InterconnectContext &ctx);
|
bool Refresh(InterconnectContext &ctx);
|
||||||
|
|
||||||
|
void PurgeCaches();
|
||||||
};
|
};
|
||||||
|
|
||||||
class VertexInputState : dirty::ManualDirty {
|
class VertexInputState : dirty::ManualDirty {
|
||||||
|
Loading…
Reference in New Issue
Block a user