mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Pipeline checker: Add support for checking for identical pipelines with different vertex formats
This turned out not to be very fruitful.
This commit is contained in:
@@ -999,7 +999,7 @@ bool DrawEngineCommon::DescribeCodePtr(const u8 *ptr, std::string &name) const {
|
||||
|
||||
if (found) {
|
||||
char temp[256];
|
||||
found->ToString(temp, false);
|
||||
found->ToString(temp, sizeof(temp), false);
|
||||
name = temp;
|
||||
snprintf(temp, sizeof(temp), "_%08X", foundKey);
|
||||
name += temp;
|
||||
|
||||
@@ -259,7 +259,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
// Reset the code ptr and return zero to indicate that we failed.
|
||||
ResetCodePtr(GetOffset(start));
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
WARN_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %s: %s", GetStepFunctionName(dec.steps_[i]), temp);
|
||||
return 0;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
/*
|
||||
DisassembleArm(start, GetCodePtr() - start);
|
||||
char temp[1024] = {0};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
INFO_LOG(Log::G3D, "%s", temp);
|
||||
*/
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
// Reset the code ptr (effectively undoing what we generated) and return zero to indicate that we failed.
|
||||
ResetCodePtr(GetOffset(start));
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
WARN_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %s: %s", GetStepFunctionName(dec.steps_[i]), temp);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -291,7 +291,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
|
||||
if (log) {
|
||||
char temp[1024] = { 0 };
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
INFO_LOG(Log::JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start));
|
||||
std::vector<std::string> lines = DisassembleArm64(start, (int)(GetCodePtr() - start));
|
||||
for (auto line : lines) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Data/Convert/ColorConv.h"
|
||||
#include "Common/Data/Text/StringWriter.h"
|
||||
#include "Common/Math/CrossSIMD.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/LogReporting.h"
|
||||
@@ -84,6 +85,41 @@ static int DecFmtSize(u8 fmt) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *DecFmtComponentToString(u8 fmt) {
|
||||
switch (fmt) {
|
||||
case DEC_NONE: return "NONE";
|
||||
case DEC_FLOAT_1: return "FLOAT_1";
|
||||
case DEC_FLOAT_2: return "FLOAT_2";
|
||||
case DEC_FLOAT_3: return "FLOAT_3";
|
||||
case DEC_FLOAT_4: return "FLOAT_4";
|
||||
case DEC_S8_3: return "S8_3";
|
||||
case DEC_S16_3: return "S16_3";
|
||||
case DEC_U8_1: return "U8_1";
|
||||
case DEC_U8_2: return "U8_2";
|
||||
case DEC_U8_3: return "U8_3";
|
||||
case DEC_U8_4: return "U8_4";
|
||||
case DEC_U16_1: return "U16_1";
|
||||
case DEC_U16_2: return "U16_2";
|
||||
case DEC_U16_3: return "U16_3";
|
||||
case DEC_U16_4: return "U16_4";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::string DecVtxFormat::ToString() const {
|
||||
char buf[256];
|
||||
StringWriter w(buf, sizeof(buf));
|
||||
if (w0fmt) {
|
||||
w.F("W0: %s ", DecFmtComponentToString(w0fmt));
|
||||
}
|
||||
w.F("W1: %s ", DecFmtComponentToString(w1fmt));
|
||||
w.F("UV: %s ", DecFmtComponentToString(uvfmt));
|
||||
w.F("C0: %s ", DecFmtComponentToString(c0fmt));
|
||||
w.F("C1: %s ", DecFmtComponentToString(c1fmt));
|
||||
w.F("N: %s", DecFmtComponentToString(nrmfmt));
|
||||
return w.as_string();
|
||||
}
|
||||
|
||||
void DecVtxFormat::ComputeID() {
|
||||
id = w0fmt | (w1fmt << 4) | (uvfmt << 8) | (c0fmt << 12) | (c1fmt << 16) | (nrmfmt << 20);
|
||||
}
|
||||
@@ -1413,7 +1449,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options,
|
||||
|
||||
if (reportNoPos) {
|
||||
char temp[256]{};
|
||||
ToString(temp, true);
|
||||
ToString(temp, sizeof(temp), true);
|
||||
ERROR_LOG(Log::G3D, "Vertices without position found (and ignored): (%08x) %s", fmt_, temp);
|
||||
}
|
||||
|
||||
@@ -1550,8 +1586,8 @@ void VertexDecoder::CompareToJit(const u8 *startPtr, u8 *decodedptr, int count,
|
||||
controlReader.Goto(i);
|
||||
jittedReader.Goto(i);
|
||||
if (!DecodedVertsAreSimilar(controlReader, jittedReader)) {
|
||||
char name[512]{};
|
||||
ToString(name, true);
|
||||
char name[256]{};
|
||||
ToString(name, sizeof(name), true);
|
||||
ERROR_LOG(Log::G3D, "Encountered vertexjit mismatch at %d/%d for %s", i, count, name);
|
||||
if (morphcount > 1) {
|
||||
printf("Morph:\n");
|
||||
@@ -1605,26 +1641,30 @@ static const char * const idxnames[4] = { "-", "u8", "u16", "?" };
|
||||
static const char * const weightnames[4] = { "-", "u8", "u16", "f" };
|
||||
static const char * const colnames[8] = { "", "?", "?", "?", "565", "5551", "4444", "8888" };
|
||||
|
||||
int VertexDecoder::ToString(char *output, bool spaces) const {
|
||||
char *start = output;
|
||||
output += sprintf(output, "[%08x] ", fmt_);
|
||||
output += sprintf(output, "P: %s ", posnames[pos]);
|
||||
if (nrm)
|
||||
output += sprintf(output, "N: %s ", nrmnames[nrm]);
|
||||
if (col)
|
||||
output += sprintf(output, "C: %s ", colnames[col]);
|
||||
if (tc)
|
||||
output += sprintf(output, "T: %s ", tcnames[tc]);
|
||||
if (weighttype)
|
||||
output += sprintf(output, "W: %s (%ix) ", weightnames[weighttype], nweights);
|
||||
if (idx)
|
||||
output += sprintf(output, "I: %s ", idxnames[idx]);
|
||||
if (morphcount > 1)
|
||||
output += sprintf(output, "Morph: %i ", morphcount);
|
||||
if (throughmode)
|
||||
output += sprintf(output, " (through)");
|
||||
// There's a direct ToString function for vertex types in the GPU debugger, GeDescribeVertexType.
|
||||
|
||||
output += sprintf(output, " (%ib)", VertexSize());
|
||||
int VertexDecoder::ToString(char *buf, int bufSize, bool spaces) const {
|
||||
StringWriter w(buf, bufSize);
|
||||
|
||||
char *start = buf;
|
||||
w.F("[%08x] ", fmt_);
|
||||
w.F("P: %s ", posnames[pos]);
|
||||
if (nrm)
|
||||
w.F("N: %s ", nrmnames[nrm]);
|
||||
if (col)
|
||||
w.F("C: %s ", colnames[col]);
|
||||
if (tc)
|
||||
w.F("T: %s ", tcnames[tc]);
|
||||
if (weighttype)
|
||||
w.F("W: %s (%ix) ", weightnames[weighttype], nweights);
|
||||
if (idx)
|
||||
w.F("I: %s ", idxnames[idx]);
|
||||
if (morphcount > 1)
|
||||
w.F("Morph: %i ", morphcount);
|
||||
if (throughmode)
|
||||
w.F(" (through)");
|
||||
|
||||
w.F(" (%ib)", VertexSize());
|
||||
|
||||
if (!spaces) {
|
||||
size_t len = strlen(start);
|
||||
@@ -1635,17 +1675,16 @@ int VertexDecoder::ToString(char *output, bool spaces) const {
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
output += sprintf(output, " (%llu)", (long long)decodedCount);
|
||||
w.F(" (%llu)", (long long)decodedCount);
|
||||
#endif
|
||||
|
||||
return output - start;
|
||||
return (int)w.size();
|
||||
}
|
||||
|
||||
std::string VertexDecoder::GetString(DebugShaderStringType stringType) const {
|
||||
char buffer[256];
|
||||
switch (stringType) {
|
||||
case SHADER_STRING_SHORT_DESC:
|
||||
ToString(buffer, true);
|
||||
ToString(buffer, sizeof(buffer), true);
|
||||
return std::string(buffer);
|
||||
case SHADER_STRING_SOURCE_CODE:
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
// Keep this in 4 bits.
|
||||
enum {
|
||||
DEC_NONE,
|
||||
DEC_NONE = 0,
|
||||
DEC_FLOAT_1,
|
||||
DEC_FLOAT_2,
|
||||
DEC_FLOAT_3,
|
||||
@@ -63,6 +63,8 @@ enum {
|
||||
DEC_U16_4,
|
||||
};
|
||||
|
||||
const char *DecFmtComponentToString(u8 fmt);
|
||||
|
||||
// DecVtxFormat - vertex formats for PC
|
||||
// Kind of like a D3D VertexDeclaration.
|
||||
// No morph support, that is taken care of by the VertexDecoder.
|
||||
@@ -81,6 +83,8 @@ struct DecVtxFormat {
|
||||
void InitializeFromID(uint32_t id);
|
||||
|
||||
static u8 PosFmt() { return DEC_FLOAT_3; }
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound);
|
||||
@@ -153,6 +157,8 @@ inline GETexMapMode VertTypeIDUVGenMode(uint32_t vertType) {
|
||||
return (GETexMapMode)((vertType >> 24) & 3);
|
||||
}
|
||||
|
||||
std::string DecFmtIdToString(u32 id);
|
||||
|
||||
class VertexDecoder {
|
||||
public:
|
||||
// A jit cache is not mandatory.
|
||||
@@ -258,7 +264,7 @@ public:
|
||||
// output must be big for safety.
|
||||
// Returns number of chars written.
|
||||
// Ugly for speed.
|
||||
int ToString(char *output, bool spaces) const;
|
||||
int ToString(char *buf, int bufSize, bool spaces) const;
|
||||
|
||||
bool IsInSpace(const uint8_t *ptr) const {
|
||||
return ptr >= (const uint8_t *)jitted_ && ptr < ((const uint8_t *)jitted_ + jittedSize_);
|
||||
|
||||
@@ -297,7 +297,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
// Reset the code ptr (effectively undoing what we generated) and return zero to indicate that we failed.
|
||||
ResetCodePtr(GetOffset(start));
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
WARN_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %s: %s", GetStepFunctionName(dec.steps_[i]), temp);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
|
||||
if (log) {
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
INFO_LOG(Log::JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start));
|
||||
std::vector<std::string> lines = DisassembleLA64(start, (int)(GetCodePtr() - start));
|
||||
for (auto line : lines) {
|
||||
|
||||
@@ -316,7 +316,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
// Reset the code ptr (effectively undoing what we generated) and return zero to indicate that we failed.
|
||||
ResetCodePtr(GetOffset(start));
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
WARN_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %s: %s", GetStepFunctionName(dec.steps_[i]), temp);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -349,7 +349,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
|
||||
if (log) {
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
INFO_LOG(Log::JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start));
|
||||
std::vector<std::string> lines = DisassembleRV64(start, (int)(GetCodePtr() - start));
|
||||
for (auto line : lines) {
|
||||
|
||||
@@ -281,8 +281,8 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int
|
||||
EndWrite();
|
||||
// Reset the code ptr and return zero to indicate that we failed.
|
||||
ResetCodePtr(GetOffset(start));
|
||||
char temp[1024]{};
|
||||
dec.ToString(temp, true);
|
||||
char temp[256]{};
|
||||
dec.ToString(temp, sizeof(temp), true);
|
||||
WARN_LOG(Log::G3D, "Could not compile vertex decoder, failed at step %s: %s", GetStepFunctionName(dec.steps_[i]), temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ struct VulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster; // prim is included here
|
||||
VShaderID vid;
|
||||
FShaderID fid;
|
||||
uint32_t vtxFmtId;
|
||||
uint32_t vtxFmtId; // Note: This is the decoded format ID, not the source format!
|
||||
bool useHWTransform;
|
||||
|
||||
void ToString(std::string *str) const {
|
||||
|
||||
@@ -510,6 +510,10 @@ const bool IsSameExceptForShaders(const VulkanPipelineKey &a, const VulkanPipeli
|
||||
return a.useHWTransform == b.useHWTransform && a.raster == b.raster && a.vtxFmtId == b.vtxFmtId;
|
||||
}
|
||||
|
||||
const bool IsSameExceptForVertexFormat(const VulkanPipelineKey &a, const VulkanPipelineKey &b) {
|
||||
return a.useHWTransform == b.useHWTransform && a.raster == b.raster && a.vid == b.vid && a.fid == b.fid;
|
||||
}
|
||||
|
||||
void ShaderListScreen::AddPipelineAnalysis(UI::LinearLayout *tabContent) {
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
GPU_Vulkan *vgpu = dynamic_cast<GPU_Vulkan *>(gpu);
|
||||
@@ -538,6 +542,15 @@ void ShaderListScreen::AddPipelineAnalysis(UI::LinearLayout *tabContent) {
|
||||
toBeMerged += "FShader: " + keyA.fid.Description() + " vs " + keyB.fid.Description() + "\n";
|
||||
}
|
||||
}
|
||||
if (IsSameExceptForVertexFormat(keyA, keyB)) {
|
||||
if (keyA.vtxFmtId != 0 && keyB.vtxFmtId != 0 && keyA.vtxFmtId != keyB.vtxFmtId) {
|
||||
DecVtxFormat fmtA;
|
||||
DecVtxFormat fmtB;
|
||||
fmtA.InitializeFromID(keyA.vtxFmtId);
|
||||
fmtB.InitializeFromID(keyB.vtxFmtId);
|
||||
toBeMerged += "VertexFmt: " + fmtA.ToString() + " vs " + fmtB.ToString() + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!toBeMerged.empty()) {
|
||||
tabContent->Add(new UI::TextView(keys[i].GetDescription(SHADER_STRING_SHORT_DESC), FLAG_DYNAMIC_ASCII | FLAG_WRAP_TEXT, true));
|
||||
|
||||
Reference in New Issue
Block a user