Merge pull request #21901 from hrydgard/vulkan-pipeline-key-shader-id

Vulkan code cleanup: Use shader IDs in the pipeline key for the hashmap instead of shader pointers
This commit is contained in:
Henrik Rydgård
2026-07-09 19:18:47 +02:00
committed by GitHub
14 changed files with 216 additions and 272 deletions
+4 -3
View File
@@ -57,10 +57,11 @@ public:
return *this;
}
// W: Writes a zero-terminated string to the stream.
ShaderWriter &W(const char *text) {
size_t len = strlen(text);
memcpy(p_, text, len + 1);
ShaderWriter &W(std::string_view text) {
size_t len = text.size();
memcpy(p_, text.data(), len);
p_ += len;
*p_ = '\0';
return *this;
}
+1 -1
View File
@@ -101,7 +101,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
}
ShaderWriter p(buffer, compat, ShaderStage::Fragment, extensions, flags);
p.F("// %s\n", FragmentShaderDesc(id).c_str());
p.C("// %").W(id.Description()).endl();
p.ApplySamplerMetadata(arrayTexture ? samplersStereo : samplersMono);
+64 -64
View File
@@ -19,56 +19,56 @@ std::string ShaderID::ToDebugString() const {
return StringFromFormat("%08x:%08x", d >> 32, d & 0xFFFFFFFF);
}
std::string VertexShaderDesc(const VShaderID &id) {
std::string VShaderID::Description() const {
char buffer[512];
StringWriter desc(buffer, sizeof(buffer));
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 ");
if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc.C("T ");
if (id.Bit(VS_BIT_HAS_COLOR)) desc.C("C ");
if (id.Bit(VS_BIT_LMODE)) desc.C("LM ");
if (id.Bit(VS_BIT_NORM_REVERSE)) desc.C("RevN ");
if (id.Bit(VS_BIT_FLATSHADE)) desc.C("Flat ");
if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc.C("MatUp:").F("%d", id.Bits(VS_BIT_MATERIAL_UPDATE, 3)).C(" ");
desc.W(ToDebugString()).C(" ");
if (Bit(VS_BIT_IS_THROUGH)) desc.C("THR ");
if (Bit(VS_BIT_USE_HW_TRANSFORM)) desc.C("HWX "); else desc.C("SWX ");
if (Bit(VS_BIT_HAS_NORMAL)) desc.C("N ");
if (Bit(VS_BIT_HAS_TEXCOORD)) desc.C("T ");
if (Bit(VS_BIT_HAS_COLOR)) desc.C("C ");
if (Bit(VS_BIT_LMODE)) desc.C("LM ");
if (Bit(VS_BIT_NORM_REVERSE)) desc.C("RevN ");
if (Bit(VS_BIT_FLATSHADE)) desc.C("Flat ");
if (Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc.C("MatUp:").F("%d", Bits(VS_BIT_MATERIAL_UPDATE, 3)).C(" ");
int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);
int uvgMode = Bits(VS_BIT_UVGEN_MODE, 2);
static constexpr std::string_view uvgModes[4] = {"UV ", "UVMtx ", "UVEnv ", "UVUnk "};
if (uvgMode) desc.W(uvgModes[uvgMode]);
if (uvgMode == GE_TEXMAP_TEXTURE_MATRIX) {
int uvprojMode = id.Bits(VS_BIT_UVPROJ_MODE, 2);
int uvprojMode = Bits(VS_BIT_UVPROJ_MODE, 2);
static constexpr std::string_view uvprojModes[4] = { "TexProjPos ", "TexProjUV ", "TexProjNNrm ", "TexProjNrm " };
desc.W(uvprojModes[uvprojMode]);
}
if (id.Bit(VS_BIT_ENABLE_BONES)) desc.F("Bones:%d ", id.Bits(VS_BIT_BONES, 3) + 1);
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc.F("WScale:%d ", id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2));
if (Bit(VS_BIT_ENABLE_BONES)) desc.F("Bones:%d ", Bits(VS_BIT_BONES, 3) + 1);
if (Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc.F("WScale:%d ", Bits(VS_BIT_WEIGHT_FMTSCALE, 2));
int ls0 = id.Bits(VS_BIT_LS0, 2);
int ls1 = id.Bits(VS_BIT_LS1, 2);
int ls0 = Bits(VS_BIT_LS0, 2);
int ls1 = Bits(VS_BIT_LS1, 2);
if (id.Bit(VS_BIT_FS_MINMAX_DISCARD)) desc.C("FSMinMax ");
if (id.Bit(VS_BIT_FS_DEPTH_CLAMP)) desc.C("FSDepthClamp ");
if (Bit(VS_BIT_FS_MINMAX_DISCARD)) desc.C("FSMinMax ");
if (Bit(VS_BIT_FS_DEPTH_CLAMP)) desc.C("FSDepthClamp ");
// Lights
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
if (Bit(VS_BIT_LIGHTING_ENABLE)) {
desc.C("Light: ");
}
if (id.Bit(VS_BIT_LIGHT_UBERSHADER)) {
if (Bit(VS_BIT_LIGHT_UBERSHADER)) {
desc.C("LightUberShader ");
}
for (int i = 0; i < 4; i++) {
bool enabled = id.Bit(VS_BIT_LIGHT0_ENABLE + i) && id.Bit(VS_BIT_LIGHTING_ENABLE);
bool enabled = Bit(VS_BIT_LIGHT0_ENABLE + i) && Bit(VS_BIT_LIGHTING_ENABLE);
if (enabled || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
desc.F("%d: ", i);
desc.F("c:%d t:%d ", id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2), id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
desc.F("c:%d t:%d ", Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2), Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
}
}
if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc.C("SimpleStereo ");
if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc.C("RangeCull ");
if (Bit(VS_BIT_SIMPLE_STEREO)) desc.C("SimpleStereo ");
if (Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc.C("RangeCull ");
return desc.as_string();
}
@@ -176,15 +176,15 @@ static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) {
return m[2] != 0.0f || m[5] != 0.0f || (m[8] != 0.0f && mode != GE_PROJMAP_UV) || m[11] != 1.0f;
}
std::string FragmentShaderDesc(const FShaderID &id) {
std::string FShaderID::Description() const {
char buffer[512];
StringWriter desc(buffer, sizeof(buffer));
desc.W(id.ToDebugString()).C(" ");
if (id.Bit(FS_BIT_CLEARMODE)) desc.C("Clear ");
if (id.Bit(FS_BIT_DO_TEXTURE)) {
desc.W(id.Bit(FS_BIT_3D_TEXTURE) ? "Tex3D" : "Tex");
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
desc.W(ToDebugString()).C(" ");
if (Bit(FS_BIT_CLEARMODE)) desc.C("Clear ");
if (Bit(FS_BIT_DO_TEXTURE)) {
desc.W(Bit(FS_BIT_3D_TEXTURE) ? "Tex3D" : "Tex");
switch (Bits(FS_BIT_TEXFUNC, 3)) {
case GE_TEXFUNC_ADD: desc.C("(TFuncAdd) "); break;
case GE_TEXFUNC_BLEND: desc.C("(TFuncBlend) "); break;
case GE_TEXFUNC_DECAL: desc.C("(TFuncDecal) "); break;
@@ -193,41 +193,41 @@ std::string FragmentShaderDesc(const FShaderID &id) {
default: desc.C("(TFuncUnk) "); break;
}
}
if (id.Bit(FS_BIT_LMODE)) desc.C("LM ");
if (id.Bit(FS_BIT_ENABLE_FOG)) desc.C("Fog ");
if (id.Bit(FS_BIT_FLATSHADE)) desc.C("Flat ");
if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc.C("DepthNever ");
if (id.Bit(FS_BIT_COLOR_WRITEMASK)) desc.C("WriteMask ");
if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
if (Bit(FS_BIT_LMODE)) desc.C("LM ");
if (Bit(FS_BIT_ENABLE_FOG)) desc.C("Fog ");
if (Bit(FS_BIT_FLATSHADE)) desc.C("Flat ");
if (Bit(FS_BIT_DEPTH_TEST_NEVER)) desc.C("DepthNever ");
if (Bit(FS_BIT_COLOR_WRITEMASK)) desc.C("WriteMask ");
if (Bit(FS_BIT_SHADER_TEX_CLAMP)) {
desc.C("TClamp");
if (id.Bit(FS_BIT_CLAMP_S)) desc.C("S");
if (id.Bit(FS_BIT_CLAMP_T)) desc.C("T");
if (Bit(FS_BIT_CLAMP_S)) desc.C("S");
if (Bit(FS_BIT_CLAMP_T)) desc.C("T");
desc.C(" ");
}
int blendBits = id.Bits(FS_BIT_REPLACE_BLEND, 3);
int blendBits = Bits(FS_BIT_REPLACE_BLEND, 3);
if (blendBits) {
switch (blendBits) {
case ReplaceBlendType::REPLACE_BLEND_BLUE_TO_ALPHA:
desc.C("BlueToAlpha_" "A:").F("%d ", id.Bits(FS_BIT_BLENDFUNC_A, 4));
desc.C("BlueToAlpha_" "A:").F("%d ", Bits(FS_BIT_BLENDFUNC_A, 4));
break;
default:
desc.C("ReplaceBlend_").F("%d ", id.Bits(FS_BIT_REPLACE_BLEND, 3))
.C("A:").F("%d ", id.Bits(FS_BIT_BLENDFUNC_A, 4))
.C("_B:").F("%d ", id.Bits(FS_BIT_BLENDFUNC_B, 4))
.C("_Eq:").F("%d ", id.Bits(FS_BIT_BLENDEQ, 3));
desc.C("ReplaceBlend_").F("%d ", Bits(FS_BIT_REPLACE_BLEND, 3))
.C("A:").F("%d ", Bits(FS_BIT_BLENDFUNC_A, 4))
.C("_B:").F("%d ", Bits(FS_BIT_BLENDFUNC_B, 4))
.C("_Eq:").F("%d ", Bits(FS_BIT_BLENDEQ, 3));
break;
}
}
switch (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {
switch (Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {
case REPLACE_ALPHA_NO: break;
case REPLACE_ALPHA_YES: desc.C("StenToAlpha "); break;
case REPLACE_ALPHA_DUALSOURCE: desc.C("StenToAlphaDual "); break;
default: desc.C("StenToAlphaUnknown "); break; // bad
}
if (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {
switch (id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {
if (Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {
switch (Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {
case STENCIL_VALUE_UNIFORM: desc.C("StenUniform "); break;
case STENCIL_VALUE_ZERO: desc.C("Sten0 "); break;
case STENCIL_VALUE_ONE: desc.C("Sten1 "); break;
@@ -239,30 +239,30 @@ std::string FragmentShaderDesc(const FShaderID &id) {
case STENCIL_VALUE_DECR_8BIT: desc.C("StenDecr8 "); break;
default: desc.C("StenUnknown "); break;
}
} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
} else if (Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
desc.C("StenOff ");
}
if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc.C("AlphaTest0 ").W(alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)]).C(" ");
else if (id.Bit(FS_BIT_ALPHA_TEST)) desc.C("AlphaTest ").W(alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)]).C(" ");
if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc.C("ColorTest0 ").W(alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)]).C(" "); // first 4 match;
else if (id.Bit(FS_BIT_COLOR_TEST)) desc.C("ColorTest ").W(alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)]).C(" "); // first 4 match
if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc.C("TestDiscardToZero ");
if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc.C("StencilDiscardWorkaround ");
int logicMode = id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4);
if ((logicMode != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc.C("RLogic(").W(logicFuncs[logicMode]).C(")");
if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc.C("TexArray ");
if (id.Bit(FS_BIT_STEREO)) desc.C("Stereo ");
if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc.C("(fetch)");
if (id.Bit(FS_BIT_MINMAX_DISCARD)) desc.C("FragMinMaxDiscard ");
if (id.Bit(FS_BIT_DEPTH_CLAMP)) desc.C("FragDepthClamp ");
if (Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc.C("AlphaTest0 ").W(alphaTestFuncs[Bits(FS_BIT_ALPHA_TEST_FUNC, 3)]).C(" ");
else if (Bit(FS_BIT_ALPHA_TEST)) desc.C("AlphaTest ").W(alphaTestFuncs[Bits(FS_BIT_ALPHA_TEST_FUNC, 3)]).C(" ");
if (Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc.C("ColorTest0 ").W(alphaTestFuncs[Bits(FS_BIT_COLOR_TEST_FUNC, 2)]).C(" "); // first 4 match;
else if (Bit(FS_BIT_COLOR_TEST)) desc.C("ColorTest ").W(alphaTestFuncs[Bits(FS_BIT_COLOR_TEST_FUNC, 2)]).C(" "); // first 4 match
if (Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc.C("TestDiscardToZero ");
if (Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc.C("StencilDiscardWorkaround ");
int logicMode = Bits(FS_BIT_REPLACE_LOGIC_OP, 4);
if ((logicMode != GE_LOGIC_COPY) && !Bit(FS_BIT_CLEARMODE)) desc.C("RLogic(").W(logicFuncs[logicMode]).C(")");
if (Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc.C("TexArray ");
if (Bit(FS_BIT_STEREO)) desc.C("Stereo ");
if (Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc.C("(fetch)");
if (Bit(FS_BIT_MINMAX_DISCARD)) desc.C("FragMinMaxDiscard ");
if (Bit(FS_BIT_DEPTH_CLAMP)) desc.C("FragDepthClamp ");
const ShaderDepalMode depalMode = (ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
const ShaderDepalMode depalMode = (ShaderDepalMode)Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
switch (depalMode) {
case ShaderDepalMode::OFF: break;
case ShaderDepalMode::NORMAL: desc.C("Depal(");
{
const GEBufferFormat shaderDepalFormat = (GEBufferFormat)id.Bits(FS_BIT_SHADER_DEPAL_FORMAT, 3);
const GEBufferFormat shaderDepalFormat = (GEBufferFormat)Bits(FS_BIT_SHADER_DEPAL_FORMAT, 3);
desc.W(GeBufferFormatToString(shaderDepalFormat)).C(") ");
break;
}
+9 -4
View File
@@ -205,6 +205,10 @@ struct VShaderID : public ShaderID {
void SetBits(VShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string Description() const;
};
struct FShaderID : public ShaderID {
@@ -230,20 +234,21 @@ struct FShaderID : public ShaderID {
void SetBits(FShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
std::string Description() const;
};
static_assert(sizeof(VShaderID) == sizeof(uint64_t), "VShaderID size mismatch");
static_assert(sizeof(FShaderID) == sizeof(uint64_t), "FShaderID size mismatch");
namespace Draw {
class Bugs;
}
void ComputeVertexShaderID(VShaderID *id, u32 vertType, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const VShaderID &id);
struct ComputedPipelineState;
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs, ClipInfoFlags clipInfoFlags);
std::string FragmentShaderDesc(const FShaderID &id);
// For sanity checking.
bool FragmentIdNeedsFramebufferRead(const FShaderID &id);
+1 -1
View File
@@ -169,7 +169,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
ShaderWriter p(buffer, compat, ShaderStage::Vertex, extensions);
p.F("// %s\n", VertexShaderDesc(id).c_str());
p.C("// %").W(id.Description()).endl();
bool lmode = id.Bit(VS_BIT_LMODE);
+2 -2
View File
@@ -47,7 +47,7 @@ std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) con
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return FragmentShaderDesc(id_);
return id_.Description();
default:
return "N/A";
}
@@ -69,7 +69,7 @@ std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return VertexShaderDesc(id_);
return id_.Description();
default:
return "N/A";
}
+3 -3
View File
@@ -677,7 +677,7 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) {
return nullptr;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
std::string desc = FragmentShaderDesc(FSID);
std::string desc = FSID.Description();
ShaderDescGLES params{ GL_FRAGMENT_SHADER, 0, uniformMask };
return new Shader(render_, codeBuffer_, desc, params);
}
@@ -695,7 +695,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
return nullptr;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
std::string desc = VertexShaderDesc(VSID);
std::string desc = VSID.Description();
ShaderDescGLES params{ GL_VERTEX_SHADER, attrMask, uniformMask };
params.useHWTransform = useHWTransform;
return new Shader(render_, codeBuffer_, desc, params);
@@ -826,7 +826,7 @@ std::string Shader::GetShaderString(DebugShaderStringType type, ShaderID id) con
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return isFragment_ ? FragmentShaderDesc(FShaderID(id)) : VertexShaderDesc(VShaderID(id));
return isFragment_ ? FShaderID(id).Description() : VShaderID(id).Description();
default:
return "N/A";
}
+10 -10
View File
@@ -301,12 +301,12 @@ void DrawEngineVulkan::Flush() {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
VShaderID vshaderID;
FShaderID fshaderID;
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
_dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, true, 0, framebufferManager_->GetMSAALevel(), false);
shaderManager_->GetShaderIDs(prim, dec_->VertexType(), &vshaderID, &fshaderID, pipelineState_, true, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
_dbg_assert_msg_(vshaderID.Bit(VS_BIT_USE_HW_TRANSFORM) == true, "Bad vshader ID");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, shaderManager_, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshaderID, fshaderID, true, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
ResetAfterSkippedDraw();
@@ -459,12 +459,12 @@ void DrawEngineVulkan::Flush() {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
VShaderID vshaderID;
FShaderID fshaderID;
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshader, fshader, false, 0, framebufferManager_->GetMSAALevel(), false);
shaderManager_->GetShaderIDs(prim, swDec->VertexType(), &vshaderID, &fshaderID, pipelineState_, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
_dbg_assert_msg_(vshaderID.Bit(VS_BIT_USE_HW_TRANSFORM) == false, "Bad vshader ID");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, shaderManager_, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshaderID, fshaderID, false, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
ResetAfterSkippedDraw();
-1
View File
@@ -25,7 +25,6 @@
// * binding 3: Base Uniform Buffer (includes fragment state)
// * binding 4: Light uniform buffer
// * binding 5: Bone uniform buffer
// * binding 6: Tess data storage buffer
//
// All shaders conform to this layout, so they are all compatible with the same descriptor set.
// The format of the various uniform buffers may vary though - vertex shaders that don't skin
+1 -1
View File
@@ -427,7 +427,7 @@ std::vector<std::string> GPU_Vulkan::DebugGetShaderIDs(DebugShaderType type) {
std::string GPU_Vulkan::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
switch (type) {
case SHADER_TYPE_PIPELINE:
return pipelineManager_->DebugGetObjectString(id, type, stringType, shaderManagerVulkan_);
return pipelineManager_->DebugGetObjectString(id, type, stringType);
case SHADER_TYPE_SAMPLER:
return textureCacheVulkan_->DebugGetSamplerString(id, stringType);
default:
+56 -87
View File
@@ -1,12 +1,11 @@
#include <cstring>
#include <memory>
#include <set>
#include <sstream>
#include "Common/Profiler/Profiler.h"
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include "Common/Data/Text/StringWriter.h"
#include "Common/GPU/Vulkan/VulkanContext.h"
#include "GPU/Vulkan/PipelineManagerVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
@@ -30,7 +29,7 @@ PipelineManagerVulkan::~PipelineManagerVulkan() {
// Block on all pipelines to make sure any background compiles are done.
// This is very important to do before we start trying to tear down the shaders - otherwise, we might
// be deleting shaders before queued pipeline creations that use them are performed.
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
pipelines_.Iterate([](const VulkanPipelineKey &key, VulkanPipeline *value) {
if (value->pipeline) {
value->pipeline->BlockUntilCompiled();
}
@@ -186,7 +185,7 @@ static std::string CutFromMain(const std::string &str) {
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
VKRPipelineLayout *layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key,
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask, bool cacheLoad) {
const DecVtxFormat *decFmt, const VulkanVertexShader *vs, const VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask, bool cacheLoad) {
_assert_(fs && vs);
if (!fs || !fs->GetModule()) {
@@ -327,7 +326,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
std::string tag = "game";
#ifdef _DEBUG
tag = FragmentShaderDesc(fs->GetID()) + " VS " + VertexShaderDesc(vs->GetID());
tag = fs->GetID().Description() + " VS " + vs->GetID().Description();
#endif
VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, sampleCount, cacheLoad, tag.c_str());
@@ -343,7 +342,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
return vulkanPipeline;
}
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) {
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, ShaderManagerVulkan *shaderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VShaderID vid, FShaderID fid, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) {
if (!pipelineCache_) {
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
@@ -354,8 +353,8 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
key.raster = rasterKey;
key.useHWTransform = useHwTransform;
key.vShader = vs->GetModule();
key.fShader = fs->GetModule();
key.vid = vid;
key.fid = fid;
key.vtxFmtId = useHwTransform ? decFmt->id : 0;
VulkanPipeline *pipeline;
@@ -363,6 +362,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
return pipeline;
}
const VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(fid);
const VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(vid);
PipelineFlags pipelineFlags = (PipelineFlags)0;
if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) {
pipelineFlags |= PipelineFlags::USES_DISCARD;
@@ -490,7 +492,7 @@ static constexpr const char * blendFactors[19] = {
"INV_SRC1_A",
};
std::string PipelineManagerVulkan::DebugGetObjectString(const std::string &id, DebugShaderType type, DebugShaderStringType stringType, ShaderManagerVulkan *shaderManager) {
std::string PipelineManagerVulkan::DebugGetObjectString(const std::string &id, DebugShaderType type, DebugShaderStringType stringType) {
if (type != SHADER_TYPE_PIPELINE)
return "N/A";
@@ -504,72 +506,71 @@ std::string PipelineManagerVulkan::DebugGetObjectString(const std::string &id, D
_assert_(pipeline != nullptr);
u32 variants = pipeline->GetVariantsBitmask();
std::string keyDescription = pipelineKey.GetDescription(stringType, shaderManager);
std::string keyDescription = pipelineKey.GetDescription(stringType);
return StringFromFormat("%s. v: %08x", keyDescription.c_str(), variants);
}
std::string VulkanPipelineKey::GetRasterStateDesc(bool lineBreaks) const {
std::stringstream str;
str << topologies[raster.topology] << " ";
char temp[512];
StringWriter str(temp);
str.W(topologies[raster.topology]).C(" ");
if (useHWTransform) {
str << "HWX ";
str.C("HWX ");
}
if (vtxFmtId) {
str << "Vfmt(" << StringFromFormat("%08x", vtxFmtId) << ") "; // TODO: Format nicer.
str.F("Vfmt(%08x) ", vtxFmtId); // TODO: Format nicer.
} else {
str << "SWX ";
str.C("SWX ");
}
if (lineBreaks) str << std::endl;
if (lineBreaks) str.endl();
if (raster.blendEnable) {
str << "Blend(C:" << blendOps[raster.blendOpColor] << "/"
<< blendFactors[raster.srcColor] << ":" << blendFactors[raster.destColor] << " ";
str.W("Blend(C:").W(blendOps[raster.blendOpColor]).W("/").W(blendFactors[raster.srcColor]).W(":").W(blendFactors[raster.destColor]).W(" ");
if (raster.blendOpAlpha != VK_BLEND_OP_ADD ||
raster.srcAlpha != VK_BLEND_FACTOR_ONE ||
raster.destAlpha != VK_BLEND_FACTOR_ZERO) {
str << "A:" << blendOps[raster.blendOpAlpha] << "/"
<< blendFactors[raster.srcColor] << ":" << blendFactors[raster.destColor] << " ";
str.C("A:").W(blendOps[raster.blendOpAlpha]).C("/").W(blendFactors[raster.srcColor]).C(":").W(blendFactors[raster.destColor]).W(" ");
}
str << ") ";
if (lineBreaks) str << std::endl;
str.C(") ");
if (lineBreaks) str.endl();
}
if (raster.colorWriteMask != 0xF) {
str << "Mask(";
str.C("Mask(");
for (int i = 0; i < 4; i++) {
if (raster.colorWriteMask & (1 << i)) {
str << "RGBA"[i];
str.F("%c", "RGBA"[i]);
} else {
str << "_";
str.C("_");
}
}
str << ") ";
if (lineBreaks) str << std::endl;
str.C(") ");
if (lineBreaks) str.endl();
}
if (raster.depthTestEnable) {
str << "Z(";
str.C("Z(");
if (raster.depthWriteEnable)
str << "W, ";
str.C("W, ");
if (raster.depthCompareOp)
str << compareOps[raster.depthCompareOp & 7];
str << ") ";
if (lineBreaks) str << std::endl;
str.W(compareOps[raster.depthCompareOp & 7]);
str.C(") ");
if (lineBreaks) str.endl();
}
if (raster.stencilTestEnable) {
str << "Stenc(";
str << compareOps[raster.stencilCompareOp & 7] << " ";
str << stencilOps[raster.stencilPassOp & 7] << "/";
str << stencilOps[raster.stencilFailOp & 7] << "/";
str << stencilOps[raster.stencilDepthFailOp & 7];
str << ") ";
if (lineBreaks) str << std::endl;
str.C("Stenc(");
str.W(compareOps[raster.stencilCompareOp & 7]).C(" ");
str.W(stencilOps[raster.stencilPassOp & 7]).C("/");
str.W(stencilOps[raster.stencilFailOp & 7]).C("/");
str.W(stencilOps[raster.stencilDepthFailOp & 7]);
str.C(") ");
if (lineBreaks) str.endl();
}
if (raster.logicOpEnable) {
str << "Logic(" << logicOps[raster.logicOp & 15] << ") ";
if (lineBreaks) str << std::endl;
str.C("Logic(").W(logicOps[raster.logicOp & 15]).C(") ");
if (lineBreaks) str.endl();
}
return str.str();
return str.as_string();
}
std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType, ShaderManagerVulkan *shaderManager) const {
std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType) const {
switch (stringType) {
case SHADER_STRING_SHORT_DESC:
// Just show the raster state. Also show brief VS/FS IDs?
@@ -577,15 +578,11 @@ std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType,
case SHADER_STRING_SOURCE_CODE:
{
// More detailed description of all the parts of the pipeline.
VkShaderModule fsModule = this->fShader->BlockUntilReady();
VkShaderModule vsModule = this->vShader->BlockUntilReady();
std::stringstream str;
str << "VS: " << VertexShaderDesc(shaderManager->GetVertexShaderFromModule(vsModule)->GetID()) << std::endl;
str << "FS: " << FragmentShaderDesc(shaderManager->GetFragmentShaderFromModule(fsModule)->GetID()) << std::endl;
str << GetRasterStateDesc(true);
return str.str();
std::string str;
str += "VS: " + vid.Description() + "\n";
str += "FS: " + fid.Description() + "\n";
str += GetRasterStateDesc(true);
return str;
}
default:
@@ -645,28 +642,18 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
int64_t seekPosOnFailure = File::Ftell(file);
bool failed = false;
bool writeFailed = false;
// Since we don't include the full pipeline key, there can be duplicates,
// caused by things like switching from buffered to non-buffered rendering.
// Make sure the set of pipelines we write is "unique".
std::set<StoredVulkanPipelineKey> keys;
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
if (failed)
return;
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader->BlockUntilReady());
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader->BlockUntilReady());
if (!vshader || !fshader) {
failed = true;
return;
}
pipelines_.Iterate([&keys](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
_dbg_assert_(pkey.raster.topology != VK_PRIMITIVE_TOPOLOGY_POINT_LIST && pkey.raster.topology != VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
StoredVulkanPipelineKey key{};
key.raster = pkey.raster;
key.useHWTransform = pkey.useHWTransform;
key.fShaderID = fshader->GetID();
key.vShaderID = vshader->GetID();
key.fShaderID = pkey.fid;
key.vShaderID = pkey.vid;
key.gShaderID = {};
key.variants = value->GetVariantsBitmask();
if (key.useHWTransform) {
@@ -678,29 +665,14 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
// Write the number of pipelines.
size = (uint32_t)keys.size();
writeFailed = writeFailed || fwrite(&size, sizeof(size), 1, file) != 1;
fwrite(&size, sizeof(size), 1, file);
// Write the pipelines.
for (auto &key : keys) {
writeFailed = writeFailed || fwrite(&key, sizeof(key), 1, file) != 1;
fwrite(&key, sizeof(key), 1, file);
}
if (failed) {
ERROR_LOG(Log::G3D, "Failed to write pipeline cache, some shader was missing");
// Write a zero in the right place so it doesn't try to load the pipelines next time.
size = 0;
File::Fseek(file, seekPosOnFailure, SEEK_SET);
writeFailed = fwrite(&size, sizeof(size), 1, file) != 1;
if (writeFailed) {
ERROR_LOG(Log::G3D, "Failed to write pipeline cache, disk full?");
}
return;
}
if (writeFailed) {
ERROR_LOG(Log::G3D, "Failed to write pipeline cache, disk full?");
} else {
NOTICE_LOG(Log::G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size());
}
NOTICE_LOG(Log::G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size());
}
bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VKRPipelineLayout *layout, int multiSampleLevel) {
@@ -780,9 +752,6 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa
continue;
}
VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID);
VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID);
// Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination.
// Note that variantsToBuild is NOT directly a RenderPassType! instead, it's a collection of (1 << RenderPassType).
u32 variantsToBuild = key.variants;
@@ -797,7 +766,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa
DecVtxFormat fmt;
fmt.InitializeFromID(key.vtxFmtId);
VulkanPipeline *pipeline = GetOrCreatePipeline(
rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, key.useHWTransform, variantsToBuild, multiSampleLevel, true);
rm, shaderManager, layout, key.raster, key.useHWTransform ? &fmt : 0, key.vShaderID, key.fShaderID, key.useHWTransform, variantsToBuild, multiSampleLevel, true);
if (!pipeline) {
pipelineCreateFailCount += 1;
}
+6 -7
View File
@@ -43,9 +43,8 @@ class DrawEngineCommon;
struct VulkanPipelineKey {
VulkanPipelineRasterStateKey raster; // prim is included here
VKRRenderPass *renderPass;
Promise<VkShaderModule> *vShader;
Promise<VkShaderModule> *fShader;
VShaderID vid;
FShaderID fid;
uint32_t vtxFmtId;
bool useHWTransform;
@@ -56,7 +55,7 @@ struct VulkanPipelineKey {
void FromString(const std::string &str) {
memcpy(this, &str[0], sizeof(*this));
}
std::string GetDescription(DebugShaderStringType stringType, ShaderManagerVulkan *shaderManager) const;
std::string GetDescription(DebugShaderStringType stringType) const;
private:
std::string GetRasterStateDesc(bool lineBreaks) const;
@@ -87,8 +86,8 @@ public:
~PipelineManagerVulkan();
// variantMask is only used when loading pipelines from cache.
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt,
VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad);
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, ShaderManagerVulkan *shaderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt,
VShaderID vid, FShaderID fid, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad);
int GetNumPipelines() const { return (int)pipelines_.size(); }
void Clear();
@@ -98,7 +97,7 @@ public:
void InvalidateMSAAPipelines();
std::string DebugGetObjectString(const std::string &id, DebugShaderType type, DebugShaderStringType stringType, ShaderManagerVulkan *shaderManager);
std::string DebugGetObjectString(const std::string &id, DebugShaderType type, DebugShaderStringType stringType);
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type) const;
// Saves data for faster creation next time.
+54 -75
View File
@@ -106,7 +106,7 @@ VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, FShaderID id,
: vulkan_(vulkan), id_(id), flags_(flags) {
_assert_(!id.is_invalid());
source_ = code;
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, source_.c_str(), new std::string(FragmentShaderDesc(id)));
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, source_.c_str(), new std::string(id.Description()));
VERBOSE_LOG(Log::G3D, "Compiled fragment shader:\n%s\n", (const char *)code);
}
@@ -127,7 +127,7 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return FragmentShaderDesc(id_);
return id_.Description();
default:
return "N/A";
}
@@ -137,7 +137,7 @@ VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, Vert
: vulkan_(vulkan), useHWTransform_(useHWTransform), flags_(flags), id_(id) {
_assert_(!id.is_invalid());
source_ = code;
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(VertexShaderDesc(id)));
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(id.Description()));
VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code);
}
@@ -158,7 +158,7 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return VertexShaderDesc(id_);
return id_.Description();
default:
return "N/A";
}
@@ -208,8 +208,6 @@ void ShaderManagerVulkan::Clear() {
vsCache_.Clear();
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastVShader_ = nullptr;
lastFShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
@@ -223,8 +221,6 @@ void ShaderManagerVulkan::DirtyLastShader() {
// Forget the last shader ID
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastVShader_ = nullptr;
lastFShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
@@ -242,70 +238,75 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
const VulkanVertexShader *ShaderManagerVulkan::GetVertexShaderFromID(VShaderID VSID) {
VulkanVertexShader *vs = vsCache_.GetOrNull(VSID);
if (vs) {
return vs;
}
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
// Vertex shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
uint32_t attributeMask = 0; // Not used
VertexShaderFlags flags{};
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
const bool useHWTransform = VSID.Bit(VS_BIT_USE_HW_TRANSFORM);
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
return vs;
}
const VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromID(FShaderID FSID) {
VulkanFragmentShader *fs = fsCache_.GetOrNull(FSID);
if (fs) {
return fs;
}
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
// Fragment shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
FragmentShaderFlags flags{};
bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
return fs;
}
void ShaderManagerVulkan::GetShaderIDs(int prim, u32 vertexType, VShaderID *vshader, FShaderID *fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
VShaderID VSID;
VulkanVertexShader *vs = nullptr;
bool recomputedVS = false;
bool recomputedFS = false;
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
recomputedVS = true;
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, weightsAsFloat, useSkinInDecode, clipInfoFlags);
if (VSID == lastVSID_) {
_dbg_assert_(lastVShader_ != nullptr);
vs = lastVShader_;
} else if (!vsCache_.Get(VSID, &vs)) {
// Vertex shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
uint32_t attributeMask = 0; // Not used
VertexShaderFlags flags{};
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
// Don't need to re-lookup anymore, now that we lock wider.
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
lastVShader_ = vs;
lastVSID_ = VSID;
*vshader = VSID;
recomputedVS = true;
} else {
VSID = lastVSID_;
vs = lastVShader_;
*vshader = lastVSID_;
}
*vshader = vs;
FShaderID FSID;
VulkanFragmentShader *fs = nullptr;
bool recomputedFS = false;
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), clipInfoFlags);
recomputedFS = true;
if (FSID == lastFSID_) {
_dbg_assert_(lastFShader_ != nullptr);
fs = lastFShader_;
} else if (!fsCache_.Get(FSID, &fs)) {
// Fragment shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
FragmentShaderFlags flags{};
bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
}
lastFShader_ = fs;
lastFSID_ = FSID;
*fshader = FSID;
recomputedFS = true;
} else {
FSID = lastFSID_;
fs = lastFShader_;
*fshader = lastFSID_;
}
*fshader = fs;
// If you hit these, look at recomputedVS and recomputedFS to determine if it's a dirty-flag problem
// or an ID generation problem (if any of them are false, it's a dirty-flag problem).
@@ -314,7 +315,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShade
_dbg_assert_(FSID.Bit(FS_BIT_MINMAX_DISCARD) == VSID.Bit(VS_BIT_FS_MINMAX_DISCARD));
_dbg_assert_(FSID.Bit(FS_BIT_DEPTH_CLAMP) == VSID.Bit(VS_BIT_FS_DEPTH_CLAMP));
_dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed");
_dbg_assert_msg_(VSID.Bit(VS_BIT_USE_HW_TRANSFORM) == useHWTransform, "Bad vshader ID was computed");
}
std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) {
@@ -364,28 +365,6 @@ std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShade
}
}
VulkanVertexShader *ShaderManagerVulkan::GetVertexShaderFromModule(VkShaderModule module) {
VulkanVertexShader *vs = nullptr;
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *shader) {
Promise<VkShaderModule> *p = shader->GetModule();
VkShaderModule m = p->BlockUntilReady();
if (m == module)
vs = shader;
});
return vs;
}
VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderModule module) {
VulkanFragmentShader *fs = nullptr;
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *shader) {
Promise<VkShaderModule> *p = shader->GetModule();
VkShaderModule m = p->BlockUntilReady();
if (m == module)
fs = shader;
});
return fs;
}
// Shader cache.
//
// We simply store the IDs of the shaders used during gameplay. On next startup of
+5 -13
View File
@@ -46,7 +46,7 @@ public:
const std::string &source() const { return source_; }
std::string GetShaderString(DebugShaderStringType type) const;
Promise<VkShaderModule> *GetModule() { return module_; }
Promise<VkShaderModule> *GetModule() const { return module_; }
const FShaderID &GetID() const { return id_; }
FragmentShaderFlags Flags() const { return flags_; }
@@ -72,7 +72,7 @@ public:
VertexShaderFlags Flags() const { return flags_; }
std::string GetShaderString(DebugShaderStringType type) const;
Promise<VkShaderModule> *GetModule() { return module_; }
Promise<VkShaderModule> *GetModule() const { return module_; }
const VShaderID &GetID() const { return id_; }
protected:
@@ -102,19 +102,15 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void GetShaderIDs(int prim, u32 vertexType, VShaderID *vshader, FShaderID *fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void ClearShaders() override;
void DirtyLastShader() override;
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
// Used for saving/loading the cache. Don't need to be particularly fast.
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { return vsCache_.GetOrNull(id); }
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { return fsCache_.GetOrNull(id); }
VulkanVertexShader *GetVertexShaderFromModule(VkShaderModule module);
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
const VulkanVertexShader *GetVertexShaderFromID(VShaderID VSID);
const VulkanFragmentShader *GetFragmentShaderFromID(FShaderID FSID);
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type) override;
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
@@ -158,10 +154,6 @@ private:
uint64_t uboAlignment_;
Uniforms *uniforms_;
VulkanFragmentShader *lastFShader_ = nullptr;
VulkanVertexShader *lastVShader_ = nullptr;
FShaderID lastFSID_;
VShaderID lastVSID_;
};