diff --git a/Source/Engine/Graphics/Config.h b/Source/Engine/Graphics/Config.h
index 2a9167045..f2f0cc34f 100644
--- a/Source/Engine/Graphics/Config.h
+++ b/Source/Engine/Graphics/Config.h
@@ -25,6 +25,9 @@
// Maximum amount of binded vertex buffers at the same time
#define GPU_MAX_VB_BINDED 4
+// Maximum amount of vertex shader input elements in a layout
+#define GPU_MAX_VS_ELEMENTS 16
+
// Maximum amount of thread groups per dimension for compute dispatch
#define GPU_MAX_CS_DISPATCH_THREAD_GROUPS 65535
@@ -33,6 +36,7 @@
// Enable/disable assertion for graphics layers
#define GPU_ENABLE_ASSERTION 1
+#define GPU_ENABLE_ASSERTION_LOW_LAYERS (!BUILD_RELEASE)
// Enable/disable dynamic textures quality streaming
#define GPU_ENABLE_TEXTURES_STREAMING 1
diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp
index 60298a513..2f42ac08b 100644
--- a/Source/Engine/Graphics/GPUDevice.cpp
+++ b/Source/Engine/Graphics/GPUDevice.cpp
@@ -479,6 +479,8 @@ void GPUDevice::DumpResourcesToLog() const
LOG_STR(Info, output.ToStringView());
}
+extern void ClearVertexLayoutCache();
+
void GPUDevice::preDispose()
{
Locker.Lock();
@@ -494,6 +496,7 @@ void GPUDevice::preDispose()
SAFE_DELETE_GPU_RESOURCE(_res->PS_Clear);
SAFE_DELETE_GPU_RESOURCE(_res->PS_DecodeYUY2);
SAFE_DELETE_GPU_RESOURCE(_res->FullscreenTriangleVB);
+ ClearVertexLayoutCache();
Locker.Unlock();
diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h
index f7ffe00a9..23636bfdf 100644
--- a/Source/Engine/Graphics/GPUDevice.h
+++ b/Source/Engine/Graphics/GPUDevice.h
@@ -23,6 +23,7 @@ class GPUBuffer;
class GPUSampler;
class GPUPipelineState;
class GPUConstantBuffer;
+class GPUVertexLayout;
class GPUTasksContext;
class GPUTasksExecutor;
class GPUSwapChain;
@@ -396,6 +397,13 @@ public:
/// The sampler.
API_FUNCTION() virtual GPUSampler* CreateSampler() = 0;
+ ///
+ /// Creates the vertex buffer layout.
+ ///
+ /// The vertex buffer layout.
+ API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array>& elements) = 0;
+ typedef Array> VertexElements;
+
///
/// Creates the native window swap chain.
///
diff --git a/Source/Engine/Graphics/Shaders/Config.h b/Source/Engine/Graphics/Shaders/Config.h
index 4b5c92744..29b20fedb 100644
--- a/Source/Engine/Graphics/Shaders/Config.h
+++ b/Source/Engine/Graphics/Shaders/Config.h
@@ -6,12 +6,16 @@
#include "Engine/Core/Enums.h"
#include "Engine/Graphics/Enums.h"
+// [Deprecated in v1.10]
#define INPUT_LAYOUT_ELEMENT_ALIGN 0xffffffff
+// [Deprecated in v1.10]
#define INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA 0
+// [Deprecated in v1.10]
#define INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA 1
///
/// Maximum amount of input elements for vertex shader programs
+/// [Deprecated in v1.10]
///
#define VERTEX_SHADER_MAX_INPUT_ELEMENTS 16
@@ -26,7 +30,8 @@
#define SHADER_PERMUTATIONS_MAX_PARAMS_COUNT 4
///
-/// Maximum allowed amount of constant buffers that can be binded to the pipeline (maximum slot index is MAX_CONSTANT_BUFFER_SLOTS-1)
+/// Maximum allowed amount of constant buffers that can be binded to the pipeline (maximum slot index is MAX_CONSTANT_BUFFER_SLOTS-1)
+/// [Deprecated in v1.10]
///
#define MAX_CONSTANT_BUFFER_SLOTS 4
diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp
index 3fcde42cf..b29d3236b 100644
--- a/Source/Engine/Graphics/Shaders/GPUShader.cpp
+++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp
@@ -5,6 +5,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/Math/Math.h"
#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
#include "Engine/Serialization/MemoryReadStream.h"
static FORCE_INLINE uint32 HashPermutation(const StringAnsiView& name, int32 permutationIndex)
@@ -12,6 +13,21 @@ static FORCE_INLINE uint32 HashPermutation(const StringAnsiView& name, int32 per
return GetHash(name) * 37 + permutationIndex;
}
+void GPUShaderProgram::Init(const GPUShaderProgramInitializer& initializer)
+{
+ _name = initializer.Name;
+ _bindings = initializer.Bindings;
+ _flags = initializer.Flags;
+#if !BUILD_RELEASE
+ _owner = initializer.Owner;
+#endif
+}
+
+GPUShaderProgramVS::~GPUShaderProgramVS()
+{
+ SAFE_DELETE(Layout);
+}
+
GPUShader::GPUShader()
: GPUResource(SpawnParams(Guid::New(), TypeInitializer))
{
@@ -104,33 +120,32 @@ bool GPUShader::Create(MemoryReadStream& stream)
// Constant Buffers
const byte constantBuffersCount = stream.ReadByte();
- const byte maximumConstantBufferSlot = stream.ReadByte();
- if (constantBuffersCount > 0)
+ for (int32 i = 0; i < constantBuffersCount; i++)
{
- ASSERT(maximumConstantBufferSlot < MAX_CONSTANT_BUFFER_SLOTS);
-
- for (int32 i = 0; i < constantBuffersCount; i++)
+ // Load info
+ const byte slotIndex = stream.ReadByte();
+ if (slotIndex >= GPU_MAX_CB_BINDED)
{
- // Load info
- const byte slotIndex = stream.ReadByte();
- uint32 size;
- stream.ReadUint32(&size);
-
- // Create CB
-#if GPU_ENABLE_RESOURCE_NAMING
- String name = String::Format(TEXT("{}.CB{}"), ToString(), i);
-#else
- String name;
-#endif
- ASSERT(_constantBuffers[slotIndex] == nullptr);
- const auto cb = GPUDevice::Instance->CreateConstantBuffer(size, name);
- if (cb == nullptr)
- {
- LOG(Warning, "Failed to create shader constant buffer.");
- return true;
- }
- _constantBuffers[slotIndex] = cb;
+ LOG(Warning, "Failed to create shader constant buffer.");
+ return true;
}
+ uint32 size;
+ stream.ReadUint32(&size);
+
+ // Create CB
+#if GPU_ENABLE_RESOURCE_NAMING
+ String cbName = String::Format(TEXT("{}.CB{}"), ToString(), i);
+#else
+ String cbName;
+#endif
+ ASSERT(_constantBuffers[slotIndex] == nullptr);
+ const auto cb = GPUDevice::Instance->CreateConstantBuffer(size, cbName);
+ if (cb == nullptr)
+ {
+ LOG(Warning, "Failed to create shader constant buffer.");
+ return true;
+ }
+ _constantBuffers[slotIndex] = cb;
}
// Don't read additional data
diff --git a/Source/Engine/Graphics/Shaders/GPUShader.h b/Source/Engine/Graphics/Shaders/GPUShader.h
index 0ff511cc3..035619c2e 100644
--- a/Source/Engine/Graphics/Shaders/GPUShader.h
+++ b/Source/Engine/Graphics/Shaders/GPUShader.h
@@ -12,7 +12,7 @@ class GPUShaderProgram;
///
/// The runtime version of the shaders cache supported by the all graphics back-ends. The same for all the shader cache formats (easier to sync and validate).
///
-#define GPU_SHADER_CACHE_VERSION 9
+#define GPU_SHADER_CACHE_VERSION 10
///
/// The GPU resource with shader programs that can run on the GPU and are able to perform rendering calculation using textures, vertices and other resources.
@@ -23,7 +23,7 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUShader : public GPUResource
protected:
Dictionary _shaders;
- GPUConstantBuffer* _constantBuffers[MAX_CONSTANT_BUFFER_SLOTS];
+ GPUConstantBuffer* _constantBuffers[GPU_MAX_CB_BINDED];
GPUShader();
diff --git a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
index 9210ad938..9447e04a5 100644
--- a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
+++ b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
@@ -7,6 +7,7 @@
#include "Config.h"
class GPUShader;
+class GPUVertexLayout;
///
/// The shader program metadata container. Contains description about resources used by the shader.
@@ -18,17 +19,17 @@ struct FLAXENGINE_API ShaderBindings
uint32 UsedSRsMask;
uint32 UsedUAsMask;
- bool IsUsingCB(uint32 slotIndex) const
+ FORCE_INLINE bool IsUsingCB(uint32 slotIndex) const
{
return (UsedCBsMask & (1u << slotIndex)) != 0u;
}
- bool IsUsingSR(uint32 slotIndex) const
+ FORCE_INLINE bool IsUsingSR(uint32 slotIndex) const
{
return (UsedSRsMask & (1u << slotIndex)) != 0u;
}
- bool IsUsingUA(uint32 slotIndex) const
+ FORCE_INLINE bool IsUsingUA(uint32 slotIndex) const
{
return (UsedUAsMask & (1u << slotIndex)) != 0u;
}
@@ -57,15 +58,7 @@ protected:
GPUShader* _owner;
#endif
- void Init(const GPUShaderProgramInitializer& initializer)
- {
- _name = initializer.Name;
- _bindings = initializer.Bindings;
- _flags = initializer.Flags;
-#if !BUILD_RELEASE
- _owner = initializer.Owner;
-#endif
- }
+ void Init(const GPUShaderProgramInitializer& initializer);
public:
///
@@ -122,8 +115,18 @@ public:
///
class GPUShaderProgramVS : public GPUShaderProgram
{
+public:
+ ~GPUShaderProgramVS();
+
+ // Vertex elements input layout defined explicitly in the shader.
+ // It's optional as it's been deprecated in favor or layouts defined by vertex buffers to allow data customizations.
+ // Can be overriden by the vertex buffers provided upon draw call.
+ // [Deprecated in v1.10]
+ GPUVertexLayout* Layout = nullptr;
+
public:
// Input element run-time data (see VertexShaderMeta::InputElement for compile-time data)
+ // [Deprecated in v1.10]
PACK_STRUCT(struct InputElement
{
byte Type; // VertexShaderMeta::InputType
@@ -135,14 +138,15 @@ public:
uint32 InstanceDataStepRate; // 0 if per-vertex
});
-public:
///
/// Gets input layout description handle (platform dependent).
+ /// [Deprecated in v1.10]
///
virtual void* GetInputLayout() const = 0;
///
/// Gets input layout description size (in bytes).
+ /// [Deprecated in v1.10]
///
virtual byte GetInputLayoutSize() const = 0;
@@ -173,7 +177,7 @@ public:
class GPUShaderProgramHS : public GPUShaderProgram
{
protected:
- int32 _controlPointsCount;
+ int32 _controlPointsCount = 0;
public:
///
diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp
new file mode 100644
index 000000000..d90613a31
--- /dev/null
+++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp
@@ -0,0 +1,103 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#include "GPUVertexLayout.h"
+#if GPU_ENABLE_ASSERTION_LOW_LAYERS
+#include "Engine/Core/Log.h"
+#endif
+#include "Engine/Core/Collections/Dictionary.h"
+#include "Engine/Graphics/GPUDevice.h"
+#if GPU_ENABLE_RESOURCE_NAMING
+#include "Engine/Scripting/Enums.h"
+#endif
+
+// VertexElement has been designed to be POD and memory-comparable for faster hashing and comparision.
+struct VertexElementRaw
+{
+ uint32 Words[2];
+};
+
+static_assert(sizeof(VertexElement) == sizeof(VertexElementRaw), "Incorrect size of the VertexElement!");
+
+namespace
+{
+ CriticalSection CacheLocker;
+ Dictionary LayoutCache;
+}
+
+String VertexElement::ToString() const
+{
+#if GPU_ENABLE_RESOURCE_NAMING
+ return String::Format(TEXT("{}, format {}, offset {}, per-instance {}, slot {}"), ScriptingEnum::ToString(Type), ScriptingEnum::ToString(Format), Offset, PerInstance, Slot);
+#else
+ return TEXT("VertexElement");
+#endif
+}
+
+bool VertexElement::operator==(const VertexElement& other) const
+{
+ auto thisRaw = (const VertexElementRaw*)this;
+ auto otherRaw = (const VertexElementRaw*)&other;
+ return thisRaw->Words[0] == otherRaw->Words[0] && thisRaw->Words[1] == otherRaw->Words[1];
+}
+
+uint32 GetHash(const VertexElement& key)
+{
+ auto keyRaw = (const VertexElementRaw*)&key;
+ uint32 hash = keyRaw->Words[0];
+ CombineHash(hash, keyRaw->Words[1]);
+ return hash;
+}
+
+GPUVertexLayout::GPUVertexLayout()
+ : GPUResource(SpawnParams(Guid::New(), TypeInitializer))
+{
+}
+
+GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
+{
+ // Hash input layout
+ uint32 hash = 0;
+ for (const VertexElement& element : elements)
+ {
+ CombineHash(hash, GetHash(element));
+ }
+
+ // Lookup existing cache
+ CacheLocker.Lock();
+ GPUVertexLayout* result;
+ if (!LayoutCache.TryGet(hash, result))
+ {
+ result = GPUDevice::Instance->CreateVertexLayout(elements);
+ if (!result)
+ {
+#if GPU_ENABLE_ASSERTION_LOW_LAYERS
+ for (auto& e : elements)
+ LOG(Error, " {}", e.ToString());
+#endif
+ LOG(Error, "Failed to create vertex layout");
+ CacheLocker.Unlock();
+ return nullptr;
+ }
+ 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;
+}
+
+void ClearVertexLayoutCache()
+{
+ for (const auto& e : LayoutCache)
+ Delete(e.Value);
+ LayoutCache.Clear();
+}
diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h
new file mode 100644
index 000000000..a3f5158bc
--- /dev/null
+++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "VertexElement.h"
+#include "Engine/Graphics/GPUResource.h"
+#include "Engine/Core/Collections/Array.h"
+
+///
+/// Defines input layout of vertex buffer data passed to the Vertex Shader.
+///
+API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUVertexLayout : public GPUResource
+{
+ DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUVertexLayout);
+ typedef Array> Elements;
+
+protected:
+ Elements _elements;
+
+ GPUVertexLayout();
+
+public:
+ ///
+ /// Gets the list of elements used by this layout.
+ ///
+ API_PROPERTY() FORCE_INLINE const Array>& GetElements() const
+ {
+ return _elements;
+ }
+
+ ///
+ /// 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.
+ /// 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);
+
+public:
+ // [GPUResource]
+ GPUResourceType GetResourceType() const override
+ {
+ return GPUResourceType::Descriptor;
+ }
+};
diff --git a/Source/Engine/Graphics/Shaders/VertexElement.h b/Source/Engine/Graphics/Shaders/VertexElement.h
new file mode 100644
index 000000000..edf2d5df6
--- /dev/null
+++ b/Source/Engine/Graphics/Shaders/VertexElement.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Engine/Graphics/PixelFormat.h"
+
+///
+/// Vertex buffer data element. Defines access to data passed to Vertex Shader.
+///
+API_STRUCT(NoDefault)
+PACK_BEGIN() struct FLAXENGINE_API VertexElement
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(VertexElement);
+
+ ///
+ /// Types of vertex elements.
+ ///
+ API_ENUM() enum class Types : byte
+ {
+ // Undefined.
+ Unknown = 0,
+ // Vertex position.
+ Position = 1,
+ // Vertex color.
+ Color = 2,
+ // Vertex normal vector.
+ Normal = 3,
+ // Vertex tangent vector.
+ Tangent = 4,
+ // Skinned bone blend indices.
+ BlendIndices = 5,
+ // Skinned bone blend weights.
+ BlendWeight = 6,
+ // Primary texture coordinate (UV).
+ TexCoord0 = 7,
+ // Additional texture coordinate (UV1).
+ TexCoord1 = 8,
+ // Additional texture coordinate (UV2).
+ TexCoord2 = 9,
+ // Additional texture coordinate (UV3).
+ TexCoord3 = 10,
+ // Additional texture coordinate (UV4).
+ TexCoord4 = 11,
+ // Additional texture coordinate (UV5).
+ TexCoord5 = 12,
+ // Additional texture coordinate (UV6).
+ TexCoord6 = 13,
+ // Additional texture coordinate (UV7).
+ TexCoord7 = 14,
+ // General purpose attribute (at index 0).
+ Attribute0 = 15,
+ // General purpose attribute (at index 1).
+ Attribute1 = 16,
+ // General purpose attribute (at index 2).
+ Attribute2 = 17,
+ // General purpose attribute (at index 3).
+ Attribute3 = 18,
+ // Texture coordinate.
+ TexCoord = TexCoord0,
+ // General purpose attribute.
+ Attribute = Attribute0,
+ MAX
+ };
+
+ // Type of the vertex element data.
+ Types Type;
+ // Index of the input vertex buffer slot (as provided in GPUContext::BindVB).
+ 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;
+ // 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).
+ byte PerInstance;
+ // Format of the vertex element data.
+ PixelFormat Format;
+
+ String ToString() const;
+
+ bool operator==(const VertexElement& other) const;
+
+ FORCE_INLINE bool operator!=(const VertexElement& other) const
+ {
+ return !operator==(other);
+ }
+} PACK_END();
+
+uint32 FLAXENGINE_API GetHash(const VertexElement& key);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
index ae24d3879..4a9e4a6d2 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
@@ -10,11 +10,13 @@
#include "GPUTimerQueryDX11.h"
#include "GPUBufferDX11.h"
#include "GPUSamplerDX11.h"
+#include "GPUVertexLayoutDX11.h"
#include "GPUSwapChainDX11.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Threading/Threading.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
+#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Engine/CommandLine.h"
#if !USE_EDITOR && PLATFORM_WINDOWS
@@ -146,6 +148,29 @@ static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureL
return false;
}
+GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements)
+ : GPUResourceBase(device, StringView::Empty)
+ , InputElementsCount(elements.Count())
+{
+ _elements = elements;
+ uint32 offsets[GPU_MAX_VB_BINDED] = {};
+ for (int32 i = 0; i < _elements.Count(); i++)
+ {
+ const VertexElement& src = _elements.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.InputSlotClass = src.PerInstance ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
+ dst.InstanceDataStepRate = src.PerInstance ? 1 : 0;
+ offset += PixelFormatExtensions::SizeInBytes(src.Format);
+ }
+}
+
GPUDevice* GPUDeviceDX11::Create()
{
// Configuration
@@ -807,6 +832,11 @@ GPUSampler* GPUDeviceDX11::CreateSampler()
return New(this);
}
+GPUVertexLayout* GPUDeviceDX11::CreateVertexLayout(const VertexElements& elements)
+{
+ return New(this, elements);
+}
+
GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window)
{
return New(this, window);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
index ffe1688f1..079d38967 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
@@ -128,6 +128,7 @@ public:
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
+ GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
GPUSwapChain* CreateSwapChain(Window* window) override;
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
};
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h
index 18aa4652d..3ccfa85c7 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h
@@ -14,7 +14,6 @@
class GPUConstantBufferDX11 : public GPUResourceDX11
{
private:
-
ID3D11Buffer* _resource;
public:
@@ -36,7 +35,6 @@ public:
}
public:
-
///
/// Gets the constant buffer object.
///
@@ -47,7 +45,6 @@ public:
}
public:
-
// [GPUResourceDX11]
ID3D11Resource* GetResource() override
{
@@ -55,7 +52,6 @@ public:
}
public:
-
// [GPUResourceDX11]
void OnReleaseGPU() final override
{
@@ -69,11 +65,9 @@ public:
class GPUShaderDX11 : public GPUResourceDX11
{
private:
-
- Array> _cbs;
+ Array> _cbs;
public:
-
///
/// Initializes a new instance of the class.
///
@@ -85,13 +79,11 @@ public:
}
protected:
-
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
void OnReleaseGPU() override;
public:
-
// [GPUResourceDX11]
ID3D11Resource* GetResource() final override
{
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h
new file mode 100644
index 000000000..119ee2964
--- /dev/null
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUVertexLayoutDX11.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if GRAPHICS_API_DIRECTX11
+
+#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
+#include "GPUDeviceDX11.h"
+
+///
+/// Vertex layout object for DirectX 11 backend.
+///
+class GPUVertexLayoutDX11 : public GPUResourceBase
+{
+public:
+ GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements);
+
+ uint32 InputElementsCount;
+ D3D11_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS];
+};
+
+#endif
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index 0b251e5a6..eb252be54 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -10,10 +10,12 @@
#include "GPUTimerQueryDX12.h"
#include "GPUBufferDX12.h"
#include "GPUSamplerDX12.h"
+#include "GPUVertexLayoutDX12.h"
#include "GPUSwapChainDX12.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Graphics/RenderTask.h"
+#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Core/Log.h"
@@ -34,6 +36,29 @@ static bool CheckDX12Support(IDXGIAdapter* adapter)
return false;
}
+GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements)
+ : GPUResourceDX12(device, StringView::Empty)
+ , InputElementsCount(elements.Count())
+{
+ _elements = elements;
+ uint32 offsets[GPU_MAX_VB_BINDED] = {};
+ for (int32 i = 0; i < _elements.Count(); i++)
+ {
+ const VertexElement& src = _elements.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.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);
+ }
+}
+
GPUDevice* GPUDeviceDX12::Create()
{
#if PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE
@@ -843,6 +868,11 @@ GPUSampler* GPUDeviceDX12::CreateSampler()
return New(this);
}
+GPUVertexLayout* GPUDeviceDX12::CreateVertexLayout(const VertexElements& elements)
+{
+ return New(this, elements);
+}
+
GPUSwapChain* GPUDeviceDX12::CreateSwapChain(Window* window)
{
return New(this, window);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h
index 2e6b4c274..82f59a8ee 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h
@@ -196,6 +196,7 @@ public:
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
+ GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
GPUSwapChain* CreateSwapChain(Window* window) override;
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
};
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h
index 905b73633..48bf99f41 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h
@@ -22,7 +22,6 @@ public:
}
public:
-
///
/// Last uploaded data address.
///
@@ -35,7 +34,6 @@ public:
class GPUShaderDX12 : public GPUResourceDX12
{
public:
-
///
/// Initializes a new instance of the class.
///
@@ -47,7 +45,6 @@ public:
}
protected:
-
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
};
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h
index 12f2f2656..5195394c1 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h
@@ -35,6 +35,7 @@ public:
{
return (void*)_data.Get();
}
+
uint32 GetBufferSize() const override
{
return _data.Count();
@@ -65,6 +66,7 @@ public:
{
return (void*)_inputLayout;
}
+
byte GetInputLayoutSize() const override
{
return _inputLayoutSize;
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h
new file mode 100644
index 000000000..225c3367c
--- /dev/null
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUVertexLayoutDX12.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if GRAPHICS_API_DIRECTX12
+
+#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
+#include "GPUDeviceDX12.h"
+
+///
+/// Vertex layout object for DirectX 12 backend.
+///
+class GPUVertexLayoutDX12 : public GPUResourceDX12
+{
+public:
+ GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements);
+
+ uint32 InputElementsCount;
+ D3D12_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS];
+};
+
+#endif
diff --git a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
index b82126702..f9d36a748 100644
--- a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp
@@ -273,4 +273,62 @@ String RenderToolsDX::GetD3DErrorString(HRESULT errorCode)
return sb.ToString();
}
+LPCSTR RenderToolsDX::GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex)
+{
+ static_assert((int32)VertexElement::Types::MAX == 16, "Update code below.");
+ semanticIndex = 0;
+ switch (type)
+ {
+ case VertexElement::Types::Position:
+ return "POSITION";
+ case VertexElement::Types::Color:
+ return "COLOR";
+ case VertexElement::Types::Normal:
+ return "NORMAL";
+ case VertexElement::Types::Tangent:
+ return "TANGENT";
+ case VertexElement::Types::BlendIndices:
+ return "BLENDINDICES";
+ case VertexElement::Types::BlendWeight:
+ return "BLENDWEIGHT";
+ case VertexElement::Types::TexCoord0:
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord1:
+ semanticIndex = 1;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord2:
+ semanticIndex = 2;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord3:
+ semanticIndex = 3;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord4:
+ semanticIndex = 4;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord5:
+ semanticIndex = 5;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord6:
+ semanticIndex = 6;
+ return "TEXCOORD";
+ case VertexElement::Types::TexCoord7:
+ semanticIndex = 7;
+ return "TEXCOORD";
+ case VertexElement::Types::Attribute0:
+ return "ATTRIBUTE";
+ case VertexElement::Types::Attribute1:
+ semanticIndex = 1;
+ return "ATTRIBUTE";
+ case VertexElement::Types::Attribute2:
+ semanticIndex = 2;
+ return "ATTRIBUTE";
+ case VertexElement::Types::Attribute3:
+ semanticIndex = 3;
+ return "ATTRIBUTE";
+ default:
+ LOG(Fatal, "Invalid vertex shader element semantic type");
+ return "";
+ }
+}
+
#endif
diff --git a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
index 5cfb5b4eb..b34f2794d 100644
--- a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
+++ b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
@@ -7,6 +7,7 @@
#include "Engine/Core/Types/BaseTypes.h"
#include "Engine/Graphics//RenderTools.h"
#include "Engine/Graphics/Enums.h"
+#include "Engine/Graphics/Shaders/VertexElement.h"
#include "IncludeDirectXHeaders.h"
#include "Engine/Core/Log.h"
@@ -112,6 +113,8 @@ namespace RenderToolsDX
const String& errorString = GetD3DErrorString(result);
LOG(Error, "DirectX error: {0} at {1}:{2}", errorString, String(file), line);
}
+
+ LPCSTR GetVertexInputSemantic(VertexElement::Types type, UINT& semanticIndex);
};
#if GPU_ENABLE_ASSERTION
diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp
index 2716e103e..d1fe23dd8 100644
--- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp
+++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp
@@ -11,6 +11,7 @@
#include "GPUTimerQueryNull.h"
#include "GPUBufferNull.h"
#include "GPUSamplerNull.h"
+#include "GPUVertexLayoutNull.h"
#include "GPUSwapChainNull.h"
#include "Engine/Core/Log.h"
#include "Engine/Graphics/Async/GPUTasksManager.h"
@@ -172,6 +173,11 @@ GPUSampler* GPUDeviceNull::CreateSampler()
return New();
}
+GPUVertexLayout* GPUDeviceNull::CreateVertexLayout(const VertexElements& elements)
+{
+ return New(elements);
+}
+
GPUSwapChain* GPUDeviceNull::CreateSwapChain(Window* window)
{
return New(window);
diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h
index 50389d840..80de34db3 100644
--- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h
+++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h
@@ -47,6 +47,7 @@ public:
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
+ GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) 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
new file mode 100644
index 000000000..c1b7e96a7
--- /dev/null
+++ b/Source/Engine/GraphicsDevice/Null/GPUVertexLayoutNull.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if GRAPHICS_API_NULL
+
+#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
+
+///
+/// Vertex layout for Null backend.
+///
+class GPUVertexLayoutNull : public GPUVertexLayout
+{
+public:
+ GPUVertexLayoutNull(const Elements& elements)
+ : GPUVertexLayout()
+ {
+ _elements = elements;
+ }
+};
+
+#endif
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 5e11e1a86..694730ab3 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -14,6 +14,7 @@
#include "GPUTimerQueryVulkan.h"
#include "GPUBufferVulkan.h"
#include "GPUSamplerVulkan.h"
+#include "GPUVertexLayoutVulkan.h"
#include "GPUSwapChainVulkan.h"
#include "RenderToolsVulkan.h"
#include "QueueVulkan.h"
@@ -448,6 +449,50 @@ uint32 GetHash(const FramebufferVulkan::Key& key)
return hash;
}
+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++)
+ {
+ VkVertexInputBindingDescription& binding = Bindings[i];
+ binding.binding = i;
+ binding.stride = 0;
+ binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+ }
+ 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 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.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;
+
+ bindingsCount = Math::Max(bindingsCount, (uint32)src.Slot + 1);
+ offset += size;
+ }
+
+ 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)
: Device(device)
, Handle(VK_NULL_HANDLE)
@@ -2072,6 +2117,11 @@ GPUSampler* GPUDeviceVulkan::CreateSampler()
return New(this);
}
+GPUVertexLayout* GPUDeviceVulkan::CreateVertexLayout(const VertexElements& elements)
+{
+ return New(this, elements);
+}
+
GPUSwapChain* GPUDeviceVulkan::CreateSwapChain(Window* window)
{
return New(this, window);
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
index d31149d20..7fa84152a 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
@@ -610,6 +610,7 @@ public:
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
+ GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) 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
new file mode 100644
index 000000000..b2d0e4b75
--- /dev/null
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUVertexLayoutVulkan.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if GRAPHICS_API_VULKAN
+
+#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
+#include "GPUDeviceVulkan.h"
+
+///
+/// Vertex layout object for Vulkan backend.
+///
+class GPUVertexLayoutVulkan : public GPUResourceVulkan
+{
+public:
+ GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements);
+
+ VkPipelineVertexInputStateCreateInfo CreateInfo;
+ VkVertexInputBindingDescription Bindings[GPU_MAX_VB_BINDED];
+ VkVertexInputAttributeDescription Attributes[GPU_MAX_VS_ELEMENTS];
+};
+
+#endif
diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.CB.h b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.CB.h
index 0724b85bb..7f8c6a3a8 100644
--- a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.CB.h
+++ b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.CB.h
@@ -3,6 +3,7 @@
#pragma once
#include "ShaderFunctionReader.h"
+#include "Engine/Graphics/Config.h"
#if COMPILE_WITH_SHADER_COMPILER
@@ -115,9 +116,9 @@ namespace ShaderProcessing
for (int32 i = 0; i < _cache.Count(); i++)
{
auto& f = _cache[i];
- if (f.Slot >= MAX_CONSTANT_BUFFER_SLOTS)
+ if (f.Slot >= GPU_MAX_CB_BINDED)
{
- parser->OnError(String::Format(TEXT("Constant buffer {0} is using invalid slot {1}. Maximum supported slot is {2}."), String(f.Name), f.Slot, MAX_CONSTANT_BUFFER_SLOTS - 1));
+ parser->OnError(String::Format(TEXT("Constant buffer {0} is using invalid slot {1}. Maximum supported slot is {2}."), String(f.Name), f.Slot, GPU_MAX_CB_BINDED - 1));
return;
}
}
diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h b/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
index 5ccab5e66..a8c45d0eb 100644
--- a/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
+++ b/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
@@ -30,14 +30,12 @@ struct ShaderPermutation
class ShaderFunctionMeta
{
public:
-
///
/// Virtual destructor
///
virtual ~ShaderFunctionMeta() = default;
public:
-
///
/// Function name
///
@@ -59,7 +57,6 @@ public:
Array Permutations;
public:
-
///
/// Checks if definition name has been added to the given permutation
///
@@ -117,7 +114,6 @@ public:
}
public:
-
///
/// Gets shader function meta stage type.
///
@@ -130,9 +126,9 @@ public:
class VertexShaderMeta : public ShaderFunctionMeta
{
public:
-
///
/// Input element type
+ /// [Deprecated in v1.10]
///
enum class InputType : byte
{
@@ -150,6 +146,7 @@ public:
///
/// Input element
+ /// [Deprecated in v1.10]
///
struct InputElement
{
@@ -195,14 +192,13 @@ public:
};
public:
-
///
/// Input layout description
+ /// [Deprecated in v1.10]
///
Array InputLayout;
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -216,14 +212,12 @@ public:
class HullShaderMeta : public ShaderFunctionMeta
{
public:
-
///
/// The input control points count (valid range: 1-32).
///
int32 ControlPointsCount;
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -237,7 +231,6 @@ public:
class DomainShaderMeta : public ShaderFunctionMeta
{
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -251,7 +244,6 @@ public:
class GeometryShaderMeta : public ShaderFunctionMeta
{
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -265,7 +257,6 @@ public:
class PixelShaderMeta : public ShaderFunctionMeta
{
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -279,7 +270,6 @@ public:
class ComputeShaderMeta : public ShaderFunctionMeta
{
public:
-
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
@@ -309,7 +299,6 @@ struct ConstantBufferMeta
class ShaderMeta
{
public:
-
///
/// Vertex Shaders
///
@@ -346,18 +335,16 @@ public:
Array CB;
public:
-
///
- /// Gets amount of shaders attached (not counting permutations)
+ /// Gets amount of shaders attached (not counting permutations).
///
- /// Amount of all shader programs
- uint32 GetShadersCount() const
+ int32 GetShadersCount() const
{
return VS.Count() + HS.Count() + DS.Count() + GS.Count() + PS.Count() + CS.Count();
}
///
- /// Gets all shader functions (all types)
+ /// Gets all shader functions (all types).
///
/// Output collections of functions
void GetShaders(Array& functions) const
diff --git a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
index 72e3aacf8..bf7456b9e 100644
--- a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
+++ b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
@@ -6,7 +6,6 @@
#include "ShadersCompilation.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/Dictionary.h"
-#include "Engine/Engine/Globals.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Graphics/RenderTools.h"
@@ -14,7 +13,6 @@
#include "Engine/Threading/Threading.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Serialization/MemoryWriteStream.h"
-#include "Engine/Utilities/StringConverter.h"
namespace IncludedFiles
{
@@ -68,24 +66,12 @@ bool ShaderCompiler::Compile(ShaderCompilationContext* context)
// [Output] Constant Buffers
{
- const int32 cbsCount = _constantBuffers.Count();
- ASSERT(cbsCount == meta->CB.Count());
-
- // Find maximum used slot index
- byte maxCbSlot = 0;
- for (int32 i = 0; i < cbsCount; i++)
+ ASSERT(_constantBuffers.Count() == meta->CB.Count());
+ output->WriteByte((byte)_constantBuffers.Count());
+ for (const ShaderResourceBuffer& cb : _constantBuffers)
{
- maxCbSlot = Math::Max(maxCbSlot, _constantBuffers[i].Slot);
- }
-
- output->WriteByte(static_cast(cbsCount));
- output->WriteByte(maxCbSlot);
- // TODO: do we still need to serialize max cb slot?
-
- for (int32 i = 0; i < cbsCount; i++)
- {
- output->WriteByte(_constantBuffers[i].Slot);
- output->WriteUint32(_constantBuffers[i].Size);
+ output->WriteByte(cb.Slot);
+ output->WriteUint32(cb.Size);
}
}
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
index a6ffe9a98..98675bf6f 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
@@ -1254,6 +1254,11 @@ namespace Flax.Build.Bindings
// Read 'struct' keyword
var token = context.Tokenizer.NextToken();
+ if (token.Value == "PACK_BEGIN")
+ {
+ context.Tokenizer.SkipUntil(TokenType.RightParent);
+ token = context.Tokenizer.NextToken();
+ }
if (token.Value != "struct")
throw new ParseException(ref context, $"Invalid {ApiTokens.Struct} usage (expected 'struct' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");