mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Reverse the bits so we actually get the desired shader sorting order in the debug shader viewer
This commit is contained in:
@@ -24,6 +24,23 @@ inline u32 ReverseBits32(u32 v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
inline u64 ReverseBits64(u64 v) {
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
|
||||
// swap odd and even bits
|
||||
v = ((v >> 1) & 0x5555555555555555ULL) | ((v & 0x5555555555555555ULL) << 1);
|
||||
// swap consecutive pairs
|
||||
v = ((v >> 2) & 0x3333333333333333ULL) | ((v & 0x3333333333333333ULL) << 2);
|
||||
// swap nibbles ...
|
||||
v = ((v >> 4) & 0x0F0F0F0F0F0F0F0FULL) | ((v & 0x0F0F0F0F0F0F0F0FULL) << 4);
|
||||
// swap bytes
|
||||
v = ((v >> 8) & 0x00FF00FF00FF00FFULL) | ((v & 0x00FF00FF00FF00FFULL) << 8);
|
||||
// swap 2-byte long pairs
|
||||
v = ((v >> 16) & 0x0000FFFF0000FFFFULL) | ((v & 0x0000FFFF0000FFFFULL) << 16);
|
||||
// swap 4-byte long pairs
|
||||
v = (v >> 32) | (v << 32);
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
template <typename T>
|
||||
|
||||
@@ -21,6 +21,11 @@ public:
|
||||
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
|
||||
return (m_z << 16) + m_w;
|
||||
}
|
||||
uint64_t R64() {
|
||||
const uint32_t bottom = R32();
|
||||
const uint32_t top = R32();
|
||||
return ((uint64_t)top << 32) | bottom;
|
||||
}
|
||||
float F() {
|
||||
return (float)R32() / (float)(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
+41
-15
@@ -1,10 +1,11 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/GPU/thin3d.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Data/Text/StringWriter.h"
|
||||
#include "Common/BitSet.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
#include "GPU/ge_constants.h"
|
||||
@@ -15,11 +16,15 @@
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h" // Just for ClipInfoFlags
|
||||
|
||||
std::string ShaderID::ToDebugString() const {
|
||||
return StringFromFormat("%08x:%08x", d >> 32, d & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
std::string VertexShaderDesc(const VShaderID &id) {
|
||||
char buffer[512];
|
||||
StringWriter desc(buffer, sizeof(buffer));
|
||||
|
||||
desc.F("%08x:%08x ", id.d[1], id.d[0]);
|
||||
desc.W(id.ToDebugString()).C(" ");
|
||||
if (id.Bit(VS_BIT_IS_THROUGH)) desc.C("THR ");
|
||||
if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc.C("HWX "); else desc.C("SWX ");
|
||||
if (id.Bit(VS_BIT_HAS_NORMAL)) desc.C("N ");
|
||||
@@ -174,10 +179,19 @@ static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) {
|
||||
|
||||
std::string FragmentShaderDesc(const FShaderID &id) {
|
||||
std::stringstream desc;
|
||||
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
|
||||
desc << id.ToDebugString() << " ";
|
||||
if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";
|
||||
if (id.Bit(FS_BIT_DO_TEXTURE)) desc << (id.Bit(FS_BIT_3D_TEXTURE) ? "Tex3D " : "Tex ");
|
||||
if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
|
||||
if (id.Bit(FS_BIT_DO_TEXTURE)) {
|
||||
desc << (id.Bit(FS_BIT_3D_TEXTURE) ? "Tex3D" : "Tex");
|
||||
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
|
||||
case GE_TEXFUNC_ADD: desc << "(TFuncAdd) "; break;
|
||||
case GE_TEXFUNC_BLEND: desc << "(TFuncBlend) "; break;
|
||||
case GE_TEXFUNC_DECAL: desc << "(TFuncDecal) "; break;
|
||||
case GE_TEXFUNC_MODULATE: desc << "(TFuncMod) "; break;
|
||||
case GE_TEXFUNC_REPLACE: desc << "(TFuncRepl) "; break;
|
||||
default: desc << "(TFuncUnk) "; break;
|
||||
}
|
||||
}
|
||||
if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
|
||||
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
|
||||
if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc << "DepthNever ";
|
||||
@@ -224,16 +238,7 @@ std::string FragmentShaderDesc(const FShaderID &id) {
|
||||
} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
|
||||
desc << "StenOff ";
|
||||
}
|
||||
if (id.Bit(FS_BIT_DO_TEXTURE)) {
|
||||
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
|
||||
case GE_TEXFUNC_ADD: desc << "TFuncAdd "; break;
|
||||
case GE_TEXFUNC_BLEND: desc << "TFuncBlend "; break;
|
||||
case GE_TEXFUNC_DECAL: desc << "TFuncDecal "; break;
|
||||
case GE_TEXFUNC_MODULATE: desc << "TFuncMod "; break;
|
||||
case GE_TEXFUNC_REPLACE: desc << "TFuncRepl "; break;
|
||||
default: desc << "TFuncUnk "; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc << "AlphaTest0 " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
|
||||
else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
|
||||
@@ -429,3 +434,24 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
|
||||
|
||||
*id_out = id;
|
||||
}
|
||||
|
||||
std::vector<std::string> ToSortedDebugShaderIdVec(std::vector<uint64_t> ids) {
|
||||
// Reverse the bits so that the sort order matches the importance order.
|
||||
for (auto &id : ids) {
|
||||
id = ReverseBits64(id);
|
||||
}
|
||||
std::sort(ids.begin(), ids.end());
|
||||
// Reverse the bits back to get the original IDs.
|
||||
for (auto &id : ids) {
|
||||
id = ReverseBits64(id);
|
||||
}
|
||||
std::vector<std::string> strIds;
|
||||
for (auto &id : ids) {
|
||||
ShaderID shaderId;
|
||||
shaderId.FromUint64(id);
|
||||
std::string idStr;
|
||||
shaderId.ToString(&idStr);
|
||||
strIds.push_back(idStr);
|
||||
}
|
||||
return strIds;
|
||||
}
|
||||
|
||||
+31
-42
@@ -121,87 +121,73 @@ struct ShaderID {
|
||||
clear();
|
||||
}
|
||||
void clear() {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
|
||||
d[i] = 0;
|
||||
}
|
||||
d = 0;
|
||||
}
|
||||
void set_invalid() {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
|
||||
d[i] = 0xFFFFFFFF;
|
||||
}
|
||||
d = 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
bool is_invalid() const {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
|
||||
if (d[i] != 0xFFFFFFFF)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return d == 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
|
||||
uint32_t d[2];
|
||||
bool operator < (const ShaderID &other) const {
|
||||
for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) {
|
||||
if (d[i] < other.d[i])
|
||||
return true;
|
||||
if (d[i] > other.d[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return d < other.d;
|
||||
}
|
||||
bool operator == (const ShaderID &other) const {
|
||||
for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) {
|
||||
if (d[i] != other.d[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return d == other.d;
|
||||
}
|
||||
bool operator != (const ShaderID &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uint32_t Word(int word) const {
|
||||
return d[word];
|
||||
}
|
||||
|
||||
// Note: This is a binary copy to string-as-bytes, not a human-readable representation.
|
||||
void ToString(std::string *dest) const {
|
||||
dest->resize(sizeof(d));
|
||||
memcpy(&(*dest)[0], d, sizeof(d));
|
||||
memcpy(&(*dest)[0], &d, sizeof(d));
|
||||
}
|
||||
// Note: This is a binary copy from string-as-bytes, not a human-readable representation.
|
||||
void FromString(std::string src) {
|
||||
memcpy(d, &(src)[0], sizeof(d));
|
||||
memcpy(&d, &(src)[0], sizeof(d));
|
||||
}
|
||||
|
||||
uint64_t ToUint64() const {
|
||||
return d;
|
||||
}
|
||||
void FromUint64(uint64_t src) {
|
||||
d = src;
|
||||
}
|
||||
|
||||
std::string ToDebugString() const;
|
||||
uint64_t d;
|
||||
protected:
|
||||
bool Bit(int bit) const {
|
||||
return (d[bit >> 5] >> (bit & 31)) & 1;
|
||||
return (d >> bit) & 1;
|
||||
}
|
||||
// Does not handle crossing 32-bit boundaries. count must be 30 or smaller.
|
||||
int Bits(int bit, int count) const {
|
||||
const int mask = (1 << count) - 1;
|
||||
return (d[bit >> 5] >> (bit & 31)) & mask;
|
||||
return (d >> bit) & mask;
|
||||
}
|
||||
void SetBit(int bit, bool value = true) {
|
||||
if (value) {
|
||||
d[bit >> 5] |= 1 << (bit & 31);
|
||||
d |= 1ULL << bit;
|
||||
} else {
|
||||
d[bit >> 5] &= ~(1 << (bit & 31));
|
||||
d &= ~(1ULL << bit);
|
||||
}
|
||||
}
|
||||
void SetBits(int bit, int count, int value) {
|
||||
const int mask = (1 << count) - 1;
|
||||
const int shifted_mask = mask << (bit & 31);
|
||||
d[bit >> 5] = (d[bit >> 5] & ~shifted_mask) | ((value & mask) << (bit & 31));
|
||||
const uint64_t shifted_mask = uint64_t(mask) << bit;
|
||||
d = (d & ~shifted_mask) | (uint64_t(value & mask) << bit);
|
||||
}
|
||||
};
|
||||
|
||||
struct VShaderID : ShaderID {
|
||||
struct VShaderID : public ShaderID {
|
||||
VShaderID() : ShaderID() {
|
||||
}
|
||||
|
||||
explicit VShaderID(ShaderID &src) {
|
||||
memcpy(d, src.d, sizeof(d));
|
||||
explicit VShaderID(const ShaderID &src) {
|
||||
d = src.d;
|
||||
}
|
||||
|
||||
bool Bit(VShaderBit bit) const {
|
||||
@@ -221,12 +207,12 @@ struct VShaderID : ShaderID {
|
||||
}
|
||||
};
|
||||
|
||||
struct FShaderID : ShaderID {
|
||||
struct FShaderID : public ShaderID {
|
||||
FShaderID() : ShaderID() {
|
||||
}
|
||||
|
||||
explicit FShaderID(ShaderID &src) {
|
||||
memcpy(d, src.d, sizeof(d));
|
||||
explicit FShaderID(const ShaderID &src) {
|
||||
d = src.d;
|
||||
}
|
||||
|
||||
bool Bit(FShaderBit bit) const {
|
||||
@@ -261,3 +247,6 @@ std::string FragmentShaderDesc(const FShaderID &id);
|
||||
|
||||
// For sanity checking.
|
||||
bool FragmentIdNeedsFramebufferRead(const FShaderID &id);
|
||||
|
||||
// For the shader viewer.
|
||||
std::vector<std::string> ToSortedDebugShaderIdVec(std::vector<uint64_t> ids);
|
||||
|
||||
@@ -262,28 +262,26 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertexType, D3D11VertexShader
|
||||
|
||||
std::vector<std::string> ShaderManagerD3D11::DebugGetShaderIDs(DebugShaderType type) {
|
||||
std::string id;
|
||||
std::vector<std::string> ids;
|
||||
std::vector<uint64_t> ids;
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
{
|
||||
for (auto iter : vsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
for (auto &iter : vsCache_) {
|
||||
ids.push_back(iter.first.ToUint64());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
{
|
||||
for (auto iter : fsCache_) {
|
||||
iter.first.ToString(&id);
|
||||
ids.push_back(id);
|
||||
for (auto &iter : fsCache_) {
|
||||
ids.push_back(iter.first.ToUint64());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
return ToSortedDebugShaderIdVec(ids);
|
||||
}
|
||||
|
||||
std::string ShaderManagerD3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
|
||||
@@ -673,7 +673,7 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) {
|
||||
std::string errorString;
|
||||
FragmentShaderFlags flags;
|
||||
if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString)) {
|
||||
ERROR_LOG_REPORT(Log::G3D, "FS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", FSID.d[0], FSID.d[1]);
|
||||
ERROR_LOG_REPORT(Log::G3D, "FS shader gen error: %s (%s: %s)", errorString.c_str(), "GLES", FSID.ToDebugString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
|
||||
@@ -691,7 +691,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
|
||||
std::string errorString;
|
||||
VertexShaderFlags flags;
|
||||
if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &errorString)) {
|
||||
ERROR_LOG_REPORT(Log::G3D, "VS shader gen error: %s (%s: %08x:%08x)", errorString.c_str(), "GLES", VSID.d[0], VSID.d[1]);
|
||||
ERROR_LOG_REPORT(Log::G3D, "VS shader gen error: %s (%s: %s)", errorString.c_str(), "GLES", VSID.ToDebugString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
|
||||
@@ -776,7 +776,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
|
||||
// Could fail to generate, in which case we're kinda screwed.
|
||||
fs = CompileFragmentShader(FSID);
|
||||
if (!fs) {
|
||||
ERROR_LOG(Log::G3D, "Failed to generate fragment shader with ID %08x:%08x", FSID.d[0], FSID.d[1]);
|
||||
ERROR_LOG(Log::G3D, "Failed to generate fragment shader with ID %s", FSID.ToDebugString().c_str());
|
||||
// Still insert it so we don't end up spamming generation.
|
||||
}
|
||||
fsCache_.Insert(FSID, fs);
|
||||
@@ -834,26 +834,22 @@ std::string Shader::GetShaderString(DebugShaderStringType type, ShaderID id) con
|
||||
|
||||
std::vector<std::string> ShaderManagerGLES::DebugGetShaderIDs(DebugShaderType type) {
|
||||
std::string id;
|
||||
std::vector<std::string> ids;
|
||||
std::vector<uint64_t> ids;
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
vsCache_.Iterate([&](const VShaderID &id, Shader *shader) {
|
||||
std::string idstr;
|
||||
id.ToString(&idstr);
|
||||
ids.push_back(idstr);
|
||||
ids.push_back(id.ToUint64());
|
||||
});
|
||||
break;
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
fsCache_.Iterate([&](const FShaderID &id, Shader *shader) {
|
||||
std::string idstr;
|
||||
id.ToString(&idstr);
|
||||
ids.push_back(idstr);
|
||||
ids.push_back(id.ToUint64());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
return ToSortedDebugShaderIdVec(ids);
|
||||
}
|
||||
|
||||
std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
|
||||
@@ -318,28 +318,23 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShade
|
||||
}
|
||||
|
||||
std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) {
|
||||
std::vector<std::string> ids;
|
||||
std::vector<uint64_t> ids;
|
||||
switch (type) {
|
||||
case SHADER_TYPE_VERTEX:
|
||||
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *shader) {
|
||||
std::string idstr;
|
||||
id.ToString(&idstr);
|
||||
ids.push_back(idstr);
|
||||
ids.push_back(id.ToUint64());
|
||||
});
|
||||
break;
|
||||
case SHADER_TYPE_FRAGMENT:
|
||||
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *shader) {
|
||||
std::string idstr;
|
||||
id.ToString(&idstr);
|
||||
ids.push_back(idstr);
|
||||
ids.push_back(id.ToUint64());
|
||||
});
|
||||
break;
|
||||
case SHADER_TYPE_GEOMETRY:
|
||||
return ids;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ids;
|
||||
|
||||
return ToSortedDebugShaderIdVec(ids);
|
||||
}
|
||||
|
||||
std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
||||
|
||||
@@ -368,11 +368,9 @@ bool TestVertexShaders() {
|
||||
// Generate a bunch of random vertex shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
uint64_t id64 = rng.R64();
|
||||
VShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
id.FromUint64(id64);
|
||||
|
||||
// The generated bits need some adjustment:
|
||||
|
||||
@@ -453,11 +451,9 @@ bool TestFragmentShaders() {
|
||||
// Generate a bunch of random fragment shader IDs, try to generate shader source.
|
||||
// Then compile it and check that it's ok.
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t bottom = rng.R32();
|
||||
uint32_t top = rng.R32();
|
||||
uint64_t id64 = rng.R64();
|
||||
FShaderID id;
|
||||
id.d[0] = bottom;
|
||||
id.d[1] = top;
|
||||
id.FromUint64(id64);
|
||||
|
||||
// bits we don't need to test because they are irrelevant on d3d11
|
||||
id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, false);
|
||||
|
||||
Reference in New Issue
Block a user