From 7b7dd9d142c148b2959aabd8e28cb507fe151b33 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 3 Jan 2025 01:09:25 +0100 Subject: [PATCH] Improve GPU vertex layout binding in case of missing element from the mesh --- Source/Engine/Graphics/GPUDevice.h | 2 +- .../Graphics/Shaders/GPUVertexLayout.cpp | 153 +++++++++++++----- .../Engine/Graphics/Shaders/GPUVertexLayout.h | 20 ++- .../Engine/Graphics/Shaders/VertexElement.h | 2 +- .../DirectX/DX11/GPUDeviceDX11.cpp | 17 +- .../DirectX/DX11/GPUDeviceDX11.h | 2 +- .../DirectX/DX11/GPUShaderDX11.cpp | 12 +- .../DirectX/DX11/GPUVertexLayoutDX11.h | 2 +- .../DirectX/DX12/GPUDeviceDX12.cpp | 17 +- .../DirectX/DX12/GPUDeviceDX12.h | 2 +- .../DirectX/DX12/GPUVertexLayoutDX12.h | 2 +- .../GraphicsDevice/Null/GPUDeviceNull.cpp | 2 +- .../GraphicsDevice/Null/GPUDeviceNull.h | 2 +- .../GraphicsDevice/Null/GPUVertexLayoutNull.h | 2 +- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 19 +-- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.h | 2 +- .../Vulkan/GPUVertexLayoutVulkan.h | 2 +- 17 files changed, 168 insertions(+), 92 deletions(-) diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index 23636bfdf..9fdba7885 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -401,7 +401,7 @@ public: /// Creates the vertex buffer layout. /// /// The vertex buffer layout. - API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array>& elements) = 0; + API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array>& elements, bool explicitOffsets = false) = 0; typedef Array> VertexElements; /// diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp index 659bcb344..91f19c701 100644 --- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp +++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp @@ -45,6 +45,26 @@ namespace CriticalSection CacheLocker; Dictionary LayoutCache; Dictionary VertexBufferCache; + + GPUVertexLayout* AddCache(const VertexBufferLayouts& key, int32 count) + { + GPUVertexLayout::Elements elements; + bool anyValid = false; + for (int32 slot = 0; slot < count; slot++) + { + if (key.Layouts[slot]) + { + anyValid = true; + int32 start = elements.Count(); + elements.Add(key.Layouts[slot]->GetElements()); + for (int32 j = start; j < elements.Count(); j++) + elements.Get()[j].Slot = (byte)slot; + } + } + GPUVertexLayout* result = anyValid ? GPUVertexLayout::Get(elements) : nullptr; + VertexBufferCache.Add(key, result); + return result; + } } String VertexElement::ToString() const @@ -76,22 +96,27 @@ GPUVertexLayout::GPUVertexLayout() { } -void GPUVertexLayout::SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS]) +void GPUVertexLayout::SetElements(const Elements& elements, bool explicitOffsets) { + uint32 offsets[GPU_MAX_VB_BINDED] = {}; _elements = elements; - uint32 strides[GPU_MAX_VB_BINDED] = {}; - for (int32 i = 0; i < elements.Count(); i++) + for (int32 i = 0; i < _elements.Count(); i++) { - const VertexElement& e = elements[i]; + VertexElement& e = _elements[i]; ASSERT(e.Slot < GPU_MAX_VB_BINDED); - strides[e.Slot] = Math::Max(strides[e.Slot], offsets[e.Slot]); + uint32& offset = offsets[e.Slot]; + if (e.Offset != 0 || explicitOffsets) + offset = e.Offset; + else + e.Offset = (byte)offset; + offset += PixelFormatExtensions::SizeInBytes(e.Format); } _stride = 0; - for (uint32 stride : strides) - _stride += stride; + for (uint32 offset : offsets) + _stride += offset; } -GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements) +GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements, bool explicitOffsets) { // Hash input layout uint32 hash = 0; @@ -105,7 +130,7 @@ GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements) GPUVertexLayout* result; if (!LayoutCache.TryGet(hash, result)) { - result = GPUDevice::Instance->CreateVertexLayout(elements); + result = GPUDevice::Instance->CreateVertexLayout(elements, explicitOffsets); if (!result) { #if GPU_ENABLE_ASSERTION_LOW_LAYERS @@ -118,16 +143,6 @@ GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements) } LayoutCache.Add(hash, result); } -#if GPU_ENABLE_ASSERTION_LOW_LAYERS - else if (result->GetElements() != elements) - { - for (auto& e : result->GetElements()) - LOG(Error, " (a) {}", e.ToString()); - for (auto& e : elements) - LOG(Error, " (b) {}", e.ToString()); - LOG(Fatal, "Vertex layout cache collision for hash {}", hash); - } -#endif CacheLocker.Unlock(); return result; @@ -141,38 +156,94 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span& vertexBuffers) return vertexBuffers.Get()[0] ? vertexBuffers.Get()[0]->GetVertexLayout() : nullptr; // Build hash key for set of buffers (in case there is layout sharing by different sets of buffers) - VertexBufferLayouts layouts; - for (int32 i = 0; i < vertexBuffers.Length(); i++) - layouts.Layouts[i] = vertexBuffers.Get()[i] ? vertexBuffers.Get()[i]->GetVertexLayout() : nullptr; + VertexBufferLayouts key; + for (int32 i = 0; i < vertexBuffers.Length() && i < GPU_MAX_VB_BINDED; i++) + key.Layouts[i] = vertexBuffers.Get()[i] ? vertexBuffers.Get()[i]->GetVertexLayout() : nullptr; for (int32 i = vertexBuffers.Length(); i < GPU_MAX_VB_BINDED; i++) - layouts.Layouts[i] = nullptr; + key.Layouts[i] = nullptr; // Lookup existing cache CacheLocker.Lock(); GPUVertexLayout* result; - if (!VertexBufferCache.TryGet(layouts, result)) - { - Elements elements; - bool anyValid = false; - for (int32 slot = 0; slot < vertexBuffers.Length(); slot++) - { - if (layouts.Layouts[slot]) - { - anyValid = true; - int32 start = elements.Count(); - elements.Add(layouts.Layouts[slot]->GetElements()); - for (int32 j = start; j < elements.Count(); j++) - elements.Get()[j].Slot = (byte)slot; - } - } - result = anyValid ? Get(elements) : nullptr; - VertexBufferCache.Add(layouts, result); - } + if (!VertexBufferCache.TryGet(key, result)) + result = AddCache(key, vertexBuffers.Length()); CacheLocker.Unlock(); return result; } +GPUVertexLayout* GPUVertexLayout::Get(const Span& layouts) +{ + if (layouts.Length() == 0) + return nullptr; + if (layouts.Length() == 1) + return layouts.Get()[0] ? layouts.Get()[0] : nullptr; + + // Build hash key for set of buffers (in case there is layout sharing by different sets of buffers) + VertexBufferLayouts key; + for (int32 i = 0; i < layouts.Length() && i < GPU_MAX_VB_BINDED; i++) + key.Layouts[i] = layouts.Get()[i]; + for (int32 i = layouts.Length(); i < GPU_MAX_VB_BINDED; i++) + key.Layouts[i] = nullptr; + + // Lookup existing cache + CacheLocker.Lock(); + GPUVertexLayout* result; + if (!VertexBufferCache.TryGet(key, result)) + result = AddCache(key, layouts.Length()); + CacheLocker.Unlock(); + + return result; +} + +GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, const GPUVertexLayout* reference) +{ + if (!reference || !base || base == reference) + return base; + GPUVertexLayout* result = base; + if (base && reference) + { + bool anyMissing = false; + const Elements& baseElements = base->GetElements(); + Elements newElements = baseElements; + for (const VertexElement& e : reference->GetElements()) + { + bool missing = true; + for (const VertexElement& ee : baseElements) + { + 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); + anyMissing = true; + } + } + if (anyMissing) + result = Get(newElements, true); + } + return result; +} + void ClearVertexLayoutCache() { for (const auto& e : LayoutCache) diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h index e234b32b1..56cf413bc 100644 --- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h +++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h @@ -23,7 +23,7 @@ private: protected: GPUVertexLayout(); - void SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS]); + void SetElements(const Elements& elements, bool explicitOffsets); public: /// @@ -46,8 +46,9 @@ public: /// Gets the vertex layout for a given list of elements. Uses internal cache to skip creating layout if it's already exists for a given list. /// /// The list of elements for the layout. + /// If set to true, input elements offsets will be used without automatic calculations (offsets with value 0). /// Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime. - API_FUNCTION() static GPUVertexLayout* Get(const Array>& elements); + API_FUNCTION() static GPUVertexLayout* Get(const Array>& elements, bool explicitOffsets = false); /// /// Gets the vertex layout for a given list of vertex buffers (sequence of binding slots based on layouts set on those buffers). Uses internal cache to skip creating layout if it's already exists for a given list. @@ -56,6 +57,21 @@ public: /// Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime. API_FUNCTION() static GPUVertexLayout* Get(const Span& vertexBuffers); + /// + /// Merges list of layouts in a single one. Uses internal cache to skip creating layout if it's already exists for a given list. + /// + /// The list of layouts to merge. + /// Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime. + API_FUNCTION() static GPUVertexLayout* Get(const Span& layouts); + + /// + /// Merges reference vertex elements into the given set of elements to ensure the reference list is satisfied (vertex shader input requirement). Returns base layout if it's valid. + /// + /// The list of vertex buffers for the layout. + /// The list of reference inputs. + /// Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime. + static GPUVertexLayout* Merge(GPUVertexLayout* base, const GPUVertexLayout* reference); + public: // [GPUResource] GPUResourceType GetResourceType() const override diff --git a/Source/Engine/Graphics/Shaders/VertexElement.h b/Source/Engine/Graphics/Shaders/VertexElement.h index f15bb86c7..4bc628fcc 100644 --- a/Source/Engine/Graphics/Shaders/VertexElement.h +++ b/Source/Engine/Graphics/Shaders/VertexElement.h @@ -66,7 +66,7 @@ PACK_BEGIN() struct FLAXENGINE_API VertexElement API_FIELD() Types Type; // Index of the input vertex buffer slot (as provided in GPUContext::BindVB). API_FIELD() byte Slot; - // Byte offset of this element relative to the start of a vertex buffer. Use value 0 to use auto-calculated offset based on previous elements in the layout (or for the first one). + // Byte offset of this element relative to the start of a vertex buffer. Use value 0 to use auto-calculated offset based on previous elements in the layout (except when explicitOffsets is false). API_FIELD() byte Offset; // Flag used to mark data using hardware-instancing (element will be repeated for every instance). Empty to step data per-vertex when reading input buffer stream (rather than per-instance step). API_FIELD() byte PerInstance; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index 35656606a..ac11989d5 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -148,27 +148,22 @@ static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureL return false; } -GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements) +GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements, bool explicitOffsets) : GPUResourceBase(device, StringView::Empty) , InputElementsCount(elements.Count()) { - uint32 offsets[GPU_MAX_VB_BINDED] = {}; + SetElements(elements, explicitOffsets); for (int32 i = 0; i < elements.Count(); i++) { - const VertexElement& src = elements.Get()[i]; + const VertexElement& src = GetElements().Get()[i]; D3D11_INPUT_ELEMENT_DESC& dst = InputElements[i]; - uint32& offset = offsets[src.Slot]; - if (src.Offset != 0) - offset = src.Offset; dst.SemanticName = RenderToolsDX::GetVertexInputSemantic(src.Type, dst.SemanticIndex); dst.Format = RenderToolsDX::ToDxgiFormat(src.Format); dst.InputSlot = src.Slot; - dst.AlignedByteOffset = offset; + dst.AlignedByteOffset = src.Offset; dst.InputSlotClass = src.PerInstance ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; dst.InstanceDataStepRate = src.PerInstance ? 1 : 0; - offset += PixelFormatExtensions::SizeInBytes(src.Format); } - SetElements(elements, offsets); } GPUDevice* GPUDeviceDX11::Create() @@ -832,9 +827,9 @@ GPUSampler* GPUDeviceDX11::CreateSampler() return New(this); } -GPUVertexLayout* GPUDeviceDX11::CreateVertexLayout(const VertexElements& elements) +GPUVertexLayout* GPUDeviceDX11::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) { - return New(this, elements); + return New(this, elements, explicitOffsets); } GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h index 079d38967..066f02863 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h @@ -128,7 +128,7 @@ public: GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; GPUSampler* CreateSampler() override; - GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override; + GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override; GPUSwapChain* CreateSwapChain(Window* window) override; GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override; }; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp index faf50a927..7dcfb0d31 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp @@ -11,19 +11,23 @@ GPUShaderProgramVSDX11::~GPUShaderProgramVSDX11() { for (const auto& e : _cache) - e.Value->Release(); + { + if (e.Value) + e.Value->Release(); + } } ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* vertexLayout) { - if (!vertexLayout) - vertexLayout = (GPUVertexLayoutDX11*)Layout; ID3D11InputLayout* inputLayout = nullptr; if (!_cache.TryGet(vertexLayout, inputLayout)) { + if (!vertexLayout) + vertexLayout = (GPUVertexLayoutDX11*)Layout; if (vertexLayout && vertexLayout->InputElementsCount) { - VALIDATE_DIRECTX_CALL(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(vertexLayout->InputElements, vertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout)); + auto actualLayout = (GPUVertexLayoutDX11*)GPUVertexLayout::Merge(vertexLayout, Layout); + LOG_DIRECTX_RESULT(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(actualLayout->InputElements, actualLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout)); } _cache.Add(vertexLayout, inputLayout); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h index 119ee2964..d5ff07a0c 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h @@ -13,7 +13,7 @@ class GPUVertexLayoutDX11 : public GPUResourceBase { public: - GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements); + GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements, bool explicitOffsets); uint32 InputElementsCount; D3D11_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS]; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index ab4a0ab81..65e3f6d83 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -36,27 +36,22 @@ static bool CheckDX12Support(IDXGIAdapter* adapter) return false; } -GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements) +GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements, bool explicitOffsets) : GPUResourceDX12(device, StringView::Empty) , InputElementsCount(elements.Count()) { - uint32 offsets[GPU_MAX_VB_BINDED] = {}; + SetElements(elements, explicitOffsets); for (int32 i = 0; i < elements.Count(); i++) { - const VertexElement& src = elements.Get()[i]; + const VertexElement& src = GetElements().Get()[i]; D3D12_INPUT_ELEMENT_DESC& dst = InputElements[i]; - uint32& offset = offsets[src.Slot]; - if (src.Offset != 0) - offset = src.Offset; dst.SemanticName = RenderToolsDX::GetVertexInputSemantic(src.Type, dst.SemanticIndex); dst.Format = RenderToolsDX::ToDxgiFormat(src.Format); dst.InputSlot = src.Slot; - dst.AlignedByteOffset = offset; + dst.AlignedByteOffset = src.Offset; dst.InputSlotClass = src.PerInstance ? D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA : D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; dst.InstanceDataStepRate = src.PerInstance ? 1 : 0; - offset += PixelFormatExtensions::SizeInBytes(src.Format); } - SetElements(elements, offsets); } GPUDevice* GPUDeviceDX12::Create() @@ -868,9 +863,9 @@ GPUSampler* GPUDeviceDX12::CreateSampler() return New(this); } -GPUVertexLayout* GPUDeviceDX12::CreateVertexLayout(const VertexElements& elements) +GPUVertexLayout* GPUDeviceDX12::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) { - return New(this, elements); + return New(this, elements, explicitOffsets); } GPUSwapChain* GPUDeviceDX12::CreateSwapChain(Window* window) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h index 82f59a8ee..81c42070f 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h @@ -196,7 +196,7 @@ public: GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; GPUSampler* CreateSampler() override; - GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override; + GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override; GPUSwapChain* CreateSwapChain(Window* window) override; GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override; }; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h index 225c3367c..79b4aa9de 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h @@ -13,7 +13,7 @@ class GPUVertexLayoutDX12 : public GPUResourceDX12 { public: - GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements); + GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements, bool explicitOffsets); uint32 InputElementsCount; D3D12_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS]; diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp index d1fe23dd8..f7fdd1eba 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp +++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp @@ -173,7 +173,7 @@ GPUSampler* GPUDeviceNull::CreateSampler() return New(); } -GPUVertexLayout* GPUDeviceNull::CreateVertexLayout(const VertexElements& elements) +GPUVertexLayout* GPUDeviceNull::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) { return New(elements); } diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h index 80de34db3..b9d53d2f4 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h @@ -47,7 +47,7 @@ public: GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; GPUSampler* CreateSampler() override; - GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override; + GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override; GPUSwapChain* CreateSwapChain(Window* window) override; GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override; }; diff --git a/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h b/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h index f1a5f0abd..a483a881f 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h @@ -15,7 +15,7 @@ public: GPUVertexLayoutNull(const Elements& elements) : GPUVertexLayout() { - SetElements(elements, {}); + SetElements(elements, false); } }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index e5f7f2bcc..21e653a36 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -449,10 +449,10 @@ uint32 GetHash(const FramebufferVulkan::Key& key) return hash; } -GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements) +GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements, bool explicitOffsets) : GPUResourceVulkan(device, StringView::Empty) { - uint32 offsets[GPU_MAX_VB_BINDED] = {}; + SetElements(elements, explicitOffsets); for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++) { VkVertexInputBindingDescription& binding = Bindings[i]; @@ -463,28 +463,23 @@ GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elem uint32 bindingsCount = 0; for (int32 i = 0; i < elements.Count(); i++) { - const VertexElement& src = elements.Get()[i]; - uint32& offset = offsets[src.Slot]; - if (src.Offset != 0) - offset = src.Offset; + 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)(offset + size)); + 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 = offset; + attribute.offset = src.Offset; bindingsCount = Math::Max(bindingsCount, (uint32)src.Slot + 1); - offset += size; } - SetElements(elements, offsets); RenderToolsVulkan::ZeroStruct(CreateInfo, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO); CreateInfo.vertexBindingDescriptionCount = bindingsCount; @@ -2129,9 +2124,9 @@ GPUSampler* GPUDeviceVulkan::CreateSampler() return New(this); } -GPUVertexLayout* GPUDeviceVulkan::CreateVertexLayout(const VertexElements& elements) +GPUVertexLayout* GPUDeviceVulkan::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) { - return New(this, elements); + return New(this, elements, explicitOffsets); } GPUSwapChain* GPUDeviceVulkan::CreateSwapChain(Window* window) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index 8b64eeb9c..10a6c1b77 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -610,7 +610,7 @@ public: GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; GPUSampler* CreateSampler() override; - GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override; + GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override; GPUSwapChain* CreateSwapChain(Window* window) override; GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override; }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUVertexLayoutVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUVertexLayoutVulkan.h index b2d0e4b75..67a05824f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUVertexLayoutVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUVertexLayoutVulkan.h @@ -13,7 +13,7 @@ class GPUVertexLayoutVulkan : public GPUResourceVulkan { public: - GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements); + GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements, bool explicitOffsets); VkPipelineVertexInputStateCreateInfo CreateInfo; VkVertexInputBindingDescription Bindings[GPU_MAX_VB_BINDED];