Vulkan: Add geometry shader ID tracking.

We're still not generating them, yet.  But this tracks the objects and
IDs through the pipeline.
This commit is contained in:
Unknown W. Brackets 2022-10-01 20:01:23 -07:00
parent 38e16324f0
commit d16caa71af
13 changed files with 241 additions and 24 deletions

View file

@ -30,8 +30,9 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
// Fill in the last part of the desc since now it's time to block.
VkShaderModule vs = desc->vertexShader->BlockUntilReady();
VkShaderModule fs = desc->fragmentShader->BlockUntilReady();
VkShaderModule gs = desc->geometryShader ? desc->geometryShader->BlockUntilReady() : VK_NULL_HANDLE;
if (!vs || !fs) {
if (!vs || !fs || (!gs && desc->geometryShader)) {
ERROR_LOG(G3D, "Failed creating graphics pipeline - missing shader modules");
// We're kinda screwed here?
return false;
@ -49,6 +50,14 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
ss[1].pSpecializationInfo = nullptr;
ss[1].module = fs;
ss[1].pName = "main";
if (gs) {
stageCount++;
ss[2].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
ss[2].stage = VK_SHADER_STAGE_GEOMETRY_BIT;
ss[2].pSpecializationInfo = nullptr;
ss[2].module = gs;
ss[2].pName = "main";
}
VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
pipe.pStages = ss;

View file

@ -128,6 +128,7 @@ struct VKRGraphicsPipelineDesc {
// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
Promise<VkShaderModule> *vertexShader = nullptr;
Promise<VkShaderModule> *fragmentShader = nullptr;
Promise<VkShaderModule> *geometryShader = nullptr;
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
VkVertexInputAttributeDescription attrs[8]{};

View file

@ -366,3 +366,42 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
*id_out = id;
}
std::string GeometryShaderDesc(const GShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(GS_BIT_ENABLED)) desc << "ENABLED ";
if (id.Bit(GS_BIT_DO_TEXTURE)) desc << "TEX ";
if (id.Bit(GS_BIT_LMODE)) desc << "LMODE ";
return desc.str();
}
void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim) {
GShaderID id;
bool vertexRangeCulling =
!gstate.isModeThrough() && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692
// If we're not using GS culling, return a zero ID.
// Also, only use this for triangle primitives.
if (!vertexRangeCulling || !gstate_c.Supports(GPU_SUPPORTS_GS_CULLING) || (prim != GE_PRIM_TRIANGLES && prim != GE_PRIM_TRIANGLE_FAN && prim != GE_PRIM_TRIANGLE_STRIP)) {
*id_out = id;
return;
}
id.SetBit(GS_BIT_ENABLED, true);
if (gstate.isModeClear()) {
// No attribute bits.
} else {
bool isModeThrough = gstate.isModeThrough();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
id.SetBit(GS_BIT_LMODE, lmode);
if (gstate.isTextureMapEnabled()) {
id.SetBit(GS_BIT_DO_TEXTURE);
}
}
*id_out = id;
}

View file

