Merge pull request #16408 from unknownbrackets/jit-wx

softgpu: Fix compile hazard while running
This commit is contained in:
Henrik Rydgård 2022-11-20 21:42:10 +01:00 committed by GitHub
commit fd110ef6a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 109 additions and 69 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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) {

View file

@ -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__)