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}').");