mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #16408 from unknownbrackets/jit-wx
softgpu: Fix compile hazard while running
This commit is contained in:
commit
fd110ef6a9
7 changed files with 109 additions and 69 deletions
|
@ -558,6 +558,9 @@ void BinManager::Flush(const char *reason) {
|
|||
while (cluts_.Size() > 1)
|
||||
cluts_.SkipNext();
|
||||
|
||||
Rasterizer::FlushJit();
|
||||
Sampler::FlushJit();
|
||||
|
||||
queueRange_.x1 = 0x7FFFFFFF;
|
||||
queueRange_.y1 = 0x7FFFFFFF;
|
||||
queueRange_.x2 = 0;
|
||||
|
|
|
@ -36,6 +36,10 @@ void Init() {
|
|||
jitCache = new PixelJitCache();
|
||||
}
|
||||
|
||||
void FlushJit() {
|
||||
jitCache->Flush();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
delete jitCache;
|
||||
jitCache = nullptr;
|
||||
|
@ -771,7 +775,17 @@ std::string PixelJitCache::DescribeCodePtr(const u8 *ptr) {
|
|||
return CodeBlock::DescribeCodePtr(ptr);
|
||||
}
|
||||
|
||||
void PixelJitCache::Flush() {
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
for (const auto &queued : compileQueue_)
|
||||
Compile(queued);
|
||||
compileQueue_.clear();
|
||||
}
|
||||
|
||||
SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function<void()> flushForCompile) {
|
||||
if (!g_Config.bSoftwareRenderingJit)
|
||||
return nullptr;
|
||||
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
|
||||
auto it = cache_.find(id);
|
||||
|
@ -779,24 +793,39 @@ SingleFunc PixelJitCache::GetSingle(const PixelFuncID &id, std::function<void()>
|
|||
return it->second;
|
||||
}
|
||||
|
||||
if (g_Config.bSoftwareRenderingJit) {
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
if (!flushForCompile) {
|
||||
// Can't compile, let's try to do it later when there's an opportunity.
|
||||
compileQueue_.insert(id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// x64 is typically 200-500 bytes, but let's be safe.
|
||||
if (GetSpaceLeft() < 65536) {
|
||||
Clear();
|
||||
}
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
|
||||
for (const auto &queued : compileQueue_)
|
||||
Compile(queued);
|
||||
compileQueue_.clear();
|
||||
|
||||
Compile(id);
|
||||
|
||||
it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PixelJitCache::Compile(const PixelFuncID &id) {
|
||||
// x64 is typically 200-500 bytes, but let's be safe.
|
||||
if (GetSpaceLeft() < 65536) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
#if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP)
|
||||
addresses_[id] = GetCodePointer();
|
||||
SingleFunc func = CompileSingle(id);
|
||||
cache_[id] = func;
|
||||
return func;
|
||||
addresses_[id] = GetCodePointer();
|
||||
SingleFunc func = CompileSingle(id);
|
||||
cache_[id] = func;
|
||||
#endif
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ComputePixelBlendState(PixelBlendState &state, const PixelFuncID &id) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/Software/FuncId.h"
|
||||
#include "GPU/Software/RasterizerRegCache.h"
|
||||
|
@ -40,6 +41,7 @@ typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntAr
|
|||
SingleFunc GetSingleFunc(const PixelFuncID &id, std::function<void()> flushForCompile);
|
||||
|
||||
void Init();
|
||||
void FlushJit();
|
||||
void Shutdown();
|
||||
|
||||
bool CheckDepthTestPassed(GEComparison func, int x, int y, int stride, u16 z);
|
||||
|
@ -64,10 +66,12 @@ public:
|
|||
SingleFunc GetSingle(const PixelFuncID &id, std::function<void()> flushForCompile);
|
||||
SingleFunc GenericSingle(const PixelFuncID &id);
|
||||
void Clear() override;
|
||||
void Flush();
|
||||
|
||||
std::string DescribeCodePtr(const u8 *ptr) override;
|
||||
|
||||
private:
|
||||
void Compile(const PixelFuncID &id);
|
||||
SingleFunc CompileSingle(const PixelFuncID &id);
|
||||
|
||||
RegCache::Reg GetPixelID();
|
||||
|
@ -105,6 +109,7 @@ private:
|
|||
|
||||
std::unordered_map<PixelFuncID, SingleFunc> cache_;
|
||||
std::unordered_map<PixelFuncID, const u8 *> addresses_;
|
||||
std::unordered_set<PixelFuncID> compileQueue_;
|
||||
|
||||
const u8 *constBlendHalf_11_4s_ = nullptr;
|
||||
const u8 *constBlendInvert_11_4s_ = nullptr;
|
||||
|
|
|
@ -150,13 +150,9 @@ void ComputeRasterizerState(RasterizerState *state, std::function<void()> flushF
|
|||
#endif
|
||||
}
|
||||
|
||||
RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexData &v1) {
|
||||
RasterizerState OptimizeFlatRasterizerState(const RasterizerState &origState, const VertexData &v1) {
|
||||
uint8_t alpha = v1.color0 >> 24;
|
||||
|
||||
// TODO: Problematic to potentially execute-protect blocks at runtime.
|
||||
// This might actually be a very slight risk anyway, since it could clear the codespace?
|
||||
if (PlatformIsWXExclusive())
|
||||
return state;
|
||||
RasterizerState state = origState;
|
||||
|
||||
bool changedPixelID = false;
|
||||
bool changedSamplerID = false;
|
||||
|
@ -201,11 +197,18 @@ RasterizerState OptimizeFlatRasterizerState(RasterizerState state, const VertexD
|
|||
}
|
||||
}
|
||||
|
||||
if (changedPixelID)
|
||||
state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, [] {});
|
||||
if (changedPixelID) {
|
||||
state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID, nullptr);
|
||||
// Can't compile during runtime.
|
||||
if (!state.drawPixel)
|
||||
return origState;
|
||||
}
|
||||
if (changedSamplerID) {
|
||||
state.linear = Sampler::GetLinearFunc(state.samplerID, [] {});
|
||||
state.nearest = Sampler::GetNearestFunc(state.samplerID, [] {});
|
||||
state.linear = Sampler::GetLinearFunc(state.samplerID, nullptr);
|
||||
state.nearest = Sampler::GetNearestFunc(state.samplerID, nullptr);
|
||||
// Can't compile during runtime.
|
||||
if (!state.linear || !state.nearest)
|
||||
return origState;
|
||||
|
||||
// Since the definitions are the same, just force this setting using the func pointer.
|
||||
if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR)
|
||||
|
|
|
@ -163,7 +163,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran
|
|||
uint16_t texbufw = state.texbufw[0];
|
||||
|
||||
// We won't flush, since we compile all samplers together.
|
||||
Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, [] {});
|
||||
Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID, nullptr);
|
||||
_dbg_assert_msg_(fetchFunc != nullptr, "Failed to get precompiled fetch func");
|
||||
auto &pixelID = state.pixelID;
|
||||
auto &samplerID = state.samplerID;
|
||||
|
||||
|
|
|
@ -49,6 +49,10 @@ void Init() {
|
|||
jitCache = new SamplerJitCache();
|
||||
}
|
||||
|
||||
void FlushJit() {
|
||||
jitCache->Flush();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
delete jitCache;
|
||||
jitCache = nullptr;
|
||||
|
@ -138,67 +142,56 @@ std::string SamplerJitCache::DescribeCodePtr(const u8 *ptr) {
|
|||
return CodeBlock::DescribeCodePtr(ptr);
|
||||
}
|
||||
|
||||
NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function<void()> flushForCompile) {
|
||||
void SamplerJitCache::Flush() {
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
for (const auto &queued : compileQueue_)
|
||||
Compile(queued);
|
||||
compileQueue_.clear();
|
||||
}
|
||||
|
||||
NearestFunc SamplerJitCache::GetByID(const SamplerID &id, std::function<void()> flushForCompile) {
|
||||
if (!g_Config.bSoftwareRenderingJit)
|
||||
return nullptr;
|
||||
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
|
||||
auto it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (NearestFunc)it->second;
|
||||
return it->second;
|
||||
|
||||
if (g_Config.bSoftwareRenderingJit) {
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
Compile(id);
|
||||
if (!flushForCompile) {
|
||||
// Can't compile, let's try to do it later when there's an opportunity.
|
||||
compileQueue_.insert(id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
|
||||
for (const auto &queued : compileQueue_)
|
||||
Compile(queued);
|
||||
compileQueue_.clear();
|
||||
|
||||
Compile(id);
|
||||
|
||||
// Okay, should be there now.
|
||||
it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (NearestFunc)it->second;
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NearestFunc SamplerJitCache::GetNearest(const SamplerID &id, std::function<void()> flushForCompile) {
|
||||
return (NearestFunc)GetByID(id, flushForCompile);
|
||||
}
|
||||
|
||||
LinearFunc SamplerJitCache::GetLinear(const SamplerID &id, std::function<void()> flushForCompile) {
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
|
||||
auto it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (LinearFunc)it->second;
|
||||
|
||||
if (g_Config.bSoftwareRenderingJit) {
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
Compile(id);
|
||||
}
|
||||
|
||||
// Okay, should be there now.
|
||||
it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (LinearFunc)it->second;
|
||||
return nullptr;
|
||||
return (LinearFunc)GetByID(id, flushForCompile);
|
||||
}
|
||||
|
||||
FetchFunc SamplerJitCache::GetFetch(const SamplerID &id, std::function<void()> flushForCompile) {
|
||||
std::unique_lock<std::mutex> guard(jitCacheLock);
|
||||
|
||||
auto it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (FetchFunc)it->second;
|
||||
|
||||
if (g_Config.bSoftwareRenderingJit) {
|
||||
guard.unlock();
|
||||
flushForCompile();
|
||||
guard.lock();
|
||||
Compile(id);
|
||||
}
|
||||
|
||||
// Okay, should be there now.
|
||||
it = cache_.find(id);
|
||||
if (it != cache_.end())
|
||||
return (FetchFunc)it->second;
|
||||
return nullptr;
|
||||
return (FetchFunc)GetByID(id, flushForCompile);
|
||||
}
|
||||
|
||||
void SamplerJitCache::Compile(const SamplerID &id) {
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "GPU/Math3D.h"
|
||||
#include "GPU/Software/FuncId.h"
|
||||
#include "GPU/Software/RasterizerRegCache.h"
|
||||
|
@ -43,6 +45,7 @@ typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t,
|
|||
LinearFunc GetLinearFunc(SamplerID id, std::function<void()> flushForCompile);
|
||||
|
||||
void Init();
|
||||
void FlushJit();
|
||||
void Shutdown();
|
||||
|
||||
bool DescribeCodePtr(const u8 *ptr, std::string &name);
|
||||
|
@ -56,11 +59,13 @@ public:
|
|||
LinearFunc GetLinear(const SamplerID &id, std::function<void()> flushForCompile);
|
||||
FetchFunc GetFetch(const SamplerID &id, std::function<void()> flushForCompile);
|
||||
void Clear() override;
|
||||
void Flush();
|
||||
|
||||
std::string DescribeCodePtr(const u8 *ptr) override;
|
||||
|
||||
private:
|
||||
void Compile(const SamplerID &id);
|
||||
NearestFunc GetByID(const SamplerID &id, std::function<void()> flushForCompile);
|
||||
FetchFunc CompileFetch(const SamplerID &id);
|
||||
NearestFunc CompileNearest(const SamplerID &id);
|
||||
LinearFunc CompileLinear(const SamplerID &id);
|
||||
|
@ -123,6 +128,7 @@ private:
|
|||
|
||||
std::unordered_map<SamplerID, NearestFunc> cache_;
|
||||
std::unordered_map<SamplerID, const u8 *> addresses_;
|
||||
std::unordered_set<SamplerID> compileQueue_;
|
||||
};
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
|
|
Loading…
Add table
Reference in a new issue