Vulkan: Fix bug where we ended up creating duplicate pipelines even if vertices decoded to the same format, if they were created from different formats.
This can cut down the number of pipelines to a third or less in some games. However, benefit is likely smaller since Vulkan drivers will deduplicate shaders inside each vkPipelineCache object. Helps #10106 while not actually implementing any of the suggestions inside.
This commit is contained in:
parent
0f10014219
commit
3e749a94ce
8 changed files with 21 additions and 40 deletions
|
@ -73,13 +73,15 @@ int DecFmtSize(u8 fmt) {
|
|||
case DEC_U16_2: return 4;
|
||||
case DEC_U16_3: return 8;
|
||||
case DEC_U16_4: return 8;
|
||||
case DEC_U8A_2: return 4;
|
||||
case DEC_U16A_2: return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DecVtxFormat::ComputeID() {
|
||||
id = w0fmt | (w1fmt << 4) | (uvfmt << 8) | (c0fmt << 12) | (c1fmt << 16) | (nrmfmt << 20) | (posfmt << 24);
|
||||
}
|
||||
|
||||
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
|
||||
// Find index bounds. Could cache this in display lists.
|
||||
// Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck.
|
||||
|
@ -1152,6 +1154,8 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options,
|
|||
|
||||
decFmt.stride = decOff;
|
||||
|
||||
decFmt.ComputeID();
|
||||
|
||||
size = align(size, biggest);
|
||||
onesize_ = size;
|
||||
size *= morphcount;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
// Can write code to easily bind these using OpenGL, or read these manually.
|
||||
// No morph support, that is taken care of by the VertexDecoder.
|
||||
|
||||
// Keep this in 4 bits.
|
||||
enum {
|
||||
DEC_NONE,
|
||||
DEC_FLOAT_1,
|
||||
|
@ -59,8 +60,6 @@ enum {
|
|||
DEC_U16_2,
|
||||
DEC_U16_3,
|
||||
DEC_U16_4,
|
||||
DEC_U8A_2,
|
||||
DEC_U16A_2,
|
||||
};
|
||||
|
||||
int DecFmtSize(u8 fmt);
|
||||
|
@ -74,6 +73,9 @@ struct DecVtxFormat {
|
|||
u8 nrmfmt; u8 nrmoff;
|
||||
u8 posfmt; u8 posoff;
|
||||
short stride;
|
||||
|
||||
uint32_t id;
|
||||
void ComputeID();
|
||||
};
|
||||
|
||||
struct TransformedVertex
|
||||
|
@ -297,21 +299,6 @@ public:
|
|||
}
|
||||
break;
|
||||
|
||||
case DEC_U8A_2:
|
||||
{
|
||||
const u8 *b = (const u8 *)(data_ + decFmt_.uvoff);
|
||||
uv[0] = (float)b[0];
|
||||
uv[1] = (float)b[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case DEC_U16A_2:
|
||||
{
|
||||
const u16 *p = (const u16 *)(data_ + decFmt_.uvoff);
|
||||
uv[0] = (float)p[0];
|
||||
uv[1] = (float)p[1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG_REPORT_ONCE(fmtuv, G3D, "Reader: Unsupported UV Format %d", decFmt_.uvfmt);
|
||||
memset(uv, 0, sizeof(float) * 2);
|
||||
|
|
|
@ -175,8 +175,6 @@ static const DeclTypeInfo VComp[] = {
|
|||
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
|
||||
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
|
||||
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
|
||||
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U8A_2"}, // DEC_U8A_2,
|
||||
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16A_2" }, // DEC_U16A_2,
|
||||
};
|
||||
|
||||
static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, u8 offset, const char *semantic, u8 semantic_index = 0) {
|
||||
|
|
|
@ -155,9 +155,6 @@ static const DeclTypeInfo VComp[] = {
|
|||
{0, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
|
||||
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
|
||||
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
|
||||
// Not supported in regular DX9 so faking, will cause graphics bugs until worked around
|
||||
{0,"UNUSED_DEC_U8A_2"}, // DEC_U8A_2,
|
||||
{0,"UNUSED_DEC_U16A_2" }, // DEC_U16A_2,
|
||||
};
|
||||
|
||||
static void VertexAttribSetup(D3DVERTEXELEMENT9 * VertexElement, u8 fmt, u8 offset, u8 usage, u8 usage_index = 0) {
|
||||
|
|
|
@ -228,8 +228,6 @@ static const GlTypeInfo GLComp[] = {
|
|||
{GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2,
|
||||
{GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3,
|
||||
{GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4,
|
||||
{GL_UNSIGNED_BYTE, 2, GL_FALSE},// DEC_U8A_2,
|
||||
{GL_UNSIGNED_SHORT, 2, GL_FALSE},// DEC_U16A_2,
|
||||
};
|
||||
|
||||
static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) {
|
||||
|
|
|
@ -887,7 +887,7 @@ void DrawEngineVulkan::DoFlush() {
|
|||
}
|
||||
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
|
||||
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true);
|
||||
if (!pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
|
@ -985,7 +985,7 @@ void DrawEngineVulkan::DoFlush() {
|
|||
}
|
||||
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
|
||||
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false);
|
||||
if (!pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
|
|
|
@ -66,9 +66,6 @@ static const DeclTypeInfo VComp[] = {
|
|||
{ VK_FORMAT_R16G16_UNORM, "R16G16_UNORM" }, // DEC_U16_2,
|
||||
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_3,
|
||||
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_4,
|
||||
|
||||
{ VK_FORMAT_R8G8_UINT, "R8G8_UINT" }, // DEC_U8A_2,
|
||||
{ VK_FORMAT_R16G16_UINT, "R16G16_UINT" }, // DEC_U16A_2,
|
||||
};
|
||||
|
||||
static void VertexAttribSetup(VkVertexInputAttributeDescription *attr, int fmt, int offset, PspAttributeLocation location) {
|
||||
|
@ -121,7 +118,7 @@ static bool UsesBlendConstant(int factor) {
|
|||
|
||||
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache,
|
||||
VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key,
|
||||
const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) {
|
||||
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) {
|
||||
bool useBlendConstant = false;
|
||||
|
||||
VkPipelineColorBlendAttachmentState blend0 = {};
|
||||
|
@ -229,10 +226,10 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
|||
VkVertexInputAttributeDescription attrs[8];
|
||||
int attributeCount;
|
||||
if (useHwTransform) {
|
||||
attributeCount = SetupVertexAttribs(attrs, vtxDec->decFmt);
|
||||
vertexStride = vtxDec->decFmt.stride;
|
||||
attributeCount = SetupVertexAttribs(attrs, *decFmt);
|
||||
vertexStride = decFmt->stride;
|
||||
} else {
|
||||
attributeCount = SetupVertexAttribsPretransformed(attrs, vtxDec->decFmt);
|
||||
attributeCount = SetupVertexAttribsPretransformed(attrs, *decFmt);
|
||||
vertexStride = 36;
|
||||
}
|
||||
|
||||
|
@ -301,7 +298,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
|||
return vulkanPipeline;
|
||||
}
|
||||
|
||||
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||
VulkanPipelineKey key;
|
||||
if (!renderPass)
|
||||
Crash();
|
||||
|
@ -311,7 +308,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
|
|||
key.useHWTransform = useHwTransform;
|
||||
key.vShader = vs->GetModule();
|
||||
key.fShader = fs->GetModule();
|
||||
key.vtxDec = useHwTransform ? vtxDec : nullptr;
|
||||
key.vtxDecId = useHwTransform ? decFmt->id : 0;
|
||||
|
||||
auto iter = pipelines_.Get(key);
|
||||
if (iter)
|
||||
|
@ -321,7 +318,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
|
|||
|
||||
VulkanPipeline *pipeline = CreateVulkanPipeline(
|
||||
vulkan_->GetDevice(), pipelineCache_, layout, renderPass,
|
||||
rasterKey, vtxDec, vs, fs, useHwTransform, lineWidth_);
|
||||
rasterKey, decFmt, vs, fs, useHwTransform, lineWidth_);
|
||||
// Even if the result is nullptr, insert it so we don't try to create it repeatedly.
|
||||
pipelines_.Insert(key, pipeline);
|
||||
return pipeline;
|
||||
|
|
|
@ -41,7 +41,7 @@ struct VulkanPipelineKey {
|
|||
VulkanPipelineRasterStateKey raster; // prim is included here
|
||||
VkRenderPass renderPass;
|
||||
bool useHWTransform;
|
||||
const VertexDecoder *vtxDec;
|
||||
uint32_t vtxDecId;
|
||||
VkShaderModule vShader;
|
||||
VkShaderModule fShader;
|
||||
|
||||
|
@ -77,7 +77,7 @@ public:
|
|||
PipelineManagerVulkan(VulkanContext *ctx);
|
||||
~PipelineManagerVulkan();
|
||||
|
||||
VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
|
||||
VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
|
||||
int GetNumPipelines() const { return (int)pipelines_.size(); }
|
||||
|
||||
void Clear();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue