More fixes for Vulkan rendering to be on pair with DirectX when it comes to accessing missing vertex buffer components
This commit is contained in:
@@ -169,15 +169,22 @@ GPUBuffer::GPUBuffer()
|
||||
|
||||
bool GPUBuffer::Init(const GPUBufferDescription& desc)
|
||||
{
|
||||
ASSERT(Math::IsInRange<uint32>(desc.Size, 1, MAX_int32)
|
||||
&& Math::IsInRange<uint32>(desc.Stride, 0, 1024));
|
||||
|
||||
// Validate description
|
||||
#if !BUILD_RELEASE
|
||||
#define GET_NAME() GetName()
|
||||
#else
|
||||
#define GET_NAME() TEXT("")
|
||||
#endif
|
||||
if (Math::IsNotInRange<uint32>(desc.Size, 1, MAX_int32))
|
||||
{
|
||||
LOG(Warning, "Cannot create buffer '{}'. Incorrect size {}.", GET_NAME(), desc.Size);
|
||||
return true;
|
||||
}
|
||||
if (Math::IsNotInRange<uint32>(desc.Stride, 0, 1024))
|
||||
{
|
||||
LOG(Warning, "Cannot create buffer '{}'. Incorrect stride {}.", GET_NAME(), desc.Stride);
|
||||
return true;
|
||||
}
|
||||
if (EnumHasAnyFlags(desc.Flags, GPUBufferFlags::Structured))
|
||||
{
|
||||
if (desc.Stride <= 0)
|
||||
|
||||
@@ -96,12 +96,12 @@ GPUVertexLayout::GPUVertexLayout()
|
||||
|
||||
void GPUVertexLayout::SetElements(const Elements& elements, bool explicitOffsets)
|
||||
{
|
||||
uint32 offsets[GPU_MAX_VB_BINDED] = {};
|
||||
uint32 offsets[GPU_MAX_VB_BINDED + 1] = {};
|
||||
_elements = elements;
|
||||
for (int32 i = 0; i < _elements.Count(); i++)
|
||||
{
|
||||
VertexElement& e = _elements[i];
|
||||
ASSERT(e.Slot < GPU_MAX_VB_BINDED);
|
||||
ASSERT(e.Slot <= GPU_MAX_VB_BINDED); // One special slot after all VBs for any missing vertex elements binding (on Vulkan)
|
||||
uint32& offset = offsets[e.Slot];
|
||||
if (e.Offset != 0 || explicitOffsets)
|
||||
offset = e.Offset;
|
||||
@@ -216,7 +216,7 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUVertexLayout*>& layouts)
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing)
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing, int32 missingSlotOverride)
|
||||
{
|
||||
GPUVertexLayout* result = base ? base : reference;
|
||||
if (base && reference && base != reference)
|
||||
@@ -261,7 +261,7 @@ GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout*
|
||||
if (missing)
|
||||
{
|
||||
// Insert any missing elements
|
||||
VertexElement ne = { e.Type, e.Slot, 0, e.PerInstance, e.Format };
|
||||
VertexElement ne = { e.Type, missingSlotOverride != -1 ? (byte)missingSlotOverride : 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
|
||||
|
||||
@@ -83,8 +83,9 @@ public:
|
||||
/// <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>
|
||||
/// <param name="missingSlotOverride">Allows to override the input slot for missing elements. Use value -1 to inherit slot from the 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, bool removeUnused = false, bool addMissing = true);
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true, int32 missingSlotOverride = -1);
|
||||
|
||||
public:
|
||||
// [GPUResource]
|
||||
|
||||
@@ -529,6 +529,8 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
|
||||
auto handle = handles[slot];
|
||||
if (!handle)
|
||||
{
|
||||
if (descriptor.ResourceFormat == PixelFormat::Unknown)
|
||||
break;
|
||||
const auto dummy = _device->HelperResources.GetDummyBuffer(descriptor.ResourceFormat);
|
||||
handle = (DescriptorOwnerResourceVulkan*)dummy->View()->GetNativePtr();
|
||||
}
|
||||
@@ -650,23 +652,14 @@ void GPUContextVulkan::OnDrawCall()
|
||||
}
|
||||
}
|
||||
|
||||
// Bind any missing vertex buffers to null if required by the current state
|
||||
GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexBufferLayout;
|
||||
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
|
||||
// Check for missing vertex buffers layout
|
||||
GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexBufferLayout;
|
||||
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 ? vertexLayout->MaxSlot + 1 - _vbCount : 0;
|
||||
if (missingVBs > 0)
|
||||
{
|
||||
VkBuffer buffers[GPU_MAX_VB_BINDED];
|
||||
VkDeviceSize offsets[GPU_MAX_VB_BINDED] = {};
|
||||
for (int32 i = 0; i < missingVBs; i++)
|
||||
buffers[i] = _device->HelperResources.GetDummyVertexBuffer()->GetHandle();
|
||||
vkCmdBindVertexBuffers(cmdBuffer->GetHandle(), _vbCount, missingVBs, buffers, offsets);
|
||||
}
|
||||
|
||||
// Start render pass if not during one
|
||||
if (cmdBuffer->IsOutsideRenderPass())
|
||||
@@ -734,6 +727,9 @@ void GPUContextVulkan::FrameBegin()
|
||||
// Init command buffer
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
vkCmdSetStencilReference(cmdBuffer->GetHandle(), VK_STENCIL_FRONT_AND_BACK, _stencilRef);
|
||||
VkBuffer buffers[1] = { _device->HelperResources.GetDummyVertexBuffer()->GetHandle() };
|
||||
VkDeviceSize offsets[1] = {};
|
||||
vkCmdBindVertexBuffers(cmdBuffer->GetHandle(), GPU_MAX_VB_BINDED, 1, buffers, offsets);
|
||||
|
||||
#if VULKAN_RESET_QUERY_POOLS
|
||||
// Reset pending queries
|
||||
|
||||
@@ -499,6 +499,7 @@ RenderPassVulkan::RenderPassVulkan(GPUDeviceVulkan* device, const RenderTargetLa
|
||||
: Device(device)
|
||||
, Handle(VK_NULL_HANDLE)
|
||||
, Layout(layout)
|
||||
, CanDepthWrite(true)
|
||||
{
|
||||
const int32 colorAttachmentsCount = layout.RTsCount;
|
||||
const bool hasDepthStencilAttachment = layout.DepthFormat != PixelFormat::Unknown;
|
||||
@@ -585,6 +586,8 @@ RenderPassVulkan::RenderPassVulkan(GPUDeviceVulkan* device, const RenderTargetLa
|
||||
depthStencilReference.attachment = colorAttachmentsCount;
|
||||
depthStencilReference.layout = depthStencilLayout;
|
||||
subpassDesc.pDepthStencilAttachment = &depthStencilReference;
|
||||
if (!layout.WriteDepth && !layout.WriteStencil)
|
||||
CanDepthWrite = false;
|
||||
}
|
||||
|
||||
VkRenderPassCreateInfo createInfo;
|
||||
|
||||
@@ -239,6 +239,7 @@ public:
|
||||
GPUDeviceVulkan* Device;
|
||||
VkRenderPass Handle;
|
||||
RenderTargetLayoutVulkan Layout;
|
||||
bool CanDepthWrite;
|
||||
#if VULKAN_USE_DEBUG_DATA
|
||||
VkRenderPassCreateInfo DebugCreateInfo;
|
||||
#endif
|
||||
|
||||
@@ -224,7 +224,7 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer
|
||||
|
||||
// Bind vertex input
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo;
|
||||
VkVertexInputBindingDescription vertexInputBindings[GPU_MAX_VB_BINDED];
|
||||
VkVertexInputBindingDescription vertexInputBindings[GPU_MAX_VB_BINDED + 1];
|
||||
VkVertexInputAttributeDescription vertexInputAttributes[GPU_MAX_VS_ELEMENTS];
|
||||
_desc.pVertexInputState = nullptr;
|
||||
if (!vertexLayout)
|
||||
@@ -253,12 +253,33 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer
|
||||
}
|
||||
|
||||
// Vertex elements (including any merged elements from reference layout from shader reflection)
|
||||
vertexLayout = (GPUVertexLayoutVulkan*)GPUVertexLayout::Merge(vertexLayout, VertexInputLayout, true, true);
|
||||
uint32 missingSlotBinding = bindingsCount;
|
||||
int32 missingSlotOverride = GPU_MAX_VB_BINDED; // Use additional slot with empty VB
|
||||
vertexLayout = (GPUVertexLayoutVulkan*)GPUVertexLayout::Merge(vertexLayout, VertexInputLayout, true, true, missingSlotOverride);
|
||||
for (int32 i = 0; i < vertexLayout->GetElements().Count(); i++)
|
||||
{
|
||||
const VertexElement& src = vertexLayout->GetElements().Get()[i];
|
||||
VkVertexInputAttributeDescription& attribute = vertexInputAttributes[i];
|
||||
attribute.location = i;
|
||||
if (VertexInputLayout)
|
||||
{
|
||||
// Sync locations with vertex shader inputs to ensure that shader will load correct attributes
|
||||
const auto& vertexInputLayoutElements = VertexInputLayout->GetElements();
|
||||
for (int32 j = 0; j < vertexInputLayoutElements.Count(); j++)
|
||||
{
|
||||
if (vertexInputLayoutElements.Get()[j].Type == src.Type)
|
||||
{
|
||||
attribute.location = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.Slot == missingSlotOverride)
|
||||
{
|
||||
// Element is missing and uses special empty VB
|
||||
vertexInputBindings[missingSlotBinding] = { GPU_MAX_VB_BINDED, sizeof(byte[4]), VK_VERTEX_INPUT_RATE_INSTANCE };
|
||||
bindingsCount = missingSlotBinding + 1;
|
||||
}
|
||||
attribute.binding = src.Slot;
|
||||
attribute.format = RenderToolsVulkan::ToVulkanFormat(src.Format);
|
||||
attribute.offset = src.Offset;
|
||||
@@ -277,14 +298,15 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer
|
||||
_descMultisample.rasterizationSamples = (VkSampleCountFlagBits)renderPass->Layout.MSAA;
|
||||
_desc.renderPass = renderPass->Handle;
|
||||
|
||||
// Check if has missing layout
|
||||
// Ensure to have valid layout set
|
||||
if (_desc.layout == VK_NULL_HANDLE)
|
||||
{
|
||||
_desc.layout = GetLayout()->Handle;
|
||||
}
|
||||
|
||||
// Create object
|
||||
auto depthWrite = _descDepthStencil.depthWriteEnable;
|
||||
_descDepthStencil.depthWriteEnable &= renderPass->CanDepthWrite;
|
||||
const VkResult result = vkCreateGraphicsPipelines(_device->Device, _device->PipelineCache, 1, &_desc, nullptr, &pipeline);
|
||||
_descDepthStencil.depthWriteEnable = depthWrite;
|
||||
LOG_VULKAN_RESULT(result);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user