@ -104,6 +104,17 @@ static inline FShaderBit operator +(FShaderBit bit, int i) {
return FShaderBit((int)bit + i);
}
// Some of these bits are straight from FShaderBit, since they essentially enable attributes directly.
enum GShaderBit : uint8_t {
GS_BIT_ENABLED = 0, // If not set, we don't use a geo shader.
GS_BIT_DO_TEXTURE = 1, // presence of texcoords
GS_BIT_LMODE = 2, // presence of specular color (regular color always present)
};
static inline GShaderBit operator +(GShaderBit bit, int i) {
return GShaderBit((int)bit + i);
}
struct ShaderID {
ShaderID() {
clear();
@ -232,6 +243,31 @@ struct FShaderID : ShaderID {
}
};
struct GShaderID : ShaderID {
GShaderID() : ShaderID() {
}
explicit GShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(GShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(GShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(GShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(GShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
namespace Draw {
class Bugs;
}
@ -244,3 +280,6 @@ std::string VertexShaderDesc(const VShaderID &id);
struct ComputedPipelineState;
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs);
std::string FragmentShaderDesc(const FShaderID &id);
void ComputeGeometryShaderID(GShaderID *id, const Draw::Bugs &bugs, int prim);
std::string GeometryShaderDesc(const GShaderID &id);

View file

@ -486,7 +486,8 @@ enum {
// Free bit: 15
GPU_SUPPORTS_DEPTH_TEXTURE = FLAG_BIT(16),
GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17),
// Free bits: 18-19
GPU_SUPPORTS_GS_CULLING = FLAG_BIT(18), // Geometry shader
// Free bit: 19
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21),
GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22),

View file

@ -89,8 +89,6 @@ DrawEngineVulkan::DrawEngineVulkan(Draw::DrawContext *draw)
decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
indexGen.Setup(decIndex);
InitDeviceObjects();
}
void DrawEngineVulkan::InitDeviceObjects() {
@ -114,6 +112,8 @@ void DrawEngineVulkan::InitDeviceObjects() {
bindings[3].descriptorCount = 1;
bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
if (gstate_c.Supports(GPU_SUPPORTS_GS_CULLING))
bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
bindings[3].binding = DRAW_BINDING_DYNUBO_BASE;
bindings[4].descriptorCount = 1;
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
@ -581,6 +581,7 @@ void DrawEngineVulkan::DoFlush() {
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
uint32_t ibOffset;
uint32_t vbOffset;
@ -775,14 +776,14 @@ void DrawEngineVulkan::DoFlush() {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform
if (!vshader) {
// We're screwed.
return;
}
_dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, true, 0);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
return;
@ -905,9 +906,9 @@ void DrawEngineVulkan::DoFlush() {
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, false, 0);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
decodedVerts_ = 0;

View file

@ -127,6 +127,9 @@ public:
DrawEngineVulkan(Draw::DrawContext *draw);
virtual ~DrawEngineVulkan();
// We reference feature flags, so this is called after construction.
void InitDeviceObjects();
void SetShaderManager(ShaderManagerVulkan *shaderManager) {
shaderManager_ = shaderManager;
}
@ -196,7 +199,6 @@ private:
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
void BindShaderBlendTex();
void InitDeviceObjects();
void DestroyDeviceObjects();
void DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf);

View file

@ -53,6 +53,7 @@
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
: GPUCommon(gfxCtx, draw), drawEngine_(draw) {
gstate_c.featureFlags = CheckGPUFeatures();
drawEngine_.InitDeviceObjects();
VulkanContext *vulkan = (VulkanContext *)gfxCtx->GetAPIContext();

View file

@ -171,7 +171,7 @@ static std::string CutFromMain(std::string str) {
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key,
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask) {
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) {
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc;
desc->pipelineCache = pipelineCache;
@ -254,6 +254,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
desc->fragmentShader = fs->GetModule();
desc->vertexShader = vs->GetModule();
desc->geometryShader = gs ? gs->GetModule() : nullptr;
VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly;
inputAssembly.flags = 0;
@ -301,6 +302,9 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
if (useBlendConstant) {
pipelineFlags |= PipelineFlags::USES_BLEND_CONSTANT;
}
if (gs) {
pipelineFlags |= PipelineFlags::USES_GEOMETRY_SHADER;
}
if (dss.depthTestEnable || dss.stencilTestEnable) {
pipelineFlags |= PipelineFlags::USES_DEPTH_STENCIL;
}
@ -308,7 +312,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
return vulkanPipeline;
}
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask) {
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) {
if (!pipelineCache_) {
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
@ -321,6 +325,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
key.useHWTransform = useHwTransform;
key.vShader = vs->GetModule();
key.fShader = fs->GetModule();
key.gShader = gs ? gs->GetModule() : VK_NULL_HANDLE;
key.vtxFmtId = useHwTransform ? decFmt->id : 0;
auto iter = pipelines_.Get(key);
@ -334,7 +339,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
VulkanPipeline *pipeline = CreateVulkanPipeline(
renderManager, pipelineCache_, layout, pipelineFlags,
rasterKey, decFmt, vs, fs, useHwTransform, variantBitmask);
rasterKey, decFmt, vs, fs, gs, useHwTransform, variantBitmask);
pipelines_.Insert(key, pipeline);
// Don't return placeholder null pipelines.
@ -589,7 +594,13 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
return;
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader->BlockUntilReady());
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader->BlockUntilReady());
if (!vshader || !fshader) {
VulkanGeometryShader *gshader = nullptr;
if (pkey.gShader) {
gshader = shaderManager->GetGeometryShaderFromModule(pkey.gShader->BlockUntilReady());
if (!gshader)
failed = true;
}
if (!vshader || !fshader || failed) {
failed = true;
return;
}
@ -710,7 +721,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
DecVtxFormat fmt;
fmt.InitializeFromID(key.vtxFmtId);
VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, key.useHWTransform, key.variants);
VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, nullptr, key.useHWTransform, key.variants);
if (!pipeline) {
pipelineCreateFailCount += 1;
}

View file

@ -38,6 +38,7 @@ struct VulkanPipelineKey {
VKRRenderPass *renderPass;
Promise<VkShaderModule> *vShader;
Promise<VkShaderModule> *fShader;
Promise<VkShaderModule> *gShader;
uint32_t vtxFmtId;
bool useHWTransform;
@ -68,6 +69,7 @@ struct VulkanPipeline {
class VulkanContext;
class VulkanVertexShader;
class VulkanFragmentShader;
class VulkanGeometryShader;
class ShaderManagerVulkan;
class DrawEngineCommon;
@ -77,7 +79,7 @@ public:
~PipelineManagerVulkan();
// variantMask is only used when loading pipelines from cache.
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantMask);
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask);
int GetNumPipelines() const { return (int)pipelines_.size(); }
void Clear();

View file

@ -163,8 +163,38 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons
}
}
VulkanGeometryShader::VulkanGeometryShader(VulkanContext *vulkan, GShaderID id, const char *code)
: vulkan_(vulkan), id_(id) {
source_ = code;
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_GEOMETRY_BIT, source_.c_str(), new std::string(GeometryShaderDesc(id).c_str()));
if (!module_) {
failed_ = true;
} else {
VERBOSE_LOG(G3D, "Compiled geometry shader:\n%s\n", (const char *)code);
}
}
VulkanGeometryShader::~VulkanGeometryShader() {
if (module_) {
VkShaderModule shaderModule = module_->BlockUntilReady();
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
delete module_;
}
}
std::string VulkanGeometryShader::GetShaderString(DebugShaderStringType type) const {
switch (type) {
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return GeometryShaderDesc(id_);
default:
return "N/A";
}
}
ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw)
: ShaderManagerCommon(draw), compat_(GLSL_VULKAN), fsCache_(16), vsCache_(16) {
: ShaderManagerCommon(draw), compat_(GLSL_VULKAN), fsCache_(16), vsCache_(16), gsCache_(16) {
codeBuffer_ = new char[16384];
VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
uboAlignment_ = vulkan->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment;
@ -199,10 +229,15 @@ void ShaderManagerVulkan::Clear() {
vsCache_.Iterate([&](const VShaderID &key, VulkanVertexShader *shader) {
delete shader;
});
gsCache_.Iterate([&](const GShaderID &key, VulkanGeometryShader *shader) {
delete shader;
});
fsCache_.Clear();
vsCache_.Clear();
gsCache_.Clear();
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastGSID_.set_invalid();
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
}
@ -216,12 +251,14 @@ void ShaderManagerVulkan::DirtyShader() {
// Forget the last shader ID
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastGSID_.set_invalid();
DirtyLastShader();
}
void ShaderManagerVulkan::DirtyLastShader() {
lastVShader_ = nullptr;
lastFShader_ = nullptr;
lastGShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
}
@ -239,7 +276,7 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
@ -256,14 +293,23 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
FSID = lastFSID_;
}
GShaderID GSID;
if (gstate_c.IsDirty(DIRTY_GEOMETRYSHADER_STATE)) {
gstate_c.Clean(DIRTY_GEOMETRYSHADER_STATE);
ComputeGeometryShaderID(&GSID, draw_->GetBugs(), prim);
} else {
GSID = lastGSID_;
}
_dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
_dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
_dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
// Just update uniforms if this is the same shader as last time.
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_ && GSID == lastGSID_) {
*vshader = lastVShader_;
*fshader = lastFShader_;
*gshader = lastGShader_;
_dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was cached");
// Already all set, no need to look up in shader maps.
return;
@ -281,11 +327,9 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
vs = new VulkanVertexShader(vulkan, VSID, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
lastVSID_ = VSID;
VulkanFragmentShader *fs = fsCache_.Get(FSID);
if (!fs) {
// uint32_t vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID;
// Fragment shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
@ -296,13 +340,28 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
fsCache_.Insert(FSID, fs);
}
VulkanGeometryShader *gs;
if (GSID.Bit(GS_BIT_ENABLED)) {
gs = gsCache_.Get(GSID);
if (!gs) {
// Geometry shader not in cache. Let's compile it.
// TODO
}
} else {
gs = nullptr;
}
lastVSID_ = VSID;
lastFSID_ = FSID;
lastGSID_ = GSID;
lastVShader_ = vs;
lastFShader_ = fs;
lastGShader_ = gs;
*vshader = vs;
*fshader = fs;
*gshader = gs;
_dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed");
}
@ -327,6 +386,15 @@ std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType
});
break;
}
case SHADER_TYPE_GEOMETRY:
{
gsCache_.Iterate([&](const GShaderID &id, VulkanGeometryShader *shader) {
std::string idstr;
id.ToString(&idstr);
ids.push_back(idstr);
});
break;
}
default:
break;
}
@ -342,12 +410,16 @@ std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShade
VulkanVertexShader *vs = vsCache_.Get(VShaderID(shaderId));
return vs ? vs->GetShaderString(stringType) : "";
}
case SHADER_TYPE_FRAGMENT:
{
VulkanFragmentShader *fs = fsCache_.Get(FShaderID(shaderId));
return fs ? fs->GetShaderString(stringType) : "";
}
case SHADER_TYPE_GEOMETRY:
{
VulkanGeometryShader *gs = gsCache_.Get(GShaderID(shaderId));
return gs ? gs->GetShaderString(stringType) : "";
}
default:
return "N/A";
}
@ -375,6 +447,17 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM
return fs;
}
VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderModule module) {
VulkanGeometryShader *gs = nullptr;
gsCache_.Iterate([&](const GShaderID &id, VulkanGeometryShader *shader) {
Promise<VkShaderModule> *p = shader->GetModule();
VkShaderModule m = p->BlockUntilReady();
if (m == module)
gs = shader;
});
return gs;
}
// Shader cache.
//
// We simply store the IDs of the shaders used during gameplay. On next startup of

View file

@ -83,7 +83,27 @@ protected:
VShaderID id_;
};
class VulkanPushBuffer;
class VulkanGeometryShader {
public:
VulkanGeometryShader(VulkanContext *vulkan, GShaderID id, const char *code);
~VulkanGeometryShader();
const std::string &source() const { return source_; }
bool Failed() const { return failed_; }
std::string GetShaderString(DebugShaderStringType type) const;
Promise<VkShaderModule> *GetModule() const { return module_; }
const GShaderID &GetID() { return id_; }
protected:
Promise<VkShaderModule> *module_ = nullptr;
VulkanContext *vulkan_;
std::string source_;
bool failed_ = false;
GShaderID id_;
};
class ShaderManagerVulkan : public ShaderManagerCommon {
public:
@ -93,19 +113,22 @@ public:
void DeviceLost();
void DeviceRestore(Draw::DrawContext *draw);
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
void ClearShaders();
void DirtyShader();
void DirtyLastShader() override;
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
int GetNumGeometryShaders() const { return (int)gsCache_.size(); }
// Used for saving/loading the cache. Don't need to be particularly fast.
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { return vsCache_.Get(id); }
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { return fsCache_.Get(id); }
VulkanGeometryShader *GetGeometryShaderFromID(GShaderID id) { return gsCache_.Get(id); }
VulkanVertexShader *GetVertexShaderFromModule(VkShaderModule module);
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
VulkanGeometryShader *GetGeometryShaderFromModule(VkShaderModule module);
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
@ -143,6 +166,9 @@ private:
typedef DenseHashMap<VShaderID, VulkanVertexShader *, nullptr> VSCache;
VSCache vsCache_;
typedef DenseHashMap<GShaderID, VulkanGeometryShader *, nullptr> GSCache;
GSCache gsCache_;
char *codeBuffer_;
uint64_t uboAlignment_;
@ -153,7 +179,9 @@ private:
VulkanFragmentShader *lastFShader_ = nullptr;
VulkanVertexShader *lastVShader_ = nullptr;
VulkanGeometryShader *lastGShader_ = nullptr;
FShaderID lastFSID_;
VShaderID lastVSID_;
GShaderID lastGSID_;
};

View file

@ -1156,7 +1156,7 @@ int ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *
struct { DebugShaderType type; const char *name; } shaderTypes[] = {
{ SHADER_TYPE_VERTEX, "Vertex" },
{ SHADER_TYPE_FRAGMENT, "Fragment" },
// { SHADER_TYPE_GEOMETRY, "Geometry" },
{ SHADER_TYPE_GEOMETRY, "Geometry" },
{ SHADER_TYPE_VERTEXLOADER, "VertexLoader" },
{ SHADER_TYPE_PIPELINE, "Pipeline" },
{ SHADER_TYPE_TEXTURE, "Texture" },