mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Delete the vertex cache option from the code.
This commit is contained in:
parent
7d43a4940d
commit
e4ea4831e9
@ -590,7 +590,6 @@ static const ConfigSetting graphicsSettings[] = {
|
||||
ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, CfgFlag::PER_GAME),
|
||||
ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 0, CfgFlag::PER_GAME), // Number of samples is 1 << iMultiSampleLevel
|
||||
|
||||
ConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, CfgFlag::PER_GAME | CfgFlag::REPORT),
|
||||
ConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, CfgFlag::PER_GAME | CfgFlag::REPORT),
|
||||
ConfigSetting("VertexDecJit", &g_Config.bVertexDecoderJit, &DefaultCodeGen, CfgFlag::DONT_SAVE | CfgFlag::REPORT),
|
||||
|
||||
|
@ -176,7 +176,6 @@ public:
|
||||
float fUITint;
|
||||
float fUISaturation;
|
||||
|
||||
bool bVertexCache;
|
||||
bool bTextureBackoffCache;
|
||||
bool bVertexDecoderJit;
|
||||
bool bFullScreen;
|
||||
|
@ -575,80 +575,6 @@ void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) {
|
||||
gstate_c.Dirty(DIRTY_SHADERBLEND);
|
||||
}
|
||||
|
||||
inline u32 ComputeMiniHashRange(const void *ptr, size_t sz) {
|
||||
// Switch to u32 units, and round up to avoid unaligned accesses.
|
||||
// Probably doesn't matter if we skip the first few bytes in some cases.
|
||||
const u32 *p = (const u32 *)(((uintptr_t)ptr + 3) & ~3);
|
||||
sz >>= 2;
|
||||
|
||||
if (sz > 100) {
|
||||
size_t step = sz / 4;
|
||||
u32 hash = 0;
|
||||
for (size_t i = 0; i < sz; i += step) {
|
||||
hash += XXH3_64bits(p + i, 100);
|
||||
}
|
||||
return hash;
|
||||
} else {
|
||||
return p[0] + p[sz - 1];
|
||||
}
|
||||
}
|
||||
|
||||
u32 DrawEngineCommon::ComputeMiniHash() {
|
||||
u32 fullhash = 0;
|
||||
const int vertexSize = dec_->GetDecVtxFmt().stride;
|
||||
const int indexSize = IndexSize(dec_->VertexType());
|
||||
|
||||
int step;
|
||||
if (numDrawVerts_ < 3) {
|
||||
step = 1;
|
||||
} else if (numDrawVerts_ < 8) {
|
||||
step = 4;
|
||||
} else {
|
||||
step = numDrawVerts_ / 8;
|
||||
}
|
||||
for (int i = 0; i < numDrawVerts_; i += step) {
|
||||
const DeferredVerts &dc = drawVerts_[i];
|
||||
fullhash += ComputeMiniHashRange((const u8 *)dc.verts + vertexSize * dc.indexLowerBound, vertexSize * (dc.indexUpperBound - dc.indexLowerBound));
|
||||
}
|
||||
for (int i = 0; i < numDrawInds_; i += step) {
|
||||
const DeferredInds &di = drawInds_[i];
|
||||
if (di.indexType != 0) {
|
||||
fullhash += ComputeMiniHashRange(di.inds, indexSize * di.vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
return fullhash;
|
||||
}
|
||||
|
||||
// Cheap bit scrambler from https://nullprogram.com/blog/2018/07/31/
|
||||
inline uint32_t lowbias32_r(uint32_t x) {
|
||||
x ^= x >> 16;
|
||||
x *= 0x43021123U;
|
||||
x ^= x >> 15 ^ x >> 30;
|
||||
x *= 0x1d69e2a5U;
|
||||
x ^= x >> 16;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint32_t DrawEngineCommon::ComputeDrawcallsHash() const {
|
||||
uint32_t dcid = 0;
|
||||
for (int i = 0; i < numDrawVerts_; i++) {
|
||||
u32 dhash = dcid;
|
||||
dhash = __rotl(dhash ^ (u32)(uintptr_t)drawVerts_[i].verts, 13);
|
||||
dhash = __rotl(dhash ^ (u32)drawInds_[i].vertexCount, 11);
|
||||
dcid = lowbias32_r(dhash ^ (u32)drawInds_[i].prim);
|
||||
}
|
||||
for (int i = 0; i < numDrawInds_; i++) {
|
||||
const DeferredInds &di = drawInds_[i];
|
||||
u32 dhash = dcid;
|
||||
if (di.indexType) {
|
||||
dhash = __rotl(dhash ^ (u32)(uintptr_t)di.inds, 19);
|
||||
dcid = lowbias32_r(__rotl(dhash ^ (u32)di.indexType, 7));
|
||||
}
|
||||
}
|
||||
return dcid;
|
||||
}
|
||||
|
||||
int DrawEngineCommon::ComputeNumVertsToDecode() const {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < numDrawVerts_; i++) {
|
||||
@ -657,32 +583,6 @@ int DrawEngineCommon::ComputeNumVertsToDecode() const {
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint64_t DrawEngineCommon::ComputeHash() {
|
||||
uint64_t fullhash = 0;
|
||||
const int vertexSize = dec_->GetDecVtxFmt().stride;
|
||||
|
||||
// TODO: Add some caps both for numDrawCalls_ and num verts to check?
|
||||
// It is really very expensive to check all the vertex data so often.
|
||||
for (int i = 0; i < numDrawVerts_; i++) {
|
||||
const DeferredVerts &dv = drawVerts_[i];
|
||||
int indexLowerBound = dv.indexLowerBound, indexUpperBound = dv.indexUpperBound;
|
||||
fullhash += XXH3_64bits((const char *)dv.verts + vertexSize * indexLowerBound, vertexSize * (indexUpperBound - indexLowerBound));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numDrawInds_; i++) {
|
||||
const DeferredInds &di = drawInds_[i];
|
||||
if (di.indexType != 0) {
|
||||
int indexSize = IndexSize(di.indexType << GE_VTYPE_IDX_SHIFT);
|
||||
// Hm, we will miss some indices when combining above, but meh, it should be fine.
|
||||
fullhash += XXH3_64bits((const char *)di.inds, indexSize * di.vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
// this looks utterly broken??
|
||||
// fullhash += XXH3_64bits(&drawCalls_[0].uvScale, sizeof(drawCalls_[0].uvScale) * numDrawCalls_);
|
||||
return fullhash;
|
||||
}
|
||||
|
||||
int DrawEngineCommon::ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t *stall, u32 vertTypeID, bool clockwise, int *bytesRead, bool isTriangle) {
|
||||
const uint32_t *start = cmd;
|
||||
int prevDrawVerts = numDrawVerts_ - 1;
|
||||
|
@ -159,10 +159,6 @@ protected:
|
||||
// Preprocessing for spline/bezier
|
||||
u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize = nullptr);
|
||||
|
||||
// Utility for vertex caching
|
||||
u32 ComputeMiniHash();
|
||||
uint64_t ComputeHash();
|
||||
|
||||
int ComputeNumVertsToDecode() const;
|
||||
|
||||
void ApplyFramebufferRead(FBOTexState *fboTexState);
|
||||
@ -271,7 +267,6 @@ protected:
|
||||
int numDrawInds_ = 0;
|
||||
int vertexCountInDrawCalls_ = 0;
|
||||
|
||||
int decimationCounter_ = 0;
|
||||
int decodeVertsCounter_ = 0;
|
||||
int decodeIndsCounter_ = 0;
|
||||
|
||||
|
@ -53,9 +53,6 @@ const D3D11_PRIMITIVE_TOPOLOGY d3d11prim[8] = {
|
||||
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Need expansion - though we could do it with geom shaders in most cases
|
||||
};
|
||||
|
||||
#define VERTEXCACHE_DECIMATION_INTERVAL 17
|
||||
|
||||
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
|
||||
enum {
|
||||
VERTEX_PUSH_SIZE = 1024 * 1024 * 16,
|
||||
INDEX_PUSH_SIZE = 1024 * 1024 * 4,
|
||||
@ -73,7 +70,6 @@ DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device,
|
||||
: draw_(draw),
|
||||
device_(device),
|
||||
context_(context),
|
||||
vai_(256),
|
||||
inputLayoutMap_(32),
|
||||
blendCache_(32),
|
||||
blendCache1_(32),
|
||||
@ -84,7 +80,6 @@ DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device,
|
||||
decOptions_.expandAllWeightsToFloat = true;
|
||||
decOptions_.expand8BitNormalsToFloat = true;
|
||||
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
// Allocate nicely aligned memory. Maybe graphics drivers will
|
||||
// appreciate it.
|
||||
// All this is a LOT of memory, need to see if we can cut down somehow.
|
||||
@ -111,13 +106,6 @@ void DrawEngineD3D11::InitDeviceObjects() {
|
||||
draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::ClearTrackedVertexArrays() {
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoD3D11 *vai){
|
||||
delete vai;
|
||||
});
|
||||
vai_.Clear();
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::ClearInputLayoutMap() {
|
||||
inputLayoutMap_.Iterate([&](const InputLayoutKey &key, ID3D11InputLayout *il) {
|
||||
if (il)
|
||||
@ -259,69 +247,13 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::MarkUnreliable(VertexArrayInfoD3D11 *vai) {
|
||||
vai->status = VertexArrayInfoD3D11::VAI_UNRELIABLE;
|
||||
if (vai->vbo) {
|
||||
vai->vbo->Release();
|
||||
vai->vbo = nullptr;
|
||||
}
|
||||
if (vai->ebo) {
|
||||
vai->ebo->Release();
|
||||
vai->ebo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::BeginFrame() {
|
||||
pushVerts_->Reset();
|
||||
pushInds_->Reset();
|
||||
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
if (--decimationCounter_ <= 0) {
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const int threshold = gpuStats.numFlips - VAI_KILL_AGE;
|
||||
const int unreliableThreshold = gpuStats.numFlips - VAI_UNRELIABLE_KILL_AGE;
|
||||
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX;
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoD3D11 *vai){
|
||||
bool kill;
|
||||
if (vai->status == VertexArrayInfoD3D11::VAI_UNRELIABLE) {
|
||||
// We limit killing unreliable so we don't rehash too often.
|
||||
kill = vai->lastFrame < unreliableThreshold && --unreliableLeft >= 0;
|
||||
} else {
|
||||
kill = vai->lastFrame < threshold;
|
||||
}
|
||||
if (kill) {
|
||||
delete vai;
|
||||
vai_.Remove(hash);
|
||||
}
|
||||
});
|
||||
vai_.Maintain();
|
||||
|
||||
// Enable if you want to see vertex decoders in the log output. Need a better way.
|
||||
#if 0
|
||||
char buffer[16384];
|
||||
for (std::map<u32, VertexDecoder*>::iterator dec = decoderMap_.begin(); dec != decoderMap_.end(); ++dec) {
|
||||
char *ptr = buffer;
|
||||
ptr += dec->second->ToString(ptr);
|
||||
// *ptr++ = '\n';
|
||||
NOTICE_LOG(G3D, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
}
|
||||
|
||||
VertexArrayInfoD3D11::~VertexArrayInfoD3D11() {
|
||||
if (vbo)
|
||||
vbo->Release();
|
||||
if (ebo)
|
||||
ebo->Release();
|
||||
}
|
||||
|
||||
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
|
||||
void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) {
|
||||
if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {
|
||||
@ -354,175 +286,16 @@ void DrawEngineD3D11::DoFlush() {
|
||||
ID3D11Buffer *vb_ = nullptr;
|
||||
ID3D11Buffer *ib_ = nullptr;
|
||||
|
||||
int vertexCount = 0;
|
||||
int maxIndex = 0;
|
||||
bool useElements = true;
|
||||
|
||||
// Cannot cache vertex data with morph enabled.
|
||||
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
|
||||
// Also avoid caching when software skinning.
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
|
||||
useCache = false;
|
||||
|
||||
if (useCache) {
|
||||
// getUVGenMode can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263
|
||||
u32 dcid = ComputeDrawcallsHash() ^ gstate.getUVGenMode();
|
||||
|
||||
VertexArrayInfoD3D11 *vai;
|
||||
if (!vai_.Get(dcid, &vai)) {
|
||||
vai = new VertexArrayInfoD3D11();
|
||||
vai_.Insert(dcid, vai);
|
||||
}
|
||||
|
||||
switch (vai->status) {
|
||||
case VertexArrayInfoD3D11::VAI_NEW:
|
||||
{
|
||||
// Haven't seen this one before.
|
||||
uint64_t dataHash = ComputeHash();
|
||||
vai->hash = dataHash;
|
||||
vai->minihash = ComputeMiniHash();
|
||||
vai->status = VertexArrayInfoD3D11::VAI_HASHING;
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
DecodeVerts(decoded_); // writes to indexGen
|
||||
DecodeInds();
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0;
|
||||
goto rotateVBO;
|
||||
}
|
||||
|
||||
// Hashing - still gaining confidence about the buffer.
|
||||
// But if we get this far it's likely to be worth creating a vertex buffer.
|
||||
case VertexArrayInfoD3D11::VAI_HASHING:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
if (vai->drawsUntilNextFullHash == 0) {
|
||||
// Let's try to skip a full hash if mini would fail.
|
||||
const u32 newMiniHash = ComputeMiniHash();
|
||||
uint64_t newHash = vai->hash;
|
||||
if (newMiniHash == vai->minihash) {
|
||||
newHash = ComputeHash();
|
||||
}
|
||||
if (newMiniHash != vai->minihash || newHash != vai->hash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
if (vai->numVerts > 64) {
|
||||
// exponential backoff up to 16 draws, then every 24
|
||||
vai->drawsUntilNextFullHash = std::min(24, vai->numFrames);
|
||||
} else {
|
||||
// Lower numbers seem much more likely to change.
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
}
|
||||
// TODO: tweak
|
||||
//if (vai->numFrames > 1000) {
|
||||
// vai->status = VertexArrayInfo::VAI_RELIABLE;
|
||||
//}
|
||||
} else {
|
||||
vai->drawsUntilNextFullHash--;
|
||||
u32 newMiniHash = ComputeMiniHash();
|
||||
if (newMiniHash != vai->minihash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
|
||||
if (vai->vbo == 0) {
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0;
|
||||
useElements = !indexGen.SeenOnlyPurePrims() || prim == GE_PRIM_TRIANGLE_FAN;
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vai->numVerts = indexGen.PureCount();
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching.");
|
||||
|
||||
// TODO: Combine these two into one buffer?
|
||||
u32 size = dec_->GetDecVtxFmt().stride * MaxIndex();
|
||||
D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_VERTEX_BUFFER, 0 };
|
||||
D3D11_SUBRESOURCE_DATA data{ decoded_ };
|
||||
ASSERT_SUCCESS(device_->CreateBuffer(&desc, &data, &vai->vbo));
|
||||
if (useElements) {
|
||||
u32 size = sizeof(short) * indexGen.VertexCount();
|
||||
D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, 0 };
|
||||
D3D11_SUBRESOURCE_DATA data{ decIndex_ };
|
||||
ASSERT_SUCCESS(device_->CreateBuffer(&desc, &data, &vai->ebo));
|
||||
} else {
|
||||
vai->ebo = 0;
|
||||
}
|
||||
} else {
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
useElements = vai->ebo ? true : false;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAI11_FLAG_VERTEXFULLALPHA;
|
||||
}
|
||||
vb_ = vai->vbo;
|
||||
ib_ = vai->ebo;
|
||||
vertexCount = vai->numVerts;
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
break;
|
||||
}
|
||||
|
||||
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
|
||||
case VertexArrayInfoD3D11::VAI_RELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
vb_ = vai->vbo;
|
||||
ib_ = vai->ebo;
|
||||
|
||||
vertexCount = vai->numVerts;
|
||||
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAI11_FLAG_VERTEXFULLALPHA;
|
||||
break;
|
||||
}
|
||||
|
||||
case VertexArrayInfoD3D11::VAI_UNRELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
|
||||
vai->lastFrame = gpuStats.numFlips;
|
||||
} else {
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
rotateVBO:
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
useElements = !indexGen.SeenOnlyPurePrims() || prim == GE_PRIM_TRIANGLE_FAN;
|
||||
vertexCount = indexGen.VertexCount();
|
||||
maxIndex = MaxIndex();
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vertexCount = indexGen.PureCount();
|
||||
}
|
||||
prim = indexGen.Prim();
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
bool useElements = !indexGen.SeenOnlyPurePrims() || prim == GE_PRIM_TRIANGLE_FAN;
|
||||
int vertexCount = indexGen.VertexCount();
|
||||
int maxIndex = MaxIndex();
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vertexCount = indexGen.PureCount();
|
||||
}
|
||||
prim = indexGen.Prim();
|
||||
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
|
@ -38,65 +38,6 @@ class ShaderManagerD3D11;
|
||||
class TextureCacheD3D11;
|
||||
class FramebufferManagerD3D11;
|
||||
|
||||
// States transitions:
|
||||
// On creation: DRAWN_NEW
|
||||
// DRAWN_NEW -> DRAWN_HASHING
|
||||
// DRAWN_HASHING -> DRAWN_RELIABLE
|
||||
// DRAWN_HASHING -> DRAWN_UNRELIABLE
|
||||
// DRAWN_ONCE -> UNRELIABLE
|
||||
// DRAWN_RELIABLE -> DRAWN_SAFE
|
||||
// UNRELIABLE -> death
|
||||
// DRAWN_ONCE -> death
|
||||
// DRAWN_RELIABLE -> death
|
||||
|
||||
enum {
|
||||
VAI11_FLAG_VERTEXFULLALPHA = 1,
|
||||
};
|
||||
|
||||
// Try to keep this POD.
|
||||
class VertexArrayInfoD3D11 {
|
||||
public:
|
||||
VertexArrayInfoD3D11() {
|
||||
status = VAI_NEW;
|
||||
vbo = 0;
|
||||
ebo = 0;
|
||||
prim = GE_PRIM_INVALID;
|
||||
numDraws = 0;
|
||||
numFrames = 0;
|
||||
lastFrame = gpuStats.numFlips;
|
||||
numVerts = 0;
|
||||
drawsUntilNextFullHash = 0;
|
||||
flags = 0;
|
||||
}
|
||||
~VertexArrayInfoD3D11();
|
||||
|
||||
enum Status : uint8_t {
|
||||
VAI_NEW,
|
||||
VAI_HASHING,
|
||||
VAI_RELIABLE, // cache, don't hash
|
||||
VAI_UNRELIABLE, // never cache
|
||||
};
|
||||
|
||||
uint64_t hash;
|
||||
u32 minihash;
|
||||
|
||||
ID3D11Buffer *vbo;
|
||||
ID3D11Buffer *ebo;
|
||||
|
||||
// Precalculated parameter for drawRangeElements
|
||||
u16 numVerts;
|
||||
u16 maxIndex;
|
||||
s8 prim;
|
||||
Status status;
|
||||
|
||||
// ID information
|
||||
int numDraws;
|
||||
int numFrames;
|
||||
int lastFrame; // So that we can forget.
|
||||
u16 drawsUntilNextFullHash;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
class TessellationDataTransferD3D11 : public TessellationDataTransfer {
|
||||
private:
|
||||
ID3D11DeviceContext *context_;
|
||||
@ -155,8 +96,6 @@ public:
|
||||
Flush();
|
||||
}
|
||||
|
||||
void ClearTrackedVertexArrays() override;
|
||||
|
||||
void NotifyConfigChanged() override;
|
||||
|
||||
void ClearInputLayoutMap();
|
||||
@ -171,16 +110,12 @@ private:
|
||||
|
||||
ID3D11InputLayout *SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt);
|
||||
|
||||
void MarkUnreliable(VertexArrayInfoD3D11 *vai);
|
||||
|
||||
Draw::DrawContext *draw_; // Used for framebuffer related things exclusively.
|
||||
ID3D11Device *device_;
|
||||
ID3D11Device1 *device1_;
|
||||
ID3D11DeviceContext *context_;
|
||||
ID3D11DeviceContext1 *context1_;
|
||||
|
||||
PrehashMap<VertexArrayInfoD3D11 *> vai_;
|
||||
|
||||
struct InputLayoutKey {
|
||||
D3D11VertexShader *vshader;
|
||||
u32 decFmtId;
|
||||
|
@ -72,10 +72,6 @@ enum {
|
||||
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
|
||||
};
|
||||
|
||||
#define VERTEXCACHE_DECIMATION_INTERVAL 17
|
||||
|
||||
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
|
||||
|
||||
static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {
|
||||
{ 0, offsetof(TransformedVertex, pos), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||||
{ 0, offsetof(TransformedVertex, uv), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||||
@ -85,13 +81,11 @@ static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {
|
||||
D3DDECL_END()
|
||||
};
|
||||
|
||||
DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vai_(256), vertexDeclMap_(64) {
|
||||
DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vertexDeclMap_(64) {
|
||||
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
|
||||
decOptions_.expandAllWeightsToFloat = true;
|
||||
decOptions_.expand8BitNormalsToFloat = true;
|
||||
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
|
||||
indexGen.Setup(decIndex_);
|
||||
|
||||
InitDeviceObjects();
|
||||
@ -227,80 +221,11 @@ IDirect3DVertexDeclaration9 *DrawEngineDX9::SetupDecFmtForDraw(const DecVtxForma
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineDX9::MarkUnreliable(VertexArrayInfoDX9 *vai) {
|
||||
vai->status = VertexArrayInfoDX9::VAI_UNRELIABLE;
|
||||
if (vai->vbo) {
|
||||
vai->vbo->Release();
|
||||
vai->vbo = nullptr;
|
||||
}
|
||||
if (vai->ebo) {
|
||||
vai->ebo->Release();
|
||||
vai->ebo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineDX9::ClearTrackedVertexArrays() {
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoDX9 *vai) {
|
||||
delete vai;
|
||||
});
|
||||
vai_.Clear();
|
||||
}
|
||||
|
||||
void DrawEngineDX9::DecimateTrackedVertexArrays() {
|
||||
if (--decimationCounter_ <= 0) {
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const int threshold = gpuStats.numFlips - VAI_KILL_AGE;
|
||||
const int unreliableThreshold = gpuStats.numFlips - VAI_UNRELIABLE_KILL_AGE;
|
||||
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX;
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoDX9 *vai) {
|
||||
bool kill;
|
||||
if (vai->status == VertexArrayInfoDX9::VAI_UNRELIABLE) {
|
||||
// We limit killing unreliable so we don't rehash too often.
|
||||
kill = vai->lastFrame < unreliableThreshold && --unreliableLeft >= 0;
|
||||
} else {
|
||||
kill = vai->lastFrame < threshold;
|
||||
}
|
||||
if (kill) {
|
||||
delete vai;
|
||||
vai_.Remove(hash);
|
||||
}
|
||||
});
|
||||
vai_.Maintain();
|
||||
|
||||
// Enable if you want to see vertex decoders in the log output. Need a better way.
|
||||
#if 0
|
||||
char buffer[16384];
|
||||
for (std::map<u32, VertexDecoder*>::iterator dec = decoderMap_.begin(); dec != decoderMap_.end(); ++dec) {
|
||||
char *ptr = buffer;
|
||||
ptr += dec->second->ToString(ptr);
|
||||
// *ptr++ = '\n';
|
||||
NOTICE_LOG(G3D, buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VertexArrayInfoDX9::~VertexArrayInfoDX9() {
|
||||
if (vbo) {
|
||||
vbo->Release();
|
||||
}
|
||||
if (ebo) {
|
||||
ebo->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t SwapRB(uint32_t c) {
|
||||
return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000);
|
||||
}
|
||||
|
||||
void DrawEngineDX9::BeginFrame() {
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
DecimateTrackedVertexArrays();
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
}
|
||||
|
||||
@ -336,166 +261,9 @@ void DrawEngineDX9::DoFlush() {
|
||||
int vertexCount = 0;
|
||||
int maxIndex = 0;
|
||||
bool useElements = true;
|
||||
|
||||
// Cannot cache vertex data with morph enabled.
|
||||
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
|
||||
// Also avoid caching when software skinning.
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK))
|
||||
useCache = false;
|
||||
|
||||
if (useCache) {
|
||||
// getUVGenMode can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263
|
||||
u32 dcid = ComputeDrawcallsHash() ^ gstate.getUVGenMode();
|
||||
VertexArrayInfoDX9 *vai;
|
||||
if (!vai_.Get(dcid, &vai)) {
|
||||
vai = new VertexArrayInfoDX9();
|
||||
vai_.Insert(dcid, vai);
|
||||
}
|
||||
|
||||
switch (vai->status) {
|
||||
case VertexArrayInfoDX9::VAI_NEW:
|
||||
{
|
||||
// Haven't seen this one before.
|
||||
uint64_t dataHash = ComputeHash();
|
||||
vai->hash = dataHash;
|
||||
vai->minihash = ComputeMiniHash();
|
||||
vai->status = VertexArrayInfoDX9::VAI_HASHING;
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
DecodeVerts(decoded_); // writes to indexGen
|
||||
DecodeInds();
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0;
|
||||
|
||||
goto rotateVBO;
|
||||
}
|
||||
|
||||
// Hashing - still gaining confidence about the buffer.
|
||||
// But if we get this far it's likely to be worth creating a vertex buffer.
|
||||
case VertexArrayInfoDX9::VAI_HASHING:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
if (vai->drawsUntilNextFullHash == 0) {
|
||||
// Let's try to skip a full hash if mini would fail.
|
||||
const u32 newMiniHash = ComputeMiniHash();
|
||||
uint64_t newHash = vai->hash;
|
||||
if (newMiniHash == vai->minihash) {
|
||||
newHash = ComputeHash();
|
||||
}
|
||||
if (newMiniHash != vai->minihash || newHash != vai->hash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
if (vai->numVerts > 64) {
|
||||
// exponential backoff up to 16 draws, then every 24
|
||||
vai->drawsUntilNextFullHash = std::min(24, vai->numFrames);
|
||||
} else {
|
||||
// Lower numbers seem much more likely to change.
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
}
|
||||
// TODO: tweak
|
||||
//if (vai->numFrames > 1000) {
|
||||
// vai->status = VertexArrayInfo::VAI_RELIABLE;
|
||||
//}
|
||||
} else {
|
||||
vai->drawsUntilNextFullHash--;
|
||||
u32 newMiniHash = ComputeMiniHash();
|
||||
if (newMiniHash != vai->minihash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
|
||||
if (vai->vbo == 0) {
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0;
|
||||
useElements = !indexGen.SeenOnlyPurePrims();
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vai->numVerts = indexGen.PureCount();
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching.");
|
||||
|
||||
void * pVb;
|
||||
u32 size = dec_->GetDecVtxFmt().stride * MaxIndex();
|
||||
device_->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vai->vbo, NULL);
|
||||
vai->vbo->Lock(0, size, &pVb, 0);
|
||||
memcpy(pVb, decoded_, size);
|
||||
vai->vbo->Unlock();
|
||||
if (useElements) {
|
||||
void * pIb;
|
||||
u32 size = sizeof(short) * indexGen.VertexCount();
|
||||
device_->CreateIndexBuffer(size, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &vai->ebo, NULL);
|
||||
vai->ebo->Lock(0, size, &pIb, 0);
|
||||
memcpy(pIb, decIndex_, size);
|
||||
vai->ebo->Unlock();
|
||||
} else {
|
||||
vai->ebo = 0;
|
||||
}
|
||||
} else {
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
useElements = vai->ebo ? true : false;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAI_FLAG_VERTEXFULLALPHA;
|
||||
}
|
||||
vb_ = vai->vbo;
|
||||
ib_ = vai->ebo;
|
||||
vertexCount = vai->numVerts;
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
break;
|
||||
}
|
||||
|
||||
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
|
||||
case VertexArrayInfoDX9::VAI_RELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
vb_ = vai->vbo;
|
||||
ib_ = vai->ebo;
|
||||
|
||||
vertexCount = vai->numVerts;
|
||||
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAI_FLAG_VERTEXFULLALPHA;
|
||||
break;
|
||||
}
|
||||
|
||||
case VertexArrayInfoDX9::VAI_UNRELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
|
||||
vai->lastFrame = gpuStats.numFlips;
|
||||
} else {
|
||||
{
|
||||
DecodeVerts(decoded_);
|
||||
DecodeInds();
|
||||
rotateVBO:
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
useElements = !indexGen.SeenOnlyPurePrims();
|
||||
vertexCount = indexGen.VertexCount();
|
||||
|
@ -35,65 +35,6 @@ class ShaderManagerDX9;
|
||||
class TextureCacheDX9;
|
||||
class FramebufferManagerDX9;
|
||||
|
||||
// States transitions:
|
||||
// On creation: DRAWN_NEW
|
||||
// DRAWN_NEW -> DRAWN_HASHING
|
||||
// DRAWN_HASHING -> DRAWN_RELIABLE
|
||||
// DRAWN_HASHING -> DRAWN_UNRELIABLE
|
||||
// DRAWN_ONCE -> UNRELIABLE
|
||||
// DRAWN_RELIABLE -> DRAWN_SAFE
|
||||
// UNRELIABLE -> death
|
||||
// DRAWN_ONCE -> death
|
||||
// DRAWN_RELIABLE -> death
|
||||
|
||||
enum {
|
||||
VAI_FLAG_VERTEXFULLALPHA = 1,
|
||||
};
|
||||
|
||||
// Try to keep this POD.
|
||||
class VertexArrayInfoDX9 {
|
||||
public:
|
||||
VertexArrayInfoDX9() {
|
||||
status = VAI_NEW;
|
||||
vbo = 0;
|
||||
ebo = 0;
|
||||
prim = GE_PRIM_INVALID;
|
||||
numDraws = 0;
|
||||
numFrames = 0;
|
||||
lastFrame = gpuStats.numFlips;
|
||||
numVerts = 0;
|
||||
drawsUntilNextFullHash = 0;
|
||||
flags = 0;
|
||||
}
|
||||
~VertexArrayInfoDX9();
|
||||
|
||||
enum Status : uint8_t {
|
||||
VAI_NEW,
|
||||
VAI_HASHING,
|
||||
VAI_RELIABLE, // cache, don't hash
|
||||
VAI_UNRELIABLE, // never cache
|
||||
};
|
||||
|
||||
uint64_t hash;
|
||||
u32 minihash;
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER9 vbo;
|
||||
LPDIRECT3DINDEXBUFFER9 ebo;
|
||||
|
||||
// Precalculated parameter for drawRangeElements
|
||||
u16 numVerts;
|
||||
u16 maxIndex;
|
||||
s8 prim;
|
||||
Status status;
|
||||
|
||||
// ID information
|
||||
int numDraws;
|
||||
int numFrames;
|
||||
int lastFrame; // So that we can forget.
|
||||
u16 drawsUntilNextFullHash;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
class TessellationDataTransferDX9 : public TessellationDataTransfer {
|
||||
public:
|
||||
TessellationDataTransferDX9() {}
|
||||
@ -122,8 +63,6 @@ public:
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
void ClearTrackedVertexArrays() override;
|
||||
|
||||
void BeginFrame();
|
||||
|
||||
// So that this can be inlined
|
||||
@ -148,7 +87,6 @@ public:
|
||||
protected:
|
||||
// Not currently supported.
|
||||
bool UpdateUseHWTessellation(bool enable) const override { return false; }
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
||||
private:
|
||||
void Invalidate(InvalidationCallbackFlags flags);
|
||||
@ -159,12 +97,9 @@ private:
|
||||
|
||||
IDirect3DVertexDeclaration9 *SetupDecFmtForDraw(const DecVtxFormat &decFmt, u32 pspFmt);
|
||||
|
||||
void MarkUnreliable(VertexArrayInfoDX9 *vai);
|
||||
|
||||
LPDIRECT3DDEVICE9 device_ = nullptr;
|
||||
Draw::DrawContext *draw_;
|
||||
|
||||
PrehashMap<VertexArrayInfoDX9 *> vai_;
|
||||
DenseHashMap<u32, IDirect3DVertexDeclaration9 *> vertexDeclMap_;
|
||||
|
||||
// SimpleVertex
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "GPU/GLES/ShaderManagerGLES.h"
|
||||
#include "GPU/GLES/GPU_GLES.h"
|
||||
|
||||
const GLuint glprim[8] = {
|
||||
static const GLuint glprim[8] = {
|
||||
// Points, which are expanded to triangles.
|
||||
GL_TRIANGLES,
|
||||
// Lines and line strips, which are also expanded to triangles.
|
||||
@ -149,8 +149,6 @@ void DrawEngineGLES::ClearInputLayoutMap() {
|
||||
}
|
||||
|
||||
void DrawEngineGLES::BeginFrame() {
|
||||
gpuStats.numTrackedVertexArrays = 0;
|
||||
|
||||
FrameData &frameData = frameData_[render_->GetCurFrame()];
|
||||
render_->BeginPushBuffer(frameData.pushIndex);
|
||||
render_->BeginPushBuffer(frameData.pushVertex);
|
||||
|
@ -78,11 +78,8 @@ struct GPUStatistics {
|
||||
numVertexDecodes = 0;
|
||||
numDrawSyncs = 0;
|
||||
numListSyncs = 0;
|
||||
numCachedDrawCalls = 0;
|
||||
numVertsSubmitted = 0;
|
||||
numCachedVertsDrawn = 0;
|
||||
numUncachedVertsDrawn = 0;
|
||||
numTrackedVertexArrays = 0;
|
||||
numTextureInvalidations = 0;
|
||||
numTextureInvalidationsByFramebuffer = 0;
|
||||
numTexturesHashed = 0;
|
||||
@ -115,14 +112,11 @@ struct GPUStatistics {
|
||||
int numVertexDecodes;
|
||||
int numDrawSyncs;
|
||||
int numListSyncs;
|
||||
int numCachedDrawCalls;
|
||||
int numFlushes;
|
||||
int numBBOXJumps;
|
||||
int numPlaneUpdates;
|
||||
int numVertsSubmitted;
|
||||
int numCachedVertsDrawn;
|
||||
int numUncachedVertsDrawn;
|
||||
int numTrackedVertexArrays;
|
||||
int numTextureInvalidations;
|
||||
int numTextureInvalidationsByFramebuffer;
|
||||
int numTexturesHashed;
|
||||
|
@ -1685,8 +1685,7 @@ size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
|
||||
return snprintf(buffer, size,
|
||||
"DL processing time: %0.2f ms, %d drawsync, %d listsync\n"
|
||||
"Draw: %d (%d dec), flushes %d, clears %d, bbox jumps %d (%d updates)\n"
|
||||
"Cached draws: %d (tracked: %d)\n"
|
||||
"Vertices: %d cached: %d uncached: %d\n"
|
||||
"Vertices: %d drawn: %d\n"
|
||||
"FBOs active: %d (evaluations: %d)\n"
|
||||
"Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
|
||||
"readbacks %d (%d non-block), uploads %d, depal %d\n"
|
||||
@ -1703,10 +1702,7 @@ size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
|
||||
gpuStats.numClears,
|
||||
gpuStats.numBBOXJumps,
|
||||
gpuStats.numPlaneUpdates,
|
||||
gpuStats.numCachedDrawCalls,
|
||||
gpuStats.numTrackedVertexArrays,
|
||||
gpuStats.numVertsSubmitted,
|
||||
gpuStats.numCachedVertsDrawn,
|
||||
gpuStats.numUncachedVertsDrawn,
|
||||
(int)framebufferManager_->NumVFBs(),
|
||||
gpuStats.numFramebufferEvaluations,
|
||||
|
@ -54,20 +54,12 @@
|
||||
|
||||
using namespace PPSSPP_VK;
|
||||
|
||||
enum {
|
||||
VERTEX_CACHE_SIZE = 8192 * 1024
|
||||
};
|
||||
|
||||
#define VERTEXCACHE_DECIMATION_INTERVAL 17
|
||||
|
||||
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
|
||||
|
||||
enum {
|
||||
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
|
||||
};
|
||||
|
||||
DrawEngineVulkan::DrawEngineVulkan(Draw::DrawContext *draw)
|
||||
: draw_(draw), vai_(1024) {
|
||||
: draw_(draw) {
|
||||
decOptions_.expandAllWeightsToFloat = false;
|
||||
decOptions_.expand8BitNormalsToFloat = false;
|
||||
#if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS)
|
||||
@ -117,8 +109,6 @@ void DrawEngineVulkan::InitDeviceObjects() {
|
||||
res = vkCreateSampler(device, &samp, nullptr, &nullSampler_);
|
||||
_dbg_assert_(VK_SUCCESS == res);
|
||||
|
||||
vertexCache_ = new VulkanPushBuffer(vulkan, "pushVertexCache", VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
|
||||
tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan);
|
||||
tessDataTransfer = tessDataTransferVulkan;
|
||||
|
||||
@ -163,18 +153,8 @@ void DrawEngineVulkan::DestroyDeviceObjects() {
|
||||
vulkan->Delete().QueueDeleteSampler(samplerSecondaryLinear_);
|
||||
if (nullSampler_ != VK_NULL_HANDLE)
|
||||
vulkan->Delete().QueueDeleteSampler(nullSampler_);
|
||||
renderManager->DestroyPipelineLayout(pipelineLayout_);
|
||||
if (vertexCache_) {
|
||||
vertexCache_->Destroy(vulkan);
|
||||
delete vertexCache_;
|
||||
vertexCache_ = nullptr;
|
||||
}
|
||||
|
||||
// Need to clear this to get rid of all remaining references to the dead buffers.
|
||||
vai_.Iterate([](uint32_t hash, VertexArrayInfoVulkan *vai) {
|
||||
delete vai;
|
||||
});
|
||||
vai_.Clear();
|
||||
renderManager->DestroyPipelineLayout(pipelineLayout_);
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::DeviceLost() {
|
||||
@ -189,8 +169,6 @@ void DrawEngineVulkan::DeviceRestore(Draw::DrawContext *draw) {
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::BeginFrame() {
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
// pushUBO is the thin3d push pool, don't need to BeginFrame again.
|
||||
@ -200,54 +178,11 @@ void DrawEngineVulkan::BeginFrame() {
|
||||
tessDataTransferVulkan->SetPushPool(pushUBO_);
|
||||
|
||||
DirtyAllUBOs();
|
||||
|
||||
// First reset all buffers, then begin. This is so that Reset can free memory and Begin can allocate it,
|
||||
// if growing the buffer is needed. Doing it this way will reduce fragmentation if more than one buffer
|
||||
// needs to grow in the same frame. The state where many buffers are reset can also be used to
|
||||
// defragment memory.
|
||||
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
|
||||
|
||||
// Wipe the vertex cache if it's grown too large.
|
||||
if (vertexCache_->GetTotalSize() > VERTEX_CACHE_SIZE) {
|
||||
vertexCache_->Destroy(vulkan);
|
||||
delete vertexCache_; // orphans the buffers, they'll get deleted once no longer used by an in-flight frame.
|
||||
vertexCache_ = new VulkanPushBuffer(vulkan, "vertexCacheR", VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoVulkan *vai) {
|
||||
delete vai;
|
||||
});
|
||||
vai_.Clear();
|
||||
}
|
||||
|
||||
vertexCache_->BeginNoReset();
|
||||
|
||||
if (--decimationCounter_ <= 0) {
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
|
||||
const int threshold = gpuStats.numFlips - VAI_KILL_AGE;
|
||||
const int unreliableThreshold = gpuStats.numFlips - VAI_UNRELIABLE_KILL_AGE;
|
||||
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX;
|
||||
vai_.Iterate([&](uint32_t hash, VertexArrayInfoVulkan *vai) {
|
||||
bool kill;
|
||||
if (vai->status == VertexArrayInfoVulkan::VAI_UNRELIABLE) {
|
||||
// We limit killing unreliable so we don't rehash too often.
|
||||
kill = vai->lastFrame < unreliableThreshold && --unreliableLeft >= 0;
|
||||
} else {
|
||||
kill = vai->lastFrame < threshold;
|
||||
}
|
||||
if (kill) {
|
||||
// This is actually quite safe.
|
||||
vai_.Remove(hash);
|
||||
delete vai;
|
||||
}
|
||||
});
|
||||
}
|
||||
vai_.Maintain();
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::EndFrame() {
|
||||
stats_.pushVertexSpaceUsed = (int)pushVertex_->GetUsedThisFrame();
|
||||
stats_.pushIndexSpaceUsed = (int)pushIndex_->GetUsedThisFrame();
|
||||
vertexCache_->End();
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf) {
|
||||
@ -285,12 +220,6 @@ void DrawEngineVulkan::DirtyAllUBOs() {
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
|
||||
}
|
||||
|
||||
void MarkUnreliable(VertexArrayInfoVulkan *vai) {
|
||||
vai->status = VertexArrayInfoVulkan::VAI_UNRELIABLE;
|
||||
// TODO: If we change to a real allocator, free the data here.
|
||||
// For now we just leave it in the pushbuffer.
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::Invalidate(InvalidationCallbackFlags flags) {
|
||||
if (flags & InvalidationCallbackFlags::COMMAND_BUFFER_STATE) {
|
||||
// Nothing here anymore (removed the "frame descriptor set"
|
||||
@ -305,158 +234,6 @@ void DrawEngineVulkan::Invalidate(InvalidationCallbackFlags flags) {
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawEngineVulkan::VertexCacheLookup(int &vertexCount, GEPrimitiveType &prim, VkBuffer &vbuf, uint32_t &vbOffset, VkBuffer &ibuf, uint32_t &ibOffset, bool &useElements, bool forceIndexed) {
|
||||
// getUVGenMode can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263
|
||||
// u32 dcid = (u32)XXH3_64bits(&drawCalls_, sizeof(DeferredDrawCall) * numDrawCalls_) ^ gstate.getUVGenMode();
|
||||
u32 dcid = ComputeDrawcallsHash() ^ gstate.getUVGenMode();
|
||||
|
||||
PROFILE_THIS_SCOPE("vcache");
|
||||
VertexArrayInfoVulkan *vai;
|
||||
if (!vai_.Get(dcid, &vai)) {
|
||||
vai = new VertexArrayInfoVulkan();
|
||||
vai_.Insert(dcid, vai);
|
||||
}
|
||||
|
||||
switch (vai->status) {
|
||||
case VertexArrayInfoVulkan::VAI_NEW:
|
||||
{
|
||||
// Haven't seen this one before. We don't actually upload the vertex data yet.
|
||||
uint64_t dataHash = ComputeHash();
|
||||
vai->hash = dataHash;
|
||||
vai->minihash = ComputeMiniHash();
|
||||
vai->status = VertexArrayInfoVulkan::VAI_HASHING;
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
DecodeInds();
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAIVULKAN_FLAG_VERTEXFULLALPHA : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hashing - still gaining confidence about the buffer.
|
||||
// But if we get this far it's likely to be worth uploading the data.
|
||||
case VertexArrayInfoVulkan::VAI_HASHING:
|
||||
{
|
||||
PROFILE_THIS_SCOPE("vcachehash");
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
if (vai->drawsUntilNextFullHash == 0) {
|
||||
// Let's try to skip a full hash if mini would fail.
|
||||
const u32 newMiniHash = ComputeMiniHash();
|
||||
uint64_t newHash = vai->hash;
|
||||
if (newMiniHash == vai->minihash) {
|
||||
newHash = ComputeHash();
|
||||
}
|
||||
if (newMiniHash != vai->minihash || newHash != vai->hash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
DecodeInds();
|
||||
return true;
|
||||
}
|
||||
if (vai->numVerts > 64) {
|
||||
// exponential backoff up to 16 draws, then every 24
|
||||
vai->drawsUntilNextFullHash = std::min(24, vai->numFrames);
|
||||
} else {
|
||||
// Lower numbers seem much more likely to change.
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
}
|
||||
// TODO: tweak
|
||||
//if (vai->numFrames > 1000) {
|
||||
// vai->status = VertexArrayInfo::VAI_RELIABLE;
|
||||
//}
|
||||
} else {
|
||||
vai->drawsUntilNextFullHash--;
|
||||
u32 newMiniHash = ComputeMiniHash();
|
||||
if (newMiniHash != vai->minihash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
DecodeInds();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vai->vb) {
|
||||
// Directly push to the vertex cache.
|
||||
DecodeVertsToPushBuffer(vertexCache_, &vai->vbOffset, &vai->vb);
|
||||
DecodeInds();
|
||||
_dbg_assert_msg_(gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching.");
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->maxIndex = MaxIndex();
|
||||
vai->flags = gstate_c.vertexFullAlpha ? VAIVULKAN_FLAG_VERTEXFULLALPHA : 0;
|
||||
if (forceIndexed) {
|
||||
vai->prim = indexGen.GeneralPrim();
|
||||
useElements = true;
|
||||
} else {
|
||||
vai->prim = indexGen.Prim();
|
||||
useElements = !indexGen.SeenOnlyPurePrims();
|
||||
if (!useElements && indexGen.PureCount()) {
|
||||
vai->numVerts = indexGen.PureCount();
|
||||
}
|
||||
}
|
||||
|
||||
if (useElements) {
|
||||
u32 size = sizeof(uint16_t) * indexGen.VertexCount();
|
||||
void *dest = vertexCache_->Allocate(size, 4, &vai->ib, &vai->ibOffset);
|
||||
memcpy(dest, decIndex_, size);
|
||||
} else {
|
||||
vai->ib = VK_NULL_HANDLE;
|
||||
vai->ibOffset = 0;
|
||||
}
|
||||
} else {
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
useElements = vai->ib ? true : false;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAIVULKAN_FLAG_VERTEXFULLALPHA;
|
||||
}
|
||||
vbuf = vai->vb;
|
||||
ibuf = vai->ib;
|
||||
vbOffset = vai->vbOffset;
|
||||
ibOffset = vai->ibOffset;
|
||||
vertexCount = vai->numVerts;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
break;
|
||||
}
|
||||
|
||||
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
|
||||
case VertexArrayInfoVulkan::VAI_RELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
gpuStats.numCachedDrawCalls++;
|
||||
gpuStats.numCachedVertsDrawn += vai->numVerts;
|
||||
vbuf = vai->vb;
|
||||
ibuf = vai->ib;
|
||||
vbOffset = vai->vbOffset;
|
||||
ibOffset = vai->ibOffset;
|
||||
vertexCount = vai->numVerts;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAIVULKAN_FLAG_VERTEXFULLALPHA;
|
||||
break;
|
||||
}
|
||||
|
||||
case VertexArrayInfoVulkan::VAI_UNRELIABLE:
|
||||
{
|
||||
vai->numDraws++;
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
DecodeInds();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The inline wrapper in the header checks for numDrawCalls_ == 0
|
||||
void DrawEngineVulkan::DoFlush() {
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
@ -490,32 +267,21 @@ void DrawEngineVulkan::DoFlush() {
|
||||
if (useHWTransform) {
|
||||
int vertexCount = 0;
|
||||
bool useElements = true;
|
||||
|
||||
// Cannot cache vertex data with morph enabled.
|
||||
bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK);
|
||||
// Also avoid caching when software skinning.
|
||||
VkBuffer vbuf = VK_NULL_HANDLE;
|
||||
VkBuffer ibuf = VK_NULL_HANDLE;
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
useCache = false;
|
||||
}
|
||||
bool useIndexGen = true;
|
||||
if (useCache) {
|
||||
useIndexGen = VertexCacheLookup(vertexCount, prim, vbuf, vbOffset, ibuf, ibOffset, useElements, forceIndexed);
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
// If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content.
|
||||
DecodeVerts(decoded_);
|
||||
VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride;
|
||||
u8 *dest = (u8 *)pushVertex_->Allocate(size, 4, &vbuf, &vbOffset);
|
||||
memcpy(dest, decoded_, size);
|
||||
} else {
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
// If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content.
|
||||
DecodeVerts(decoded_);
|
||||
VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride;
|
||||
u8 *dest = (u8 *)pushVertex_->Allocate(size, 4, &vbuf, &vbOffset);
|
||||
memcpy(dest, decoded_, size);
|
||||
} else {
|
||||
// Decode directly into the pushbuffer
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
}
|
||||
DecodeInds();
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
// Decode directly into the pushbuffer
|
||||
DecodeVertsToPushPool(pushVertex_, &vbOffset, &vbuf);
|
||||
}
|
||||
DecodeInds();
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
|
||||
if (useIndexGen) {
|
||||
vertexCount = indexGen.VertexCount();
|
||||
|
@ -70,49 +70,6 @@ struct DrawEngineVulkanStats {
|
||||
int pushIndexSpaceUsed;
|
||||
};
|
||||
|
||||
enum {
|
||||
VAIVULKAN_FLAG_VERTEXFULLALPHA = 1,
|
||||
};
|
||||
|
||||
// Try to keep this POD.
|
||||
class VertexArrayInfoVulkan {
|
||||
public:
|
||||
VertexArrayInfoVulkan() {
|
||||
lastFrame = gpuStats.numFlips;
|
||||
}
|
||||
// No destructor needed - we always fully wipe.
|
||||
|
||||
enum VAIStatus : uint8_t {
|
||||
VAI_NEW,
|
||||
VAI_HASHING,
|
||||
VAI_RELIABLE, // cache, don't hash
|
||||
VAI_UNRELIABLE, // never cache
|
||||
};
|
||||
|
||||
uint64_t hash = 0;
|
||||
u32 minihash = 0;
|
||||
|
||||
// These will probably always be the same, but whatever.
|
||||
VkBuffer vb = VK_NULL_HANDLE;
|
||||
VkBuffer ib = VK_NULL_HANDLE;
|
||||
// Offsets into the cache buffer.
|
||||
uint32_t vbOffset = 0;
|
||||
uint32_t ibOffset = 0;
|
||||
|
||||
// Precalculated parameter for vkDrawIndexed
|
||||
u16 numVerts = 0;
|
||||
u16 maxIndex = 0;
|
||||
s8 prim = GE_PRIM_INVALID;
|
||||
VAIStatus status = VAI_NEW;
|
||||
|
||||
// ID information
|
||||
int numDraws = 0;
|
||||
int numFrames = 0;
|
||||
int lastFrame; // So that we can forget.
|
||||
u16 drawsUntilNextFullHash = 0;
|
||||
u8 flags = 0;
|
||||
};
|
||||
|
||||
class VulkanRenderManager;
|
||||
|
||||
class TessellationDataTransferVulkan : public TessellationDataTransfer {
|
||||
@ -228,8 +185,6 @@ private:
|
||||
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
bool VertexCacheLookup(int &vertexCount, GEPrimitiveType &prim, VkBuffer &vbuf, uint32_t &vbOffset, VkBuffer &ibuf, uint32_t &ibOffset, bool &useElements, bool forceIndexed);
|
||||
|
||||
void DecodeVertsToPushPool(VulkanPushPool *push, uint32_t *bindOffset, VkBuffer *vkbuf);
|
||||
void DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf);
|
||||
|
||||
@ -254,9 +209,6 @@ private:
|
||||
VkSampler samplerSecondaryLinear_ = VK_NULL_HANDLE;
|
||||
VkSampler samplerSecondaryNearest_ = VK_NULL_HANDLE;
|
||||
|
||||
PrehashMap<VertexArrayInfoVulkan *> vai_;
|
||||
VulkanPushBuffer *vertexCache_;
|
||||
|
||||
struct DescriptorSetKey {
|
||||
VkImageView imageView_;
|
||||
VkImageView secondaryImageView_;
|
||||
|
@ -650,8 +650,6 @@ void MainWindow::createMenus()
|
||||
|
||||
gameSettingsMenu->add(new MenuAction(this, SLOT(transformAct()), QT_TR_NOOP("&Hardware transform")))
|
||||
->addEventChecked(&g_Config.bHardwareTransform);
|
||||
gameSettingsMenu->add(new MenuAction(this, SLOT(vertexCacheAct()), QT_TR_NOOP("&Vertex cache")))
|
||||
->addEventChecked(&g_Config.bVertexCache);
|
||||
gameSettingsMenu->addSeparator();
|
||||
gameSettingsMenu->add(new MenuAction(this, SLOT(audioAct()), QT_TR_NOOP("Enable s&ound")))
|
||||
->addEventChecked(&g_Config.bEnableSound);
|
||||
|
@ -157,7 +157,6 @@ private slots:
|
||||
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
|
||||
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
||||
}
|
||||
void vertexCacheAct() { g_Config.bVertexCache = !g_Config.bVertexCache; }
|
||||
void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; }
|
||||
void frameskipTypeAct() { g_Config.iFrameSkipType = !g_Config.iFrameSkipType; }
|
||||
|
||||
|
@ -401,15 +401,6 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
|
||||
CheckBox *skipGPUReadbacks = graphicsSettings->Add(new CheckBox(&g_Config.bSkipGPUReadbacks, gr->T("Skip GPU Readbacks")));
|
||||
skipGPUReadbacks->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
|
||||
CheckBox *vtxCache = graphicsSettings->Add(new CheckBox(&g_Config.bVertexCache, gr->T("Vertex Cache")));
|
||||
vtxCache->OnClick.Add([=](EventParams &e) {
|
||||
settingInfo_->Show(gr->T("VertexCache Tip", "Faster, but may cause temporary flicker"), e.v);
|
||||
return UI::EVENT_CONTINUE;
|
||||
});
|
||||
vtxCache->SetEnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform && g_Config.iGPUBackend != (int)GPUBackend::OPENGL;
|
||||
});
|
||||
|
||||
CheckBox *texBackoff = graphicsSettings->Add(new CheckBox(&g_Config.bTextureBackoffCache, gr->T("Lazy texture caching", "Lazy texture caching (speedup)")));
|
||||
texBackoff->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
texBackoff->OnClick.Add([=](EventParams& e) {
|
||||
|
@ -290,7 +290,6 @@ namespace MainWindow {
|
||||
TranslateMenuItem(menu, ID_TEXTURESCALING_HYBRID_BICUBIC);
|
||||
TranslateMenuItem(menu, ID_TEXTURESCALING_DEPOSTERIZE);
|
||||
TranslateMenuItem(menu, ID_OPTIONS_HARDWARETRANSFORM);
|
||||
TranslateMenuItem(menu, ID_OPTIONS_VERTEXCACHE);
|
||||
TranslateMenuItem(menu, ID_EMULATION_SOUND);
|
||||
TranslateMenuItem(menu, ID_EMULATION_CHEATS, g_Config.bSystemControls ? L"\tCtrl+T" : L"");
|
||||
TranslateMenuItem(menu, ID_EMULATION_CHAT, g_Config.bSystemControls ? L"\tCtrl+C" : L"");
|
||||
@ -859,9 +858,6 @@ namespace MainWindow {
|
||||
SendToggleFullscreen(!g_Config.UseFullScreen());
|
||||
break;
|
||||
|
||||
case ID_OPTIONS_VERTEXCACHE:
|
||||
g_Config.bVertexCache = !g_Config.bVertexCache;
|
||||
break;
|
||||
case ID_OPTIONS_TEXTUREFILTERING_AUTO: g_Config.iTexFiltering = TEX_FILTER_AUTO; break;
|
||||
case ID_OPTIONS_NEARESTFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_NEAREST; break;
|
||||
case ID_OPTIONS_LINEARFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; break;
|
||||
@ -954,7 +950,6 @@ namespace MainWindow {
|
||||
CHECKITEM(ID_DEBUG_SHOWDEBUGSTATISTICS, (DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS);
|
||||
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
|
||||
CHECKITEM(ID_DEBUG_BREAKONLOAD, !g_Config.bAutoRun);
|
||||
CHECKITEM(ID_OPTIONS_VERTEXCACHE, g_Config.bVertexCache);
|
||||
CHECKITEM(ID_OPTIONS_FRAMESKIP_AUTO, g_Config.bAutoFrameSkip);
|
||||
CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != FRAMESKIP_OFF);
|
||||
CHECKITEM(ID_OPTIONS_FRAMESKIPTYPE_COUNT, g_Config.iFrameSkipType == FRAMESKIPTYPE_COUNT);
|
||||
@ -988,13 +983,6 @@ namespace MainWindow {
|
||||
CheckMenuItem(menu, displayrotationitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iInternalScreenRotation ? MF_CHECKED : MF_UNCHECKED));
|
||||
}
|
||||
|
||||
// Disable Vertex Cache when HW T&L is disabled.
|
||||
if (!g_Config.bHardwareTransform) {
|
||||
EnableMenuItem(menu, ID_OPTIONS_VERTEXCACHE, MF_GRAYED);
|
||||
} else {
|
||||
EnableMenuItem(menu, ID_OPTIONS_VERTEXCACHE, MF_ENABLED);
|
||||
}
|
||||
|
||||
static const int zoomitems[11] = {
|
||||
ID_OPTIONS_SCREENAUTO,
|
||||
ID_OPTIONS_SCREEN1X,
|
||||
|
@ -685,7 +685,6 @@ BEGIN
|
||||
MENUITEM "Deposterize", ID_TEXTURESCALING_DEPOSTERIZE
|
||||
END
|
||||
MENUITEM "Hardware Transform", ID_OPTIONS_HARDWARETRANSFORM
|
||||
MENUITEM "Vertex Cache", ID_OPTIONS_VERTEXCACHE
|
||||
MENUITEM "", 0, MFT_SEPARATOR
|
||||
MENUITEM "Enable Sound", ID_EMULATION_SOUND
|
||||
MENUITEM "", 0, MFT_SEPARATOR
|
||||
|
@ -169,7 +169,6 @@
|
||||
#define ID_OPTIONS_CONTROLS 40038
|
||||
#define ID_DEBUG_BREAKONLOAD 40039
|
||||
#define ID_DEBUG_DUMPNEXTFRAME 40040
|
||||
#define ID_OPTIONS_VERTEXCACHE 40041
|
||||
#define ID_OPTIONS_FRAMESKIP 40044
|
||||
#define IDC_MEMCHECK 40045
|
||||
#define ID_FILE_MEMSTICK 40046
|
||||
|
@ -472,7 +472,6 @@ int main(int argc, const char* argv[])
|
||||
g_Config.bHardwareTransform = true;
|
||||
g_Config.iAnisotropyLevel = 0; // When testing mipmapping we really don't want this.
|
||||
g_Config.iMultiSampleLevel = 0;
|
||||
g_Config.bVertexCache = false;
|
||||
g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH;
|
||||
g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
|
||||
g_Config.bEncryptSave = true;
|
||||
|
@ -706,15 +706,6 @@ static void check_variables(CoreParameter &coreParam)
|
||||
g_Config.bSoftwareSkinning = true;
|
||||
}
|
||||
|
||||
var.key = "ppsspp_vertex_cache";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
if (!strcmp(var.value, "disabled"))
|
||||
g_Config.bVertexCache = false;
|
||||
else
|
||||
g_Config.bVertexCache = true;
|
||||
}
|
||||
|
||||
var.key = "ppsspp_lazy_texture_caching";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user