Permalink
Browse files

Vulkan: Fix bug where we ended up creating duplicate pipelines even i…

…f 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.
  • Loading branch information...
hrydgard committed Nov 13, 2017
1 parent 0f10014 commit 3e749a94ce5085cccb5b7cbae57f35f813fb4e33
@@ -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 @@ class VertexReader {
}
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 @@ class PipelineManagerVulkan {
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();

0 comments on commit 3e749a9

Please sign in to comment.