mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
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:
parent
38e16324f0
commit
d16caa71af
13 changed files with 241 additions and 24 deletions
|
@ -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;
|
||||
|
|
|
@ -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]{};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
@ -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" },
|
||||
|
|
Loading…
Add table
Reference in a new issue