diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp
index b0d081d4c..eca708af9 100644
--- a/Source/Engine/Graphics/GPUBuffer.cpp
+++ b/Source/Engine/Graphics/GPUBuffer.cpp
@@ -6,6 +6,7 @@
#include "GPUBufferDescription.h"
#include "PixelFormatExtensions.h"
#include "RenderTask.h"
+#include "Shaders/GPUVertexLayout.h"
#include "Async/Tasks/GPUCopyResourceTask.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Core/Types/String.h"
@@ -75,6 +76,20 @@ GPUBufferDescription GPUBufferDescription::Vertex(GPUVertexLayout* layout, uint3
return desc;
}
+GPUBufferDescription GPUBufferDescription::Vertex(GPUVertexLayout* layout, uint32 elementsCount, const void* data)
+{
+ const uint32 stride = layout ? layout->GetStride() : 0;
+ CHECK_RETURN_DEBUG(stride, GPUBufferDescription());
+ return Vertex(layout, stride, elementsCount, data);
+}
+
+GPUBufferDescription GPUBufferDescription::Vertex(GPUVertexLayout* layout, uint32 elementsCount, GPUResourceUsage usage)
+{
+ const uint32 stride = layout ? layout->GetStride() : 0;
+ CHECK_RETURN_DEBUG(stride, GPUBufferDescription());
+ return Vertex(layout, stride, elementsCount, usage);
+}
+
void GPUBufferDescription::Clear()
{
Platform::MemoryClear(this, sizeof(GPUBufferDescription));
diff --git a/Source/Engine/Graphics/GPUBufferDescription.h b/Source/Engine/Graphics/GPUBufferDescription.h
index adb7f3cf2..4861d626c 100644
--- a/Source/Engine/Graphics/GPUBufferDescription.h
+++ b/Source/Engine/Graphics/GPUBufferDescription.h
@@ -202,6 +202,24 @@ public:
/// The buffer description.
static GPUBufferDescription Vertex(GPUVertexLayout* layout, uint32 elementStride, uint32 elementsCount, GPUResourceUsage usage = GPUResourceUsage::Default);
+ ///
+ /// Creates vertex buffer description.
+ ///
+ /// The vertex buffer layout.
+ /// The elements count.
+ /// The data.
+ /// The buffer description.
+ static GPUBufferDescription Vertex(GPUVertexLayout* layout, uint32 elementsCount, const void* data);
+
+ ///
+ /// Creates vertex buffer description.
+ ///
+ /// The vertex buffer layout.
+ /// The elements count.
+ /// The usage mode.
+ /// The buffer description.
+ static GPUBufferDescription Vertex(GPUVertexLayout* layout, uint32 elementsCount, GPUResourceUsage usage = GPUResourceUsage::Default);
+
///
/// Creates vertex buffer description.
/// [Deprecated in v1.10]
diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp
index 6a4b8e677..996a177c2 100644
--- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp
+++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp
@@ -5,9 +5,11 @@
#include "Engine/Core/Log.h"
#endif
#include "Engine/Core/Collections/Dictionary.h"
+#include "Engine/Core/Math/Math.h"
#include "Engine/Core/Types/Span.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUBuffer.h"
+#include "Engine/Graphics/PixelFormatExtensions.h"
#if GPU_ENABLE_RESOURCE_NAMING
#include "Engine/Scripting/Enums.h"
#endif
@@ -74,6 +76,20 @@ GPUVertexLayout::GPUVertexLayout()
{
}
+void GPUVertexLayout::SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS])
+{
+ _elements = elements;
+ uint32 strides[GPU_MAX_VB_BINDED] = {};
+ for (int32 i = 0; i < elements.Count(); i++)
+ {
+ const VertexElement& e = elements[i];
+ strides[e.Slot] = Math::Max(strides[e.Slot], offsets[i]);
+ }
+ _stride = 0;
+ for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
+ _stride += strides[i];
+}
+
GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
{
// Hash input layout
@@ -144,7 +160,7 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span& vertexBuffers)
anyValid = true;
int32 start = elements.Count();
elements.Add(layouts.Layouts[slot]->GetElements());
- for (int32 j = start; j < elements.Count() ;j++)
+ for (int32 j = start; j < elements.Count(); j++)
elements.Get()[j].Slot = (byte)slot;
}
}
diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h
index 8d60573b8..e234b32b1 100644
--- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h
+++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h
@@ -16,11 +16,15 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUVertexLayout : public GPUReso
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUVertexLayout);
typedef Array> Elements;
-protected:
+private:
Elements _elements;
+ uint32 _stride;
+protected:
GPUVertexLayout();
+ void SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS]);
+
public:
///
/// Gets the list of elements used by this layout.
@@ -30,6 +34,14 @@ public:
return _elements;
}
+ ///
+ /// Gets the size in bytes of all elements in the layout structure (including their offsets).
+ ///
+ API_PROPERTY() FORCE_INLINE uint32 GetStride() const
+ {
+ return _stride;
+ }
+
///
/// 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.
///
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
index 4a9e4a6d2..35656606a 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
@@ -152,11 +152,10 @@ GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements&
: GPUResourceBase(device, StringView::Empty)
, InputElementsCount(elements.Count())
{
- _elements = elements;
uint32 offsets[GPU_MAX_VB_BINDED] = {};
- for (int32 i = 0; i < _elements.Count(); i++)
+ for (int32 i = 0; i < elements.Count(); i++)
{
- const VertexElement& src = _elements.Get()[i];
+ const VertexElement& src = elements.Get()[i];
D3D11_INPUT_ELEMENT_DESC& dst = InputElements[i];
uint32& offset = offsets[src.Slot];
if (src.Offset != 0)
@@ -169,6 +168,7 @@ GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements&
dst.InstanceDataStepRate = src.PerInstance ? 1 : 0;
offset += PixelFormatExtensions::SizeInBytes(src.Format);
}
+ SetElements(elements, offsets);
}
GPUDevice* GPUDeviceDX11::Create()
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index eb252be54..ab4a0ab81 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -40,11 +40,10 @@ GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements&
: GPUResourceDX12(device, StringView::Empty)
, InputElementsCount(elements.Count())
{
- _elements = elements;
uint32 offsets[GPU_MAX_VB_BINDED] = {};
- for (int32 i = 0; i < _elements.Count(); i++)
+ for (int32 i = 0; i < elements.Count(); i++)
{
- const VertexElement& src = _elements.Get()[i];
+ const VertexElement& src = elements.Get()[i];
D3D12_INPUT_ELEMENT_DESC& dst = InputElements[i];
uint32& offset = offsets[src.Slot];
if (src.Offset != 0)
@@ -57,6 +56,7 @@ GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements&
dst.InstanceDataStepRate = src.PerInstance ? 1 : 0;
offset += PixelFormatExtensions::SizeInBytes(src.Format);
}
+ SetElements(elements, offsets);
}
GPUDevice* GPUDeviceDX12::Create()
diff --git a/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h b/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h
index c1b7e96a7..f1a5f0abd 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()
{
- _elements = elements;
+ SetElements(elements, {});
}
};
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 283b48e67..e5f7f2bcc 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -452,7 +452,6 @@ uint32 GetHash(const FramebufferVulkan::Key& key)
GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements)
: GPUResourceVulkan(device, StringView::Empty)
{
- _elements = elements;
uint32 offsets[GPU_MAX_VB_BINDED] = {};
for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
{
@@ -462,9 +461,9 @@ GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elem
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
}
uint32 bindingsCount = 0;
- for (int32 i = 0; i < _elements.Count(); i++)
+ for (int32 i = 0; i < elements.Count(); i++)
{
- const VertexElement& src = _elements.Get()[i];
+ const VertexElement& src = elements.Get()[i];
uint32& offset = offsets[src.Slot];
if (src.Offset != 0)
offset = src.Offset;
@@ -485,11 +484,12 @@ GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elem
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;
CreateInfo.pVertexBindingDescriptions = Bindings;
- CreateInfo.vertexAttributeDescriptionCount = _elements.Count();
+ CreateInfo.vertexAttributeDescriptionCount = elements.Count();
CreateInfo.pVertexAttributeDescriptions = Attributes;
}