Fixes for Vulkan backend after recent changes
This commit is contained in:
@@ -206,47 +206,71 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUVertexLayout*>& layouts)
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference)
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing)
|
||||
{
|
||||
GPUVertexLayout* result = base ? base : reference;
|
||||
if (base && reference && base != reference)
|
||||
{
|
||||
bool anyMissing = false;
|
||||
const Elements& baseElements = base->GetElements();
|
||||
Elements newElements = baseElements;
|
||||
for (const VertexElement& e : reference->GetElements())
|
||||
bool elementsModified = false;
|
||||
Elements newElements = base->GetElements();
|
||||
if (removeUnused)
|
||||
{
|
||||
bool missing = true;
|
||||
for (const VertexElement& ee : baseElements)
|
||||
for (int32 i = newElements.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (ee.Type == e.Type)
|
||||
bool missing = true;
|
||||
const VertexElement& e = newElements.Get()[i];
|
||||
for (const VertexElement& ee : reference->GetElements())
|
||||
{
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
// Insert any missing elements
|
||||
VertexElement ne = { e.Type, e.Slot, 0, e.PerInstance, e.Format };
|
||||
if (e.Type == VertexElement::Types::TexCoord1 || e.Type == VertexElement::Types::TexCoord2 || e.Type == VertexElement::Types::TexCoord3)
|
||||
{
|
||||
// Alias missing texcoords with existing texcoords
|
||||
for (const VertexElement& ee : newElements)
|
||||
if (ee.Type == e.Type)
|
||||
{
|
||||
if (ee.Type == VertexElement::Types::TexCoord0)
|
||||
{
|
||||
ne = ee;
|
||||
ne.Type = e.Type;
|
||||
break;
|
||||
}
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newElements.Add(ne);
|
||||
anyMissing = true;
|
||||
if (missing)
|
||||
{
|
||||
// Remove unused element
|
||||
newElements.RemoveAtKeepOrder(i);
|
||||
elementsModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (anyMissing)
|
||||
if (addMissing)
|
||||
{
|
||||
for (const VertexElement& e : reference->GetElements())
|
||||
{
|
||||
bool missing = true;
|
||||
for (const VertexElement& ee : base->GetElements())
|
||||
{
|
||||
if (ee.Type == e.Type)
|
||||
{
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
// Insert any missing elements
|
||||
VertexElement ne = { e.Type, e.Slot, 0, e.PerInstance, e.Format };
|
||||
if (e.Type == VertexElement::Types::TexCoord1 || e.Type == VertexElement::Types::TexCoord2 || e.Type == VertexElement::Types::TexCoord3)
|
||||
{
|
||||
// Alias missing texcoords with existing texcoords
|
||||
for (const VertexElement& ee : newElements)
|
||||
{
|
||||
if (ee.Type == VertexElement::Types::TexCoord0)
|
||||
{
|
||||
ne = ee;
|
||||
ne.Type = e.Type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
newElements.Add(ne);
|
||||
elementsModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (elementsModified)
|
||||
result = Get(newElements, true);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -74,8 +74,10 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="base">The list of vertex buffers for the layout.</param>
|
||||
/// <param name="reference">The list of reference inputs.</param>
|
||||
/// <param name="removeUnused">True to remove elements from base layout that don't exist in a reference layout.</param>
|
||||
/// <param name="addMissing">True to add missing elements to base layout that exist in a reference layout.</param>
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference);
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true);
|
||||
|
||||
public:
|
||||
// [GPUResource]
|
||||
|
||||
@@ -651,14 +651,14 @@ void GPUContextVulkan::OnDrawCall()
|
||||
}
|
||||
|
||||
// Bind any missing vertex buffers to null if required by the current state
|
||||
GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexShaderLayout;
|
||||
GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexBufferLayout;
|
||||
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
|
||||
if (!vertexLayout && pipelineState && !pipelineState->VertexShaderLayout && (pipelineState->UsedStagesMask & (1 << (int32)DescriptorSet::Vertex)) != 0 && !_vertexLayout && _vbCount)
|
||||
if (!vertexLayout && pipelineState && !pipelineState->VertexBufferLayout && (pipelineState->UsedStagesMask & (1 << (int32)DescriptorSet::Vertex)) != 0 && !_vertexLayout && _vbCount)
|
||||
{
|
||||
LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals.");
|
||||
}
|
||||
#endif
|
||||
const int32 missingVBs = vertexLayout ? (int32)vertexLayout->CreateInfo.vertexBindingDescriptionCount - _vbCount : 0;
|
||||
const int32 missingVBs = vertexLayout ? vertexLayout->MaxSlot + 1 - _vbCount : 0;
|
||||
if (missingVBs > 0)
|
||||
{
|
||||
VkBuffer buffers[GPU_MAX_VB_BINDED];
|
||||
@@ -1034,7 +1034,13 @@ void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
|
||||
void GPUContextVulkan::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout)
|
||||
{
|
||||
_vbCount = vertexBuffers.Length();
|
||||
_vertexLayout = (GPUVertexLayoutVulkan*)(vertexLayout ? vertexLayout : GPUVertexLayout::Get(vertexBuffers));
|
||||
if (!vertexLayout)
|
||||
vertexLayout = GPUVertexLayout::Get(vertexBuffers);
|
||||
if (_vertexLayout != vertexLayout)
|
||||
{
|
||||
_vertexLayout = (GPUVertexLayoutVulkan*)vertexLayout;
|
||||
_psDirtyFlag = true;
|
||||
}
|
||||
if (vertexBuffers.Length() == 0)
|
||||
return;
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
|
||||
@@ -453,39 +453,12 @@ GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elem
|
||||
: GPUResourceVulkan<GPUVertexLayout>(device, StringView::Empty)
|
||||
{
|
||||
SetElements(elements, explicitOffsets);
|
||||
for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
|
||||
{
|
||||
VkVertexInputBindingDescription& binding = Bindings[i];
|
||||
binding.binding = i;
|
||||
binding.stride = 0;
|
||||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
}
|
||||
uint32 bindingsCount = 0;
|
||||
MaxSlot = 0;
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& src = GetElements().Get()[i];
|
||||
const int32 size = PixelFormatExtensions::SizeInBytes(src.Format);
|
||||
|
||||
ASSERT_LOW_LAYER(src.Slot < GPU_MAX_VB_BINDED);
|
||||
VkVertexInputBindingDescription& binding = Bindings[src.Slot];
|
||||
binding.binding = src.Slot;
|
||||
binding.stride = Math::Max(binding.stride, (uint32_t)(src.Offset + size));
|
||||
binding.inputRate = src.PerInstance ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
VkVertexInputAttributeDescription& attribute = Attributes[i];
|
||||
attribute.location = i;
|
||||
attribute.binding = src.Slot;
|
||||
attribute.format = RenderToolsVulkan::ToVulkanFormat(src.Format);
|
||||
attribute.offset = src.Offset;
|
||||
|
||||
bindingsCount = Math::Max(bindingsCount, (uint32)src.Slot + 1);
|
||||
MaxSlot = Math::Max(MaxSlot, (int32)src.Slot);
|
||||
}
|
||||
|
||||
RenderToolsVulkan::ZeroStruct(CreateInfo, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
|
||||
CreateInfo.vertexBindingDescriptionCount = bindingsCount;
|
||||
CreateInfo.pVertexBindingDescriptions = Bindings;
|
||||
CreateInfo.vertexAttributeDescriptionCount = elements.Count();
|
||||
CreateInfo.pVertexAttributeDescriptions = Attributes;
|
||||
}
|
||||
|
||||
FramebufferVulkan::FramebufferVulkan(GPUDeviceVulkan* device, const Key& key, const VkExtent2D& extent, uint32 layers)
|
||||
@@ -936,7 +909,8 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyVertexBuffer()
|
||||
if (!_dummyVB)
|
||||
{
|
||||
_dummyVB = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyVertexBuffer"));
|
||||
_dummyVB->Init(GPUBufferDescription::Vertex(nullptr, sizeof(Color32), 1, &Color32::Transparent));
|
||||
auto* layout = GPUVertexLayout::Get({{ VertexElement::Types::Attribute3, 0, 0, 0, PixelFormat::R8G8B8A8_UNorm }});
|
||||
_dummyVB->Init(GPUBufferDescription::Vertex(layout, sizeof(Color32), 1, &Color32::Transparent));
|
||||
}
|
||||
return _dummyVB;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Pair.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
|
||||
static VkStencilOp ToVulkanStencilOp(const StencilOperation value)
|
||||
{
|
||||
@@ -222,8 +223,54 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer
|
||||
PROFILE_CPU_NAMED("Create Pipeline");
|
||||
|
||||
// Bind vertex input
|
||||
vertexLayout = (GPUVertexLayoutVulkan*)GPUVertexLayout::Merge(vertexLayout, VertexShaderLayout);
|
||||
_desc.pVertexInputState = vertexLayout ? &vertexLayout->CreateInfo : nullptr;
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo;
|
||||
VkVertexInputBindingDescription vertexInputBindings[GPU_MAX_VB_BINDED];
|
||||
VkVertexInputAttributeDescription vertexInputAttributes[GPU_MAX_VS_ELEMENTS];
|
||||
_desc.pVertexInputState = nullptr;
|
||||
if (!vertexLayout)
|
||||
vertexLayout = VertexBufferLayout; // Fallback to shader-specified layout (if using old APIs)
|
||||
if (vertexLayout)
|
||||
{
|
||||
// Vertex bindings based on vertex buffers assigned
|
||||
for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
|
||||
{
|
||||
VkVertexInputBindingDescription& binding = vertexInputBindings[i];
|
||||
binding.binding = i;
|
||||
binding.stride = 0;
|
||||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
}
|
||||
uint32 bindingsCount = 0;
|
||||
for (int32 i = 0; i < vertexLayout->GetElements().Count(); i++)
|
||||
{
|
||||
const VertexElement& src = vertexLayout->GetElements().Get()[i];
|
||||
const int32 size = PixelFormatExtensions::SizeInBytes(src.Format);
|
||||
ASSERT_LOW_LAYER(src.Slot < GPU_MAX_VB_BINDED);
|
||||
VkVertexInputBindingDescription& binding = vertexInputBindings[src.Slot];
|
||||
binding.binding = src.Slot;
|
||||
binding.stride = Math::Max(binding.stride, (uint32_t)(src.Offset + size));
|
||||
binding.inputRate = src.PerInstance ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
bindingsCount = Math::Max(bindingsCount, (uint32)src.Slot + 1);
|
||||
}
|
||||
|
||||
// Vertex elements (including any merged elements from reference layout from shader reflection)
|
||||
vertexLayout = (GPUVertexLayoutVulkan*)GPUVertexLayout::Merge(vertexLayout, VertexInputLayout, true, true);
|
||||
for (int32 i = 0; i < vertexLayout->GetElements().Count(); i++)
|
||||
{
|
||||
const VertexElement& src = vertexLayout->GetElements().Get()[i];
|
||||
VkVertexInputAttributeDescription& attribute = vertexInputAttributes[i];
|
||||
attribute.location = i;
|
||||
attribute.binding = src.Slot;
|
||||
attribute.format = RenderToolsVulkan::ToVulkanFormat(src.Format);
|
||||
attribute.offset = src.Offset;
|
||||
}
|
||||
|
||||
RenderToolsVulkan::ZeroStruct(vertexInputCreateInfo, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
|
||||
vertexInputCreateInfo.vertexBindingDescriptionCount = bindingsCount;
|
||||
vertexInputCreateInfo.pVertexBindingDescriptions = vertexInputBindings;
|
||||
vertexInputCreateInfo.vertexAttributeDescriptionCount = vertexLayout->GetElements().Count();
|
||||
vertexInputCreateInfo.pVertexAttributeDescriptions = vertexInputAttributes;
|
||||
_desc.pVertexInputState = &vertexInputCreateInfo;
|
||||
}
|
||||
|
||||
// Update description to match the pipeline
|
||||
_descColorBlend.attachmentCount = renderPass->Layout.RTsCount;
|
||||
@@ -320,7 +367,11 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
|
||||
_desc.pStages = _shaderStages;
|
||||
|
||||
// Input Assembly
|
||||
VertexShaderLayout = desc.VS ? (GPUVertexLayoutVulkan*)(desc.VS->Layout ? desc.VS->Layout : desc.VS->InputLayout) : nullptr;
|
||||
if (desc.VS)
|
||||
{
|
||||
VertexInputLayout = (GPUVertexLayoutVulkan*)desc.VS->InputLayout;
|
||||
VertexBufferLayout = (GPUVertexLayoutVulkan*)desc.VS->Layout;
|
||||
}
|
||||
RenderToolsVulkan::ZeroStruct(_descInputAssembly, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO);;
|
||||
switch (desc.PrimitiveTopology)
|
||||
{
|
||||
|
||||
@@ -146,7 +146,8 @@ public:
|
||||
|
||||
const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr;
|
||||
TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr;
|
||||
GPUVertexLayoutVulkan* VertexShaderLayout = nullptr;
|
||||
GPUVertexLayoutVulkan* VertexInputLayout = nullptr;
|
||||
GPUVertexLayoutVulkan* VertexBufferLayout = nullptr;
|
||||
Array<VkDescriptorSet> DescriptorSetHandles;
|
||||
Array<uint32> DynamicOffsets;
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@ class GPUVertexLayoutVulkan : public GPUResourceVulkan<GPUVertexLayout>
|
||||
public:
|
||||
GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements, bool explicitOffsets);
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo CreateInfo;
|
||||
VkVertexInputBindingDescription Bindings[GPU_MAX_VB_BINDED];
|
||||
VkVertexInputAttributeDescription Attributes[GPU_MAX_VS_ELEMENTS];
|
||||
int32 MaxSlot;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user