From b3f37ca041a361353426e51d6dc41c887ebe4486 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 15 Dec 2024 22:10:45 +0100 Subject: [PATCH] Refactor Vertex Shader input vertex layout to use `GPUVertexLayout` defined on Vertex Buffer rather than Vertex Shader #3044 #2667 --- .../Editor/MaterialTemplates/Particle.shader | 2 - .../Editor/MaterialTemplates/Terrain.shader | 2 - Flax.flaxproj | 4 +- Source/Editor/Gizmo/GridGizmo.cs | 3 +- Source/Engine/Debug/DebugDraw.cpp | 11 +- Source/Engine/Debug/DebugDraw.h | 3 + Source/Engine/Graphics/DynamicBuffer.cpp | 8 +- Source/Engine/Graphics/DynamicBuffer.h | 10 +- Source/Engine/Graphics/GPUBuffer.cpp | 49 +++++++- Source/Engine/Graphics/GPUBuffer.h | 8 ++ .../Engine/Graphics/GPUBufferDescription.cs | 110 +++++++++++++++- Source/Engine/Graphics/GPUBufferDescription.h | 36 +++++- Source/Engine/Graphics/GPUContext.h | 4 +- Source/Engine/Graphics/GPUDevice.cpp | 8 +- Source/Engine/Graphics/Models/Mesh.cpp | 31 ++++- Source/Engine/Graphics/Models/ModelData.h | 3 + Source/Engine/Graphics/Models/SkinnedMesh.cpp | 15 ++- Source/Engine/Graphics/Models/Types.h | 33 ++++- Source/Engine/Graphics/Shaders/GPUShader.cpp | 38 ++++-- Source/Engine/Graphics/Shaders/GPUShader.h | 5 +- .../Graphics/Shaders/GPUShaderProgram.h | 32 ++--- .../Graphics/Shaders/GPUVertexLayout.cpp | 62 +++++++++ .../Engine/Graphics/Shaders/GPUVertexLayout.h | 9 ++ .../Engine/Graphics/Shaders/VertexElement.h | 10 +- .../DirectX/DX11/GPUContextDX11.cpp | 32 ++++- .../DirectX/DX11/GPUContextDX11.h | 6 +- .../DirectX/DX11/GPUShaderDX11.cpp | 106 +++++----------- .../DirectX/DX11/GPUShaderDX11.h | 2 +- .../DirectX/DX11/GPUShaderProgramDX11.h | 83 ++---------- .../DirectX/DX12/GPUContextDX12.cpp | 13 +- .../DirectX/DX12/GPUContextDX12.h | 4 +- .../DirectX/DX12/GPUPipelineStateDX12.cpp | 22 +++- .../DirectX/DX12/GPUPipelineStateDX12.h | 12 +- .../DirectX/DX12/GPUShaderDX12.cpp | 82 ++---------- .../DirectX/DX12/GPUShaderDX12.h | 2 +- .../DirectX/DX12/GPUShaderProgramDX12.h | 58 +++------ .../GraphicsDevice/DirectX/DX12/Types.h | 2 - .../GraphicsDevice/Null/GPUContextNull.h | 2 +- .../GraphicsDevice/Null/GPUShaderNull.h | 2 +- .../Vulkan/GPUContextVulkan.cpp | 17 ++- .../GraphicsDevice/Vulkan/GPUContextVulkan.h | 4 +- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 21 ++-- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.h | 2 +- .../Vulkan/GPUPipelineStateVulkan.cpp | 26 ++-- .../Vulkan/GPUPipelineStateVulkan.h | 13 +- .../Vulkan/GPUShaderProgramVulkan.h | 78 +----------- .../GraphicsDevice/Vulkan/GPUShaderVulkan.cpp | 64 +--------- .../GraphicsDevice/Vulkan/GPUShaderVulkan.h | 2 +- Source/Engine/Level/Actors/StaticModel.cpp | 2 +- Source/Engine/Particles/Particles.cpp | 14 ++- Source/Engine/Render2D/Render2D.cpp | 9 ++ .../Renderer/GI/GlobalSurfaceAtlasPass.cpp | 10 +- Source/Engine/Renderer/RenderList.cpp | 3 +- Source/Engine/Renderer/VolumetricFogPass.cpp | 6 +- .../Parser/ShaderFunctionReader.VS.h | 9 +- .../ShadersCompilation/ShaderCompiler.cpp | 118 +++++++++++++++--- Source/Engine/Terrain/TerrainManager.cpp | 13 +- Source/Engine/Terrain/TerrainPatch.cpp | 2 +- Source/Engine/UI/TextRender.cpp | 6 +- Source/Shaders/Common.hlsl | 2 +- Source/Shaders/DebugDraw.shader | 2 - Source/Shaders/Editor/Grid.shader | 1 - Source/Shaders/GI/GlobalSurfaceAtlas.shader | 3 - Source/Shaders/GUI.shader | 5 - Source/Shaders/Quad.shader | 8 -- Source/Shaders/VolumetricFog.shader | 1 - 66 files changed, 786 insertions(+), 579 deletions(-) diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader index 5cdbc40a5..5cf8b9263 100644 --- a/Content/Editor/MaterialTemplates/Particle.shader +++ b/Content/Editor/MaterialTemplates/Particle.shader @@ -315,8 +315,6 @@ float3 GetParticlePosition(uint ParticleIndex) // Vertex Shader function for Sprite Rendering META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, 0, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID) { VertexOutput output; diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader index d2996d7a3..9b654e8f0 100644 --- a/Content/Editor/MaterialTemplates/Terrain.shader +++ b/Content/Editor/MaterialTemplates/Terrain.shader @@ -319,8 +319,6 @@ struct TerrainVertexInput // Vertex Shader function for terrain rendering META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 1, R8G8B8A8_UNORM, 0, ALIGN, PER_VERTEX, 0, true) VertexOutput VS(TerrainVertexInput input) { VertexOutput output; diff --git a/Flax.flaxproj b/Flax.flaxproj index 15b925c0d..629bf4087 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -2,9 +2,9 @@ "Name": "Flax", "Version": { "Major": 1, - "Minor": 9, + "Minor": 10, "Revision": 0, - "Build": 6606 + "Build": 6701 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.", diff --git a/Source/Editor/Gizmo/GridGizmo.cs b/Source/Editor/Gizmo/GridGizmo.cs index b5fcf9a31..293e9e84f 100644 --- a/Source/Editor/Gizmo/GridGizmo.cs +++ b/Source/Editor/Gizmo/GridGizmo.cs @@ -69,7 +69,8 @@ namespace FlaxEditor.Gizmo if (_vertexBuffer == null) { _vertexBuffer = new GPUBuffer(); - var desc = GPUBufferDescription.Vertex(sizeof(Float3), 4); + var layout = GPUVertexLayout.Get([new VertexElement(VertexElement.Types.Position, 0, 0, false, PixelFormat.R32G32B32_Float)]); + var desc = GPUBufferDescription.Vertex(layout, sizeof(Float3), 4); _vertexBuffer.Init(ref desc); } if (_indexBuffer == null) diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 447e6cabc..9f78a0b25 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -19,6 +19,7 @@ #include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/DynamicBuffer.h" #include "Engine/Graphics/Shaders/GPUConstantBuffer.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Graphics/Shaders/GPUShader.h" #include "Engine/Animations/AnimationUtils.h" #include "Engine/Profiler/Profiler.h" @@ -689,7 +690,7 @@ void DebugDrawService::Update() // Vertex buffer if (DebugDrawVB == nullptr) - DebugDrawVB = New((uint32)(DEBUG_DRAW_INITIAL_VB_CAPACITY * sizeof(Vertex)), (uint32)sizeof(Vertex), TEXT("DebugDraw.VB")); + DebugDrawVB = New((uint32)(DEBUG_DRAW_INITIAL_VB_CAPACITY * sizeof(Vertex)), (uint32)sizeof(Vertex), TEXT("DebugDraw.VB"), Vertex::GetLayout()); } void DebugDrawService::Dispose() @@ -710,6 +711,14 @@ void DebugDrawService::Dispose() DebugDrawShader = nullptr; } +GPUVertexLayout* DebugDraw::Vertex::GetLayout() +{ + return GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32B32_Float }, + { VertexElement::Types::Color, 0, 12, 0, PixelFormat::R8G8B8A8_UNorm }, + }); +} + #if USE_EDITOR void* DebugDraw::AllocateContext() diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index 6cfceca6d..f70fcc267 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -17,6 +17,7 @@ struct RenderContext; class GPUTextureView; class GPUContext; class GPUBuffer; +class GPUVertexLayout; class RenderTask; class SceneRenderTask; class Actor; @@ -35,6 +36,8 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw PACK_STRUCT(struct Vertex { Float3 Position; Color32 Color; + + static GPUVertexLayout* GetLayout(); }); #if USE_EDITOR diff --git a/Source/Engine/Graphics/DynamicBuffer.cpp b/Source/Engine/Graphics/DynamicBuffer.cpp index 8414d0a57..67192a821 100644 --- a/Source/Engine/Graphics/DynamicBuffer.cpp +++ b/Source/Engine/Graphics/DynamicBuffer.cpp @@ -67,9 +67,15 @@ void DynamicBuffer::Dispose() Data.Resize(0); } +void DynamicVertexBuffer::SetLayout(GPUVertexLayout* layout) +{ + _layout = layout; + SAFE_DELETE_GPU_RESOURCE(_buffer); +} + void DynamicVertexBuffer::InitDesc(GPUBufferDescription& desc, int32 numElements) { - desc = GPUBufferDescription::Vertex(_stride, numElements, GPUResourceUsage::Dynamic); + desc = GPUBufferDescription::Vertex(_layout, _stride, numElements, GPUResourceUsage::Dynamic); } void DynamicIndexBuffer::InitDesc(GPUBufferDescription& desc, int32 numElements) diff --git a/Source/Engine/Graphics/DynamicBuffer.h b/Source/Engine/Graphics/DynamicBuffer.h index e00ffacbd..6cc72d26b 100644 --- a/Source/Engine/Graphics/DynamicBuffer.h +++ b/Source/Engine/Graphics/DynamicBuffer.h @@ -127,6 +127,9 @@ protected: /// class FLAXENGINE_API DynamicVertexBuffer : public DynamicBuffer { +private: + GPUVertexLayout* _layout; + public: /// /// Init @@ -134,11 +137,16 @@ public: /// Initial capacity of the buffer (in bytes) /// Stride in bytes /// Buffer name - DynamicVertexBuffer(uint32 initialCapacity, uint32 stride, const String& name = String::Empty) + /// The vertex buffer layout. + DynamicVertexBuffer(uint32 initialCapacity, uint32 stride, const String& name = String::Empty, GPUVertexLayout* layout = nullptr) : DynamicBuffer(initialCapacity, stride, name) + , _layout(layout) { } + // Sets the vertex buffer layout. + void SetLayout(GPUVertexLayout* layout); + protected: // [DynamicBuffer] void InitDesc(GPUBufferDescription& desc, int32 numElements) override; diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp index 6a0221b14..b0d081d4c 100644 --- a/Source/Engine/Graphics/GPUBuffer.cpp +++ b/Source/Engine/Graphics/GPUBuffer.cpp @@ -27,6 +27,7 @@ GPUBufferDescription GPUBufferDescription::Buffer(uint32 size, GPUBufferFlags fl desc.Format = format; desc.InitData = initData; desc.Usage = usage; + desc.VertexLayout = nullptr; return desc; } @@ -48,6 +49,32 @@ GPUBufferDescription GPUBufferDescription::Typed(const void* data, int32 count, return Buffer(count * stride, bufferFlags, viewFormat, data, stride, usage); } +GPUBufferDescription GPUBufferDescription::Vertex(GPUVertexLayout* layout, uint32 elementStride, uint32 elementsCount, const void* data) +{ + GPUBufferDescription desc; + desc.Size = elementsCount * elementStride; + desc.Stride = elementStride; + desc.Flags = GPUBufferFlags::VertexBuffer; + desc.Format = PixelFormat::Unknown; + desc.InitData = data; + desc.Usage = GPUResourceUsage::Default; + desc.VertexLayout = layout; + return desc; +} + +GPUBufferDescription GPUBufferDescription::Vertex(GPUVertexLayout* layout, uint32 elementStride, uint32 elementsCount, GPUResourceUsage usage) +{ + GPUBufferDescription desc; + desc.Size = elementsCount * elementStride; + desc.Stride = elementStride; + desc.Flags = GPUBufferFlags::VertexBuffer; + desc.Format = PixelFormat::Unknown; + desc.InitData = nullptr; + desc.Usage = GPUResourceUsage::Default; + desc.VertexLayout = layout; + return desc; +} + void GPUBufferDescription::Clear() { Platform::MemoryClear(this, sizeof(GPUBufferDescription)); @@ -78,7 +105,8 @@ bool GPUBufferDescription::Equals(const GPUBufferDescription& other) const && Flags == other.Flags && Format == other.Format && Usage == other.Usage - && InitData == other.InitData; + && InitData == other.InitData + && VertexLayout == other.VertexLayout; } String GPUBufferDescription::ToString() const @@ -98,6 +126,7 @@ uint32 GetHash(const GPUBufferDescription& key) hashCode = (hashCode * 397) ^ (uint32)key.Flags; hashCode = (hashCode * 397) ^ (uint32)key.Format; hashCode = (hashCode * 397) ^ (uint32)key.Usage; + hashCode = (hashCode * 397) ^ GetHash(key.VertexLayout); return hashCode; } @@ -129,11 +158,16 @@ bool GPUBuffer::Init(const GPUBufferDescription& desc) && Math::IsInRange(desc.Stride, 0, 1024)); // Validate description +#if !BUILD_RELEASE +#define GET_NAME() GetName() +#else +#define GET_NAME() TEXT("") +#endif if (EnumHasAnyFlags(desc.Flags, GPUBufferFlags::Structured)) { if (desc.Stride <= 0) { - LOG(Warning, "Cannot create buffer. Element size cannot be less or equal 0 for structured buffer."); + LOG(Warning, "Cannot create buffer '{}'. Element size cannot be less or equal 0 for structured buffer.", GET_NAME()); return true; } } @@ -141,10 +175,19 @@ bool GPUBuffer::Init(const GPUBufferDescription& desc) { if (desc.Format != PixelFormat::R32_Typeless) { - LOG(Warning, "Cannot create buffer. Raw buffers must use format R32_Typeless."); + LOG(Warning, "Cannot create buffer '{}'. Raw buffers must use format R32_Typeless.", GET_NAME()); return true; } } + if (EnumHasAnyFlags(desc.Flags, GPUBufferFlags::VertexBuffer)) + { + if (desc.VertexLayout == nullptr) + { + // [Deprecated in v1.10] Change this into an error as VertexLayout becomes a requirement when layout is no longer set in a vertex shader + LOG(Warning, "Missing Vertex Layout in buffer '{}'. Vertex Buffers should provide layout information about contained vertex elements.", GET_NAME()); + } + } +#undef GET_NAME // Release previous data ReleaseGPU(); diff --git a/Source/Engine/Graphics/GPUBuffer.h b/Source/Engine/Graphics/GPUBuffer.h index d40b7744d..d8eb70a0f 100644 --- a/Source/Engine/Graphics/GPUBuffer.h +++ b/Source/Engine/Graphics/GPUBuffer.h @@ -85,6 +85,14 @@ public: return _desc.Flags; } + /// + /// Gets vertex elements layout used by vertex buffers only. + /// + API_PROPERTY() FORCE_INLINE GPUVertexLayout* GetVertexLayout() const + { + return _desc.VertexLayout; + } + /// /// Checks if buffer is a staging buffer (supports CPU readback). /// diff --git a/Source/Engine/Graphics/GPUBufferDescription.cs b/Source/Engine/Graphics/GPUBufferDescription.cs index 6bc0051a8..ee64a86c5 100644 --- a/Source/Engine/Graphics/GPUBufferDescription.cs +++ b/Source/Engine/Graphics/GPUBufferDescription.cs @@ -48,6 +48,7 @@ namespace FlaxEngine desc.Format = format; desc.InitData = initData; desc.Usage = usage; + desc.VertexLayout = null; return desc; } @@ -70,6 +71,7 @@ namespace FlaxEngine desc.Format = format; desc.InitData = initData; desc.Usage = usage; + desc.VertexLayout = null; return desc; } @@ -117,11 +119,55 @@ namespace FlaxEngine /// /// Creates vertex buffer description. /// + /// The vertex buffer layout. /// The element stride. /// The elements count. /// The data. /// The buffer description. - public static GPUBufferDescription Vertex(int elementStride, int elementsCount, IntPtr data) + public static GPUBufferDescription Vertex(GPUVertexLayout layout, int elementStride, int elementsCount, IntPtr data) + { + GPUBufferDescription desc; + desc.Size = (uint)(elementsCount * elementStride); + desc.Stride = (uint)elementStride; + desc.Flags = GPUBufferFlags.VertexBuffer; + desc.Format = PixelFormat.Unknown; + desc.InitData = data; + desc.Usage = GPUResourceUsage.Default; + desc.VertexLayout = layout; + return desc; + } + + /// + /// Creates vertex buffer description. + /// + /// The vertex buffer layout. + /// The element stride. + /// The elements count. + /// The usage mode. + /// The buffer description. + public static GPUBufferDescription Vertex(GPUVertexLayout layout, int elementStride, int elementsCount, GPUResourceUsage usage = GPUResourceUsage.Default) + { + GPUBufferDescription desc; + desc.Size = (uint)(elementsCount * elementStride); + desc.Stride = (uint)elementStride; + desc.Flags = GPUBufferFlags.VertexBuffer; + desc.Format = PixelFormat.Unknown; + desc.InitData = new IntPtr(); + desc.Usage = usage; + desc.VertexLayout = layout; + return desc; + } + + /// + /// Creates vertex buffer description. + /// + /// The element stride. + /// The elements count. + /// The data. + /// The vertex buffer layout. + /// The buffer description. + [Obsolete("Use Vertex with vertex layout parameter instead")] + public static GPUBufferDescription Vertex(int elementStride, int elementsCount, IntPtr data, GPUVertexLayout layout = null) { return Buffer(elementsCount * elementStride, GPUBufferFlags.VertexBuffer, PixelFormat.Unknown, data, elementStride, GPUResourceUsage.Default); } @@ -132,18 +178,22 @@ namespace FlaxEngine /// The element stride. /// The elements count. /// The usage mode. + /// The vertex buffer layout. /// The buffer description. - public static GPUBufferDescription Vertex(int elementStride, int elementsCount, GPUResourceUsage usage = GPUResourceUsage.Default) + [Obsolete("Use Vertex with vertex layout parameter instead")] + public static GPUBufferDescription Vertex(int elementStride, int elementsCount, GPUResourceUsage usage = GPUResourceUsage.Default, GPUVertexLayout layout = null) { return Buffer(elementsCount * elementStride, GPUBufferFlags.VertexBuffer, PixelFormat.Unknown, new IntPtr(), elementStride, usage); } /// /// Creates vertex buffer description. + /// [Deprecated in v1.10] /// /// The size (in bytes). /// The usage mode. /// The buffer description. + [Obsolete("Use Vertex with separate vertex stride and count instead")] public static GPUBufferDescription Vertex(int size, GPUResourceUsage usage = GPUResourceUsage.Default) { return Buffer(size, GPUBufferFlags.VertexBuffer, PixelFormat.Unknown, new IntPtr(), 0, usage); @@ -190,7 +240,6 @@ namespace FlaxEngine var bufferFlags = GPUBufferFlags.Structured | GPUBufferFlags.ShaderResource; if (isUnorderedAccess) bufferFlags |= GPUBufferFlags.UnorderedAccess; - return Buffer(elementCount * elementSize, bufferFlags, PixelFormat.Unknown, new IntPtr(), elementSize); } @@ -304,7 +353,8 @@ namespace FlaxEngine Flags == other.Flags && Format == other.Format && InitData.Equals(other.InitData) && - Usage == other.Usage; + Usage == other.Usage && + VertexLayout == other.VertexLayout; } /// @@ -324,6 +374,58 @@ namespace FlaxEngine hashCode = (hashCode * 397) ^ (int)Format; hashCode = (hashCode * 397) ^ InitData.GetHashCode(); hashCode = (hashCode * 397) ^ (int)Usage; + if (VertexLayout != null) + hashCode = (hashCode * 397) ^ VertexLayout.GetHashCode(); + return hashCode; + } + } + } + + partial struct VertexElement : IEquatable + { + /// + /// Creates the vertex element description. + /// + /// Element type. + /// Vertex buffer bind slot. + /// Data byte offset. + /// True if element data is instanced. + /// Data format. + public VertexElement(Types type, byte slot, byte offset, bool perInstance, PixelFormat format) + { + Type = type; + Slot = slot; + Offset = offset; + PerInstance = (byte)(perInstance ? 1 : 0); + Format = format; + } + + /// + public bool Equals(VertexElement other) + { + return Type == other.Type && + Slot == other.Slot && + Offset == other.Offset && + PerInstance == other.PerInstance && + Format == other.Format; + } + + /// + public override bool Equals(object obj) + { + return obj is VertexElement other && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + var hashCode = (int)Type; + hashCode = (hashCode * 397) ^ Slot; + hashCode = (hashCode * 397) ^ Offset; + hashCode = (hashCode * 397) ^ PerInstance; + hashCode = (hashCode * 397) ^ (int)Format; return hashCode; } } diff --git a/Source/Engine/Graphics/GPUBufferDescription.h b/Source/Engine/Graphics/GPUBufferDescription.h index d4049ea5b..73f459da2 100644 --- a/Source/Engine/Graphics/GPUBufferDescription.h +++ b/Source/Engine/Graphics/GPUBufferDescription.h @@ -5,6 +5,8 @@ #include "Enums.h" #include "PixelFormat.h" +class GPUVertexLayout; + /// /// The GPU buffer usage flags. /// @@ -110,6 +112,11 @@ API_STRUCT() struct FLAXENGINE_API GPUBufferDescription /// API_FIELD() GPUResourceUsage Usage; + /// + /// The vertex elements layout used by vertex buffers only. + /// + API_FIELD() GPUVertexLayout* VertexLayout; + public: /// /// Gets the number elements in the buffer. @@ -178,34 +185,57 @@ public: /// /// Creates vertex buffer description. /// + /// The vertex buffer layout. /// The element stride. /// The elements count. /// The data. /// The buffer description. - static GPUBufferDescription Vertex(int32 elementStride, int32 elementsCount, const void* data) + static GPUBufferDescription Vertex(GPUVertexLayout* layout, uint32 elementStride, uint32 elementsCount, const void* data); + + /// + /// Creates vertex buffer description. + /// + /// The vertex buffer layout. + /// The element stride. + /// The elements count. + /// The usage mode. + /// The buffer description. + static GPUBufferDescription Vertex(GPUVertexLayout* layout, uint32 elementStride, uint32 elementsCount, GPUResourceUsage usage = GPUResourceUsage::Default); + + /// + /// Creates vertex buffer description. + /// [Deprecated in v1.10] + /// + /// The element stride. + /// The elements count. + /// The data. + /// The buffer description. + DEPRECATED("Use Vertex with vertex layout parameter instead") static GPUBufferDescription Vertex(int32 elementStride, int32 elementsCount, const void* data) { return Buffer(elementsCount * elementStride, GPUBufferFlags::VertexBuffer, PixelFormat::Unknown, data, elementStride, GPUResourceUsage::Default); } /// /// Creates vertex buffer description. + /// [Deprecated in v1.10] /// /// The element stride. /// The elements count. /// The usage mode. /// The buffer description. - static GPUBufferDescription Vertex(int32 elementStride, int32 elementsCount, GPUResourceUsage usage = GPUResourceUsage::Default) + DEPRECATED("Use Vertex with vertex layout parameter instead") static GPUBufferDescription Vertex(int32 elementStride, int32 elementsCount, GPUResourceUsage usage = GPUResourceUsage::Default) { return Buffer(elementsCount * elementStride, GPUBufferFlags::VertexBuffer, PixelFormat::Unknown, nullptr, elementStride, usage); } /// /// Creates vertex buffer description. + /// [Deprecated in v1.10] /// /// The size (in bytes). /// The usage mode. /// The buffer description. - static GPUBufferDescription Vertex(int32 size, GPUResourceUsage usage = GPUResourceUsage::Default) + DEPRECATED("Use Vertex with separate vertex stride and count instead") static GPUBufferDescription Vertex(int32 size, GPUResourceUsage usage = GPUResourceUsage::Default) { return Buffer(size, GPUBufferFlags::VertexBuffer, PixelFormat::Unknown, nullptr, 0, usage); } diff --git a/Source/Engine/Graphics/GPUContext.h b/Source/Engine/Graphics/GPUContext.h index 52ff5ef5d..2f326c205 100644 --- a/Source/Engine/Graphics/GPUContext.h +++ b/Source/Engine/Graphics/GPUContext.h @@ -20,6 +20,7 @@ class GPUResource; class GPUResourceView; class GPUTextureView; class GPUBufferView; +class GPUVertexLayout; // Gets the GPU texture view. Checks if pointer is not null and texture has one or more mip levels loaded. #define GET_TEXTURE_VIEW_SAFE(t) (t && t->ResidentMipLevels() > 0 ? t->View() : nullptr) @@ -404,7 +405,8 @@ public: /// /// The array of vertex buffers to use. /// The optional array of byte offsets from the vertex buffers begins. Can be used to offset the vertex data when reusing the same buffer allocation for multiple geometry objects. - API_FUNCTION() virtual void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) = 0; + /// The optional vertex layout to use when passing data from vertex buffers to the vertex shader. If null, layout will be automatically extracted from vertex buffers combined. + API_FUNCTION() virtual void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) = 0; /// /// Binds the index buffer to the pipeline. diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 2f42ac08b..ad87261af 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -26,6 +26,8 @@ #include "Engine/Renderer/RenderList.h" #include "Engine/Scripting/Enums.h" +#include "Shaders/GPUVertexLayout.h" + GPUResourcePropertyBase::~GPUResourcePropertyBase() { const auto e = _resource; @@ -386,7 +388,11 @@ bool GPUDevice::LoadContent() }; // @formatter:on _res->FullscreenTriangleVB = CreateBuffer(TEXT("QuadVB")); - if (_res->FullscreenTriangleVB->Init(GPUBufferDescription::Vertex(sizeof(float) * 4, 3, vb))) + auto layout = GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32_Float }, + { VertexElement::Types::TexCoord, 0, 8, 0, PixelFormat::R32G32_Float }, + }); + if (_res->FullscreenTriangleVB->Init(GPUBufferDescription::Vertex(layout, 16, 3, vb))) return true; } diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 77c2089e1..b0ab1356b 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -11,6 +11,7 @@ #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderTools.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Scripting/ManagedCLR/MCore.h" @@ -21,6 +22,30 @@ #include "Engine/Renderer/GBufferPass.h" #endif +GPUVertexLayout* VB0ElementType18::GetLayout() +{ + return GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32B32_Float }, + }); +} + +GPUVertexLayout* VB1ElementType18::GetLayout() +{ + return GPUVertexLayout::Get({ + { VertexElement::Types::TexCoord, 1, 0, 0, PixelFormat::R16G16_Float }, + { VertexElement::Types::Normal, 1, 0, 0, PixelFormat::R10G10B10A2_UNorm }, + { VertexElement::Types::Tangent, 1, 0, 0, PixelFormat::R10G10B10A2_UNorm }, + { VertexElement::Types::TexCoord1, 1, 0, 0, PixelFormat::R16G16_Float }, + }); +} + +GPUVertexLayout* VB2ElementType18::GetLayout() +{ + return GPUVertexLayout::Get({ + { VertexElement::Types::Color, 2, 0, 0, PixelFormat::R8G8B8A8_UNorm }, + }); +} + namespace { template @@ -233,15 +258,15 @@ bool Mesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const void* #define MESH_BUFFER_NAME(postfix) String::Empty #endif vertexBuffer0 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB0")); - if (vertexBuffer0->Init(GPUBufferDescription::Vertex(sizeof(VB0ElementType), vertices, vb0))) + if (vertexBuffer0->Init(GPUBufferDescription::Vertex(VB0ElementType::GetLayout(), sizeof(VB0ElementType), vertices, vb0))) goto ERROR_LOAD_END; vertexBuffer1 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB1")); - if (vertexBuffer1->Init(GPUBufferDescription::Vertex(sizeof(VB1ElementType), vertices, vb1))) + if (vertexBuffer1->Init(GPUBufferDescription::Vertex(VB1ElementType::GetLayout(), sizeof(VB1ElementType), vertices, vb1))) goto ERROR_LOAD_END; if (vb2) { vertexBuffer2 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB2")); - if (vertexBuffer2->Init(GPUBufferDescription::Vertex(sizeof(VB2ElementType), vertices, vb2))) + if (vertexBuffer2->Init(GPUBufferDescription::Vertex(VB2ElementType::GetLayout(), sizeof(VB2ElementType), vertices, vb2))) goto ERROR_LOAD_END; } indexBuffer = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".IB")); diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h index 7278611e6..87b0abe63 100644 --- a/Source/Engine/Graphics/Models/ModelData.h +++ b/Source/Engine/Graphics/Models/ModelData.h @@ -151,6 +151,7 @@ public: /// /// Init from model vertices array + /// [Deprecated on 28.04.2023, expires on 01.01.2024] /// /// Array of vertices /// Amount of vertices @@ -158,6 +159,7 @@ public: /// /// Init from model vertices array + /// [Deprecated on 28.04.2023, expires on 01.01.2024] /// /// Array of vertices /// Amount of vertices @@ -182,6 +184,7 @@ public: /// /// Init from model vertices array + /// [Deprecated on 28.04.2023, expires on 01.01.2024] /// /// Array of data for vertex buffer 0 /// Array of data for vertex buffer 1 diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 207ff8991..1d9ab1df0 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -10,6 +10,7 @@ #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderTools.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Level/Scene/Scene.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Serialization/MemoryReadStream.h" @@ -18,6 +19,18 @@ #include "Engine/Threading/Task.h" #include "Engine/Threading/Threading.h" +GPUVertexLayout* VB0SkinnedElementType2::GetLayout() +{ + return GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32B32_Float }, + { VertexElement::Types::TexCoord, 0, 0, 0, PixelFormat::R16G16_Float }, + { VertexElement::Types::Normal, 0, 0, 0, PixelFormat::R10G10B10A2_UNorm }, + { VertexElement::Types::Tangent, 0, 0, 0, PixelFormat::R10G10B10A2_UNorm }, + { VertexElement::Types::BlendIndices, 0, 0, 0, PixelFormat::R8G8B8A8_UInt }, + { VertexElement::Types::BlendWeight, 0, 0, 0, PixelFormat::R16G16B16A16_Float }, + }); +} + void SkeletonData::Swap(SkeletonData& other) { Nodes.Swap(other.Nodes); @@ -120,7 +133,7 @@ bool SkinnedMesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const #else vertexBuffer = GPUDevice::Instance->CreateBuffer(String::Empty); #endif - if (vertexBuffer->Init(GPUBufferDescription::Vertex(sizeof(VB0SkinnedElementType), vertices, vb0))) + if (vertexBuffer->Init(GPUBufferDescription::Vertex(VB0SkinnedElementType::GetLayout(), sizeof(VB0SkinnedElementType), vertices, vb0))) goto ERROR_LOAD_END; // Create index buffer diff --git a/Source/Engine/Graphics/Models/Types.h b/Source/Engine/Graphics/Models/Types.h index 0d30e3b4a..1f57cfa2c 100644 --- a/Source/Engine/Graphics/Models/Types.h +++ b/Source/Engine/Graphics/Models/Types.h @@ -21,6 +21,7 @@ class Model; class SkinnedModel; class MeshDeformation; class GPUContext; +class GPUVertexLayout; struct RenderView; /// @@ -69,6 +70,7 @@ enum class MeshBufferType }; // Vertex structure for all models (versioned) +// [Deprecated on 28.04.2023, expires on 01.01.2024] PACK_STRUCT(struct ModelVertex15 { Float3 Position; @@ -77,6 +79,7 @@ PACK_STRUCT(struct ModelVertex15 Float1010102 Tangent; }); +// [Deprecated on 28.04.2023, expires on 01.01.2024] PACK_STRUCT(struct ModelVertex18 { Float3 Position; @@ -86,6 +89,7 @@ PACK_STRUCT(struct ModelVertex18 Half2 LightmapUVs; }); +// [Deprecated in v1.10] PACK_STRUCT(struct ModelVertex19 { Float3 Position; @@ -96,9 +100,10 @@ PACK_STRUCT(struct ModelVertex19 Color32 Color; }); +// [Deprecated in v1.10] typedef ModelVertex19 ModelVertex; -// +// [Deprecated in v1.10] struct RawModelVertex { Float3 Position; @@ -111,11 +116,12 @@ struct RawModelVertex }; // For vertex data we use three buffers: one with positions, one with other attributes, and one with colors +// [Deprecated on 28.04.2023, expires on 01.01.2024] PACK_STRUCT(struct VB0ElementType15 { Float3 Position; }); - +// [Deprecated on 28.04.2023, expires on 01.01.2024] PACK_STRUCT(struct VB1ElementType15 { Half2 TexCoord; @@ -123,30 +129,42 @@ PACK_STRUCT(struct VB1ElementType15 Float1010102 Tangent; }); +// [Deprecated in v1.10] PACK_STRUCT(struct VB0ElementType18 { Float3 Position; + + static GPUVertexLayout* GetLayout(); }); +// [Deprecated in v1.10] PACK_STRUCT(struct VB1ElementType18 { Half2 TexCoord; Float1010102 Normal; Float1010102 Tangent; Half2 LightmapUVs; + + static GPUVertexLayout* GetLayout(); }); +// [Deprecated in v1.10] PACK_STRUCT(struct VB2ElementType18 { Color32 Color; + + static GPUVertexLayout* GetLayout(); }); +// [Deprecated in v1.10] typedef VB0ElementType18 VB0ElementType; +// [Deprecated in v1.10] typedef VB1ElementType18 VB1ElementType; +// [Deprecated in v1.10] typedef VB2ElementType18 VB2ElementType; -// // Vertex structure for all skinned models (versioned) +// [Deprecated in v1.10] PACK_STRUCT(struct SkinnedModelVertex1 { Float3 Position; @@ -157,9 +175,10 @@ PACK_STRUCT(struct SkinnedModelVertex1 Color32 BlendWeights; }); +// [Deprecated in v1.10] typedef SkinnedModelVertex1 SkinnedModelVertex; -// +// [Deprecated in v1.10] struct RawSkinnedModelVertex { Float3 Position; @@ -171,6 +190,7 @@ struct RawSkinnedModelVertex Float4 BlendWeights; }; +// [Deprecated on 28.04.2023, expires on 01.01.2024] PACK_STRUCT(struct VB0SkinnedElementType1 { Float3 Position; @@ -181,6 +201,7 @@ PACK_STRUCT(struct VB0SkinnedElementType1 Color32 BlendWeights; }); +// [Deprecated in v1.10] PACK_STRUCT(struct VB0SkinnedElementType2 { Float3 Position; @@ -189,7 +210,9 @@ PACK_STRUCT(struct VB0SkinnedElementType2 Float1010102 Tangent; Color32 BlendIndices; Half4 BlendWeights; + + static GPUVertexLayout* GetLayout(); }); +// [Deprecated in v1.10] typedef VB0SkinnedElementType2 VB0SkinnedElementType; -// diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp index b29d3236b..33f54582f 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.cpp +++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp @@ -4,6 +4,7 @@ #include "GPUConstantBuffer.h" #include "Engine/Core/Log.h" #include "Engine/Core/Math/Math.h" +#include "Engine/Core/Types/Span.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Serialization/MemoryReadStream.h" @@ -23,11 +24,6 @@ void GPUShaderProgram::Init(const GPUShaderProgramInitializer& initializer) #endif } -GPUShaderProgramVS::~GPUShaderProgramVS() -{ - SAFE_DELETE(Layout); -} - GPUShader::GPUShader() : GPUResource(SpawnParams(Guid::New(), TypeInitializer)) { @@ -77,15 +73,15 @@ bool GPUShader::Create(MemoryReadStream& stream) for (int32 permutationIndex = 0; permutationIndex < permutationsCount; permutationIndex++) { - // Load cache - uint32 cacheSize; - stream.ReadUint32(&cacheSize); - if (cacheSize > stream.GetLength() - stream.GetPosition()) + // Load bytecode + uint32 bytecodeSize; + stream.ReadUint32(&bytecodeSize); + if (bytecodeSize > stream.GetLength() - stream.GetPosition()) { - LOG(Warning, "Invalid shader cache size."); + LOG(Warning, "Invalid shader bytecode size."); return true; } - byte* cache = stream.Move(cacheSize); + byte* bytecode = stream.Move(bytecodeSize); // Read bindings stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings)); @@ -96,7 +92,7 @@ bool GPUShader::Create(MemoryReadStream& stream) LOG(Warning, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name); continue; } - GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream); + GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, Span(bytecode, bytecodeSize), stream); if (shader == nullptr) { #if !GPU_ALLOW_TESSELLATION_SHADERS @@ -181,6 +177,24 @@ GPUShaderProgram* GPUShader::GetShader(ShaderStage stage, const StringAnsiView& return shader; } +GPUVertexLayout* GPUShader::ReadVertexLayout(MemoryReadStream& stream) +{ + // [Deprecated in v1.10] + byte inputLayoutSize; + stream.ReadByte(&inputLayoutSize); + if (inputLayoutSize == 0) + return nullptr; + void* elementsData = stream.Move(sizeof(VertexElement) * inputLayoutSize); + if (inputLayoutSize > GPU_MAX_VS_ELEMENTS) + { + LOG(Error, "Incorrect input layout size."); + return nullptr; + } + GPUVertexLayout::Elements elements; + elements.Set((VertexElement*)elementsData, inputLayoutSize); + return GPUVertexLayout::Get(elements); +} + GPUResourceType GPUShader::GetResourceType() const { return GPUResourceType::Shader; diff --git a/Source/Engine/Graphics/Shaders/GPUShader.h b/Source/Engine/Graphics/Shaders/GPUShader.h index 035619c2e..6879c3d5b 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 10 +#define GPU_SHADER_CACHE_VERSION 11 /// /// 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. @@ -134,7 +134,8 @@ public: protected: GPUShaderProgram* GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const; - virtual GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) = 0; + virtual GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) = 0; + static GPUVertexLayout* ReadVertexLayout(MemoryReadStream& stream); public: // [GPUResource] diff --git a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h index 9447e04a5..aa8368ea0 100644 --- a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h +++ b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h @@ -115,20 +115,11 @@ 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] + // [Deprecated in v1.10] Use VertexElement instead. PACK_STRUCT(struct InputElement - { + { byte Type; // VertexShaderMeta::InputType byte Index; byte Format; // PixelFormat @@ -136,19 +127,14 @@ public: uint32 AlignedByteOffset; // Fixed value or INPUT_LAYOUT_ELEMENT_ALIGN if auto byte InputSlotClass; // INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA or INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA uint32 InstanceDataStepRate; // 0 if per-vertex - }); + }); - /// - /// 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; + // 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. + // (don't release it as it's managed by GPUVertexLayout::Get) + // [Deprecated in v1.10] + GPUVertexLayout* Layout = nullptr; public: // [GPUShaderProgram] diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp index d90613a31..6a4b8e677 100644 --- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp +++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.cpp @@ -5,7 +5,9 @@ #include "Engine/Core/Log.h" #endif #include "Engine/Core/Collections/Dictionary.h" +#include "Engine/Core/Types/Span.h" #include "Engine/Graphics/GPUDevice.h" +#include "Engine/Graphics/GPUBuffer.h" #if GPU_ENABLE_RESOURCE_NAMING #include "Engine/Scripting/Enums.h" #endif @@ -18,10 +20,29 @@ struct VertexElementRaw static_assert(sizeof(VertexElement) == sizeof(VertexElementRaw), "Incorrect size of the VertexElement!"); +struct VertexBufferLayouts +{ + GPUVertexLayout* Layouts[GPU_MAX_VB_BINDED]; + + bool operator==(const VertexBufferLayouts& other) const + { + return Platform::MemoryCompare(&Layouts, &other.Layouts, sizeof(Layouts)) == 0; + } +}; + +uint32 GetHash(const VertexBufferLayouts& key) +{ + uint32 hash = GetHash(key.Layouts[0]); + for (int32 i = 1; i < GPU_MAX_VB_BINDED; i++) + CombineHash(hash, GetHash(key.Layouts[i])); + return hash; +} + namespace { CriticalSection CacheLocker; Dictionary LayoutCache; + Dictionary VertexBufferCache; } String VertexElement::ToString() const @@ -95,9 +116,50 @@ GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements) return result; } +GPUVertexLayout* GPUVertexLayout::Get(const Span& vertexBuffers) +{ + if (vertexBuffers.Length() == 0) + return nullptr; + if (vertexBuffers.Length() == 1) + return vertexBuffers.Get()[0] ? vertexBuffers.Get()[0]->GetVertexLayout() : nullptr; + + // Build hash key for set of buffers (in case there is layout sharing by different sets of buffers) + VertexBufferLayouts layouts; + for (int32 i = 0; i < vertexBuffers.Length(); i++) + layouts.Layouts[i] = vertexBuffers.Get()[i] ? vertexBuffers.Get()[i]->GetVertexLayout() : nullptr; + for (int32 i = vertexBuffers.Length(); i < GPU_MAX_VB_BINDED; i++) + layouts.Layouts[i] = nullptr; + + // Lookup existing cache + CacheLocker.Lock(); + GPUVertexLayout* result; + if (!VertexBufferCache.TryGet(layouts, result)) + { + Elements elements; + bool anyValid = false; + for (int32 slot = 0; slot < vertexBuffers.Length(); slot++) + { + if (layouts.Layouts[slot]) + { + anyValid = true; + int32 start = elements.Count(); + elements.Add(layouts.Layouts[slot]->GetElements()); + for (int32 j = start; j < elements.Count() ;j++) + elements.Get()[j].Slot = (byte)slot; + } + } + result = anyValid ? Get(elements) : nullptr; + VertexBufferCache.Add(layouts, result); + } + CacheLocker.Unlock(); + + return result; +} + void ClearVertexLayoutCache() { for (const auto& e : LayoutCache) Delete(e.Value); LayoutCache.Clear(); + VertexBufferCache.Clear(); } diff --git a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h index a3f5158bc..8d60573b8 100644 --- a/Source/Engine/Graphics/Shaders/GPUVertexLayout.h +++ b/Source/Engine/Graphics/Shaders/GPUVertexLayout.h @@ -6,6 +6,8 @@ #include "Engine/Graphics/GPUResource.h" #include "Engine/Core/Collections/Array.h" +class GPUBuffer; + /// /// Defines input layout of vertex buffer data passed to the Vertex Shader. /// @@ -35,6 +37,13 @@ public: /// 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); + /// + /// Gets the vertex layout for a given list of vertex buffers (sequence of binding slots based on layouts set on those buffers). Uses internal cache to skip creating layout if it's already exists for a given list. + /// + /// The list of vertex buffers 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 Span& vertexBuffers); + public: // [GPUResource] GPUResourceType GetResourceType() const override diff --git a/Source/Engine/Graphics/Shaders/VertexElement.h b/Source/Engine/Graphics/Shaders/VertexElement.h index edf2d5df6..06bf0dbb5 100644 --- a/Source/Engine/Graphics/Shaders/VertexElement.h +++ b/Source/Engine/Graphics/Shaders/VertexElement.h @@ -63,15 +63,15 @@ PACK_BEGIN() struct FLAXENGINE_API VertexElement }; // Type of the vertex element data. - Types Type; + API_FIELD() Types Type; // Index of the input vertex buffer slot (as provided in GPUContext::BindVB). - byte Slot; + API_FIELD() byte Slot; // Byte offset of this element relative to the start of a vertex buffer. Use value 0 to use auto-calculated offset based on previous elements in the layout (or for the first one). - byte Offset; + API_FIELD() byte Offset; // Flag used to mark data using hardware-instancing (element will be repeated for every instance). Empty to step data per-vertex when reading input buffer stream (rather than per-instance step). - byte PerInstance; + API_FIELD() byte PerInstance; // Format of the vertex element data. - PixelFormat Format; + API_FIELD() PixelFormat Format; String ToString() const; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp index 0ff1392ec..f045f768a 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp @@ -9,6 +9,7 @@ #include "GPUTextureDX11.h" #include "GPUBufferDX11.h" #include "GPUSamplerDX11.h" +#include "GPUVertexLayoutDX11.h" #include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h" #include "Engine/Core/Math/Viewport.h" #include "Engine/Core/Math/Rectangle.h" @@ -82,9 +83,11 @@ void GPUContextDX11::FrameBegin() _omDirtyFlag = false; _uaDirtyFlag = false; _cbDirtyFlag = false; + _iaInputLayoutDirtyFlag = false; _srMaskDirtyGraphics = 0; _srMaskDirtyCompute = 0; _rtCount = 0; + _vertexLayout = nullptr; _currentState = nullptr; _rtDepth = nullptr; Platform::MemoryClear(_rtHandles, sizeof(_rtHandles)); @@ -380,7 +383,7 @@ void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view) } } -void GPUContextDX11::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets) +void GPUContextDX11::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout) { ASSERT(vertexBuffers.Length() >= 0 && vertexBuffers.Length() <= GPU_MAX_VB_BINDED); @@ -402,6 +405,13 @@ void GPUContextDX11::BindVB(const Span& vertexBuffers, const uint32* { _context->IASetVertexBuffers(0, vertexBuffers.Length(), _vbHandles, _vbStrides, _vbOffsets); } + if (!vertexLayout) + vertexLayout = GPUVertexLayout::Get(vertexBuffers); + if (_vertexLayout != vertexLayout) + { + _vertexLayout = (GPUVertexLayoutDX11*)vertexLayout; + _iaInputLayoutDirtyFlag = true; + } } void GPUContextDX11::BindIB(GPUBuffer* indexBuffer) @@ -610,7 +620,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state) #endif CurrentVS = vs; _context->VSSetShader(vs ? vs->GetBufferHandleDX11() : nullptr, nullptr, 0); - _context->IASetInputLayout(vs ? vs->GetInputLayoutDX11() : nullptr); + _iaInputLayoutDirtyFlag = true; } #if GPU_ALLOW_TESSELLATION_SHADERS if (CurrentHS != hs) @@ -720,6 +730,7 @@ void GPUContextDX11::FlushState() flushCBs(); flushSRVs(); flushUAVs(); + flushIA(); flushOM(); } @@ -932,11 +943,28 @@ void GPUContextDX11::flushOM() } } +void GPUContextDX11::flushIA() +{ + if (_iaInputLayoutDirtyFlag) + { + _iaInputLayoutDirtyFlag = false; + ID3D11InputLayout* inputLayout = CurrentVS ? CurrentVS->GetInputLayout(_vertexLayout) : nullptr; +#if GPU_ENABLE_ASSERTION_LOW_LAYERS + if (!inputLayout && CurrentVS && !_vertexLayout && _vbHandles[0]) + { + LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals."); + } +#endif + _context->IASetInputLayout(inputLayout); + } +} + void GPUContextDX11::onDrawCall() { flushCBs(); flushSRVs(); flushUAVs(); + flushIA(); flushOM(); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h index 08225ca41..2d2b5b986 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h @@ -10,6 +10,7 @@ #if GRAPHICS_API_DIRECTX11 class GPUBufferDX11; +class GPUVertexLayoutDX11; /// /// GPU Context for DirectX 11 backend. @@ -49,6 +50,8 @@ private: ID3D11Buffer* _vbHandles[GPU_MAX_VB_BINDED]; UINT _vbStrides[GPU_MAX_VB_BINDED]; UINT _vbOffsets[GPU_MAX_VB_BINDED]; + GPUVertexLayoutDX11* _vertexLayout; + bool _iaInputLayoutDirtyFlag; // Pipeline State GPUPipelineStateDX11* _currentState; @@ -100,6 +103,7 @@ private: void flushUAVs(); void flushCBs(); void flushOM(); + void flushIA(); void onDrawCall(); public: @@ -130,7 +134,7 @@ public: void BindCB(int32 slot, GPUConstantBuffer* cb) override; void BindSR(int32 slot, GPUResourceView* view) override; void BindUA(int32 slot, GPUResourceView* view) override; - void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; + void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp index 70018233d..faf50a927 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp @@ -4,10 +4,33 @@ #include "GPUShaderDX11.h" #include "GPUShaderProgramDX11.h" +#include "GPUVertexLayoutDX11.h" #include "Engine/Serialization/MemoryReadStream.h" #include "../RenderToolsDX.h" -GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) +GPUShaderProgramVSDX11::~GPUShaderProgramVSDX11() +{ + for (const auto& e : _cache) + e.Value->Release(); +} + +ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* vertexLayout) +{ + if (!vertexLayout) + vertexLayout = (GPUVertexLayoutDX11*)Layout; + ID3D11InputLayout* inputLayout = nullptr; + if (!_cache.TryGet(vertexLayout, inputLayout)) + { + if (vertexLayout && vertexLayout->InputElementsCount) + { + VALIDATE_DIRECTX_CALL(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(vertexLayout->InputElements, vertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout)); + } + _cache.Add(vertexLayout, inputLayout); + } + return inputLayout; +} + +GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) { GPUShaderProgram* shader = nullptr; HRESULT result; @@ -16,80 +39,15 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const case ShaderStage::Vertex: { // Load Input Layout - byte inputLayoutSize; - stream.ReadByte(&inputLayoutSize); - ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS); - D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; - for (int32 a = 0; a < inputLayoutSize; a++) - { - // Read description - GPUShaderProgramVS::InputElement inputElement; - stream.Read(inputElement); - - // Get semantic name - const char* semanticName = nullptr; - // TODO: maybe use enum+mapping ? - switch (inputElement.Type) - { - case 1: - semanticName = "POSITION"; - break; - case 2: - semanticName = "COLOR"; - break; - case 3: - semanticName = "TEXCOORD"; - break; - case 4: - semanticName = "NORMAL"; - break; - case 5: - semanticName = "TANGENT"; - break; - case 6: - semanticName = "BITANGENT"; - break; - case 7: - semanticName = "ATTRIBUTE"; - break; - case 8: - semanticName = "BLENDINDICES"; - break; - case 9: - semanticName = "BLENDWEIGHT"; - break; - default: - LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type); - break; - } - - // Set data - inputLayoutDesc[a] = - { - semanticName, - static_cast(inputElement.Index), - static_cast(inputElement.Format), - static_cast(inputElement.InputSlot), - static_cast(inputElement.AlignedByteOffset), - static_cast(inputElement.InputSlotClass), - static_cast(inputElement.InstanceDataStepRate) - }; - } - - ID3D11InputLayout* inputLayout = nullptr; - if (inputLayoutSize > 0) - { - // Create input layout - VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout)); - } + GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); // Create shader ID3D11VertexShader* buffer = nullptr; - result = _device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreateVertexShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object - shader = New(initializer, buffer, inputLayout, inputLayoutSize); + shader = New(initializer, buffer, vertexLayout, bytecode); break; } #if GPU_ALLOW_TESSELLATION_SHADERS @@ -101,7 +59,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const // Create shader ID3D11HullShader* buffer = nullptr; - result = _device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreateHullShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object @@ -112,7 +70,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const { // Create shader ID3D11DomainShader* buffer = nullptr; - result = _device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreateDomainShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object @@ -132,7 +90,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const { // Create shader ID3D11GeometryShader* buffer = nullptr; - result = _device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreateGeometryShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object @@ -144,7 +102,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const { // Create shader ID3D11PixelShader* buffer = nullptr; - result = _device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreatePixelShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object @@ -155,7 +113,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const { // Create shader ID3D11ComputeShader* buffer = nullptr; - result = _device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer); + result = _device->GetDevice()->CreateComputeShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); // Create object diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h index 3ccfa85c7..7070644e4 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.h @@ -80,7 +80,7 @@ public: protected: // [GPUShader] - GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override; + GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) override; void OnReleaseGPU() override; public: diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h index 519afcbfc..d43e60b2d 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderProgramDX11.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Graphics/Shaders/GPUShaderProgram.h" +#include "Engine/Core/Types/DataContainer.h" #include "../IncludeDirectXHeaders.h" #if GRAPHICS_API_DIRECTX11 @@ -17,11 +18,6 @@ protected: BufferType* _buffer; public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. GPUShaderProgramDX11(const GPUShaderProgramInitializer& initializer, BufferType* buffer) : _buffer(buffer) { @@ -31,18 +27,11 @@ public: #endif } - /// - /// Finalizes an instance of the class. - /// ~GPUShaderProgramDX11() { DX_SAFE_RELEASE_CHECK(_buffer, 0); } -public: - /// - /// Gets DirectX 11 buffer handle. - /// FORCE_INLINE BufferType* GetBufferHandleDX11() const { return _buffer; @@ -66,51 +55,21 @@ public: class GPUShaderProgramVSDX11 : public GPUShaderProgramDX11 { private: - byte _inputLayoutSize; - ID3D11InputLayout* _inputLayout; + Dictionary _cache; public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. - /// The input layout. - /// Size of the input layout. - GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, ID3D11InputLayout* inputLayout, byte inputLayoutSize) + GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, GPUVertexLayout* vertexLayout, Span bytecode) : GPUShaderProgramDX11(initializer, buffer) - , _inputLayoutSize(inputLayoutSize) - , _inputLayout(inputLayout) { + Layout = vertexLayout; + Bytecode.Copy(bytecode); } - /// - /// Finalizes an instance of the class. - /// - ~GPUShaderProgramVSDX11() - { - DX_SAFE_RELEASE_CHECK(_inputLayout, 0); - } + ~GPUShaderProgramVSDX11(); -public: - /// - /// Gets the DirectX 11 input layout handle - /// - FORCE_INLINE ID3D11InputLayout* GetInputLayoutDX11() const - { - return _inputLayout; - } + BytesContainer Bytecode; -public: - // [GPUShaderProgramDX11] - void* GetInputLayout() const override - { - return (void*)_inputLayout; - } - byte GetInputLayoutSize() const override - { - return _inputLayoutSize; - } + ID3D11InputLayout* GetInputLayout(class GPUVertexLayoutDX11* vertexLayout); }; #if GPU_ALLOW_TESSELLATION_SHADERS @@ -120,12 +79,6 @@ public: class GPUShaderProgramHSDX11 : public GPUShaderProgramDX11 { public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. - /// The control points used by the hull shader for processing. GPUShaderProgramHSDX11(const GPUShaderProgramInitializer& initializer, ID3D11HullShader* buffer, int32 controlPointsCount) : GPUShaderProgramDX11(initializer, buffer) { @@ -139,11 +92,6 @@ public: class GPUShaderProgramDSDX11 : public GPUShaderProgramDX11 { public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. GPUShaderProgramDSDX11(const GPUShaderProgramInitializer& initializer, ID3D11DomainShader* buffer) : GPUShaderProgramDX11(initializer, buffer) { @@ -158,11 +106,6 @@ public: class GPUShaderProgramGSDX11 : public GPUShaderProgramDX11 { public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. GPUShaderProgramGSDX11(const GPUShaderProgramInitializer& initializer, ID3D11GeometryShader* buffer) : GPUShaderProgramDX11(initializer, buffer) { @@ -176,11 +119,6 @@ public: class GPUShaderProgramPSDX11 : public GPUShaderProgramDX11 { public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. GPUShaderProgramPSDX11(const GPUShaderProgramInitializer& initializer, ID3D11PixelShader* buffer) : GPUShaderProgramDX11(initializer, buffer) { @@ -193,11 +131,6 @@ public: class GPUShaderProgramCSDX11 : public GPUShaderProgramDX11 { public: - /// - /// Initializes a new instance of the class. - /// - /// The program initialization data. - /// The shader buffer object. GPUShaderProgramCSDX11(const GPUShaderProgramInitializer& initializer, ID3D11ComputeShader* buffer) : GPUShaderProgramDX11(initializer, buffer) { diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp index 8c31a358a..6f9be059f 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp @@ -26,6 +26,7 @@ #include "GPUTextureDX12.h" #include "GPUBufferDX12.h" #include "GPUSamplerDX12.h" +#include "GPUVertexLayoutDX12.h" #include "CommandQueueDX12.h" #include "DescriptorHeapDX12.h" #include "Engine/Graphics/RenderTask.h" @@ -244,6 +245,7 @@ void GPUContextDX12::Reset() Platform::MemoryClear(_srHandles, sizeof(_srHandles)); Platform::MemoryClear(_uaHandles, sizeof(_uaHandles)); Platform::MemoryClear(_vbHandles, sizeof(_vbHandles)); + _vertexLayout = nullptr; _ibHandle = nullptr; Platform::MemoryClear(&_cbHandles, sizeof(_cbHandles)); Platform::MemoryClear(&_samplers, sizeof(_samplers)); @@ -560,7 +562,13 @@ void GPUContextDX12::flushPS() // Change state ASSERT(_currentState->IsValid()); - _commandList->SetPipelineState(_currentState->GetState(_rtDepth, _rtCount, _rtHandles)); +#if GPU_ENABLE_ASSERTION_LOW_LAYERS + if (!_vertexLayout && _vbHandles[0] && !_currentState->VertexLayout) + { + LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals."); + } +#endif + _commandList->SetPipelineState(_currentState->GetState(_rtDepth, _rtCount, _rtHandles, _vertexLayout)); if (_primitiveTopology != _currentState->PrimitiveTopology) { _primitiveTopology = _currentState->PrimitiveTopology; @@ -946,7 +954,7 @@ void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view) *view->LastRenderTime = _lastRenderTime; } -void GPUContextDX12::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets) +void GPUContextDX12::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout) { ASSERT(vertexBuffers.Length() >= 0 && vertexBuffers.Length() <= GPU_MAX_VB_BINDED); @@ -982,6 +990,7 @@ void GPUContextDX12::BindVB(const Span& vertexBuffers, const uint32* #endif _commandList->IASetVertexBuffers(0, vertexBuffers.Length(), views); } + _vertexLayout = (GPUVertexLayoutDX12*)(vertexLayout ? vertexLayout : GPUVertexLayout::Get(vertexBuffers)); } void GPUContextDX12::BindIB(GPUBuffer* indexBuffer) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h index 72b6e4547..f97be6da9 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h @@ -15,6 +15,7 @@ class GPUBufferDX12; class GPUSamplerDX12; class GPUConstantBufferDX12; class GPUTextureViewDX12; +class GPUVertexLayoutDX12; /// /// Size of the resource barriers buffer size (will be flushed on overflow) @@ -61,6 +62,7 @@ private: GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED]; IShaderResourceDX12* _srHandles[GPU_MAX_SR_BINDED]; IShaderResourceDX12* _uaHandles[GPU_MAX_UA_BINDED]; + GPUVertexLayoutDX12* _vertexLayout; GPUBufferDX12* _ibHandle; GPUBufferDX12* _vbHandles[GPU_MAX_VB_BINDED]; D3D12_INDEX_BUFFER_VIEW _ibView; @@ -176,7 +178,7 @@ public: void BindCB(int32 slot, GPUConstantBuffer* cb) override; void BindSR(int32 slot, GPUResourceView* view) override; void BindUA(int32 slot, GPUResourceView* view) override; - void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; + void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp index ead13f149..ecfce4eca 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp @@ -4,6 +4,7 @@ #include "GPUPipelineStateDX12.h" #include "GPUShaderProgramDX12.h" +#include "GPUVertexLayoutDX12.h" #include "GPUTextureDX12.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h" @@ -45,14 +46,16 @@ bool GPUPipelineStateDX12::IsValid() const return !!_memoryUsage; } -ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles) +ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles, GPUVertexLayoutDX12* vertexLayout) { - // Validate ASSERT(depth || rtCount); + if (!vertexLayout) + vertexLayout = VertexLayout; // Prepare key GPUPipelineStateKeyDX12 key; key.RTsCount = rtCount; + key.VertexLayout = vertexLayout; key.DepthFormat = depth ? depth->GetFormat() : PixelFormat::Unknown; key.MSAA = depth ? depth->GetMSAA() : (rtCount ? rtHandles[0]->GetMSAA() : MSAALevel::None); for (int32 i = 0; i < rtCount; i++) @@ -72,7 +75,6 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i #endif return state; } - PROFILE_CPU_NAMED("Create Pipeline State"); // Update description to match the pipeline @@ -83,6 +85,8 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i _desc.SampleDesc.Quality = key.MSAA == MSAALevel::None ? 0 : GPUDeviceDX12::GetMaxMSAAQuality((int32)key.MSAA); _desc.SampleMask = D3D12_DEFAULT_SAMPLE_MASK; _desc.DSVFormat = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindDepthStencilFormat(key.DepthFormat)); + _desc.InputLayout.pInputElementDescs = vertexLayout ? vertexLayout->InputElements : nullptr; + _desc.InputLayout.NumElements = vertexLayout ? vertexLayout->InputElementsCount : 0; // Create object const HRESULT result = _device->GetDevice()->CreateGraphicsPipelineState(&_desc, IID_PPV_ARGS(&state)); @@ -96,6 +100,7 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i name.Add(*DebugDesc.VS->GetName(), DebugDesc.VS->GetName().Length()); name.Add('+'); } +#if GPU_ALLOW_TESSELLATION_SHADERS if (DebugDesc.HS) { name.Add(*DebugDesc.HS->GetName(), DebugDesc.HS->GetName().Length()); @@ -106,11 +111,14 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i name.Add(*DebugDesc.DS->GetName(), DebugDesc.DS->GetName().Length()); name.Add('+'); } +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS if (DebugDesc.GS) { name.Add(*DebugDesc.GS->GetName(), DebugDesc.GS->GetName().Length()); name.Add('+'); } +#endif if (DebugDesc.PS) { name.Add(*DebugDesc.PS->GetName(), DebugDesc.PS->GetName().Length()); @@ -148,7 +156,6 @@ bool GPUPipelineStateDX12::Init(const Description& desc) // Shaders Platform::MemoryClear(&Header, sizeof(Header)); - psDesc.InputLayout = { static_cast(desc.VS->GetInputLayout()), desc.VS->GetInputLayoutSize() }; #define INIT_SHADER_STAGE(stage, type) \ if (desc.stage) \ { \ @@ -172,14 +179,17 @@ bool GPUPipelineStateDX12::Init(const Description& desc) #endif INIT_SHADER_STAGE(VS, GPUShaderProgramVSDX12); INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12); - const static D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] = + + // Input Assembly + VertexLayout = desc.VS ? (GPUVertexLayoutDX12*)desc.VS->Layout : nullptr; + const D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] = { D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED, D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT, D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, }; - const static D3D_PRIMITIVE_TOPOLOGY primTypes2[] = + const D3D_PRIMITIVE_TOPOLOGY primTypes2[] = { D3D_PRIMITIVE_TOPOLOGY_UNDEFINED, D3D_PRIMITIVE_TOPOLOGY_POINTLIST, diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.h index bcb114806..aaaae48d2 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.h @@ -11,11 +11,13 @@ #include "../IncludeDirectXHeaders.h" class GPUTextureViewDX12; +class GPUVertexLayoutDX12; struct GPUPipelineStateKeyDX12 { int32 RTsCount; MSAALevel MSAA; + GPUVertexLayout* VertexLayout; PixelFormat DepthFormat; PixelFormat RTVsFormats[GPU_MAX_RT_BINDED]; @@ -29,6 +31,7 @@ struct GPUPipelineStateKeyDX12 uint32 hash = (int32)key.MSAA * 11; CombineHash(hash, (uint32)key.DepthFormat * 93473262); CombineHash(hash, key.RTsCount * 136); + CombineHash(hash, GetHash(key.VertexLayout)); CombineHash(hash, (uint32)key.RTVsFormats[0]); CombineHash(hash, (uint32)key.RTVsFormats[1]); CombineHash(hash, (uint32)key.RTVsFormats[2]); @@ -46,18 +49,16 @@ struct GPUPipelineStateKeyDX12 class GPUPipelineStateDX12 : public GPUResourceDX12 { private: - Dictionary _states; D3D12_GRAPHICS_PIPELINE_STATE_DESC _desc; public: - GPUPipelineStateDX12(GPUDeviceDX12* device); public: - D3D_PRIMITIVE_TOPOLOGY PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; DxShaderHeader Header; + GPUVertexLayoutDX12* VertexLayout; /// /// Gets DirectX 12 graphics pipeline state object for the given rendering state. Uses depth buffer and render targets formats and multi-sample levels to setup a proper PSO. Uses caching. @@ -65,17 +66,16 @@ public: /// The depth buffer (can be null). /// The render targets count (can be 0). /// The render target handles array. + /// The vertex buffers layout. /// DirectX 12 graphics pipeline state object - ID3D12PipelineState* GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles); + ID3D12PipelineState* GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles, GPUVertexLayoutDX12* vertexLayout); public: - // [GPUPipelineState] bool IsValid() const override; bool Init(const Description& desc) override; protected: - // [GPUResourceDX12] void OnReleaseGPU() override; }; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp index 638e1b409..c4aea2172 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp @@ -8,81 +8,19 @@ #include "Types.h" #include "../RenderToolsDX.h" -GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) +GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) { // Extract the DX shader header from the cache - DxShaderHeader* header = (DxShaderHeader*)cacheBytes; - cacheBytes += sizeof(DxShaderHeader); - cacheSize -= sizeof(DxShaderHeader); + DxShaderHeader* header = (DxShaderHeader*)bytecode.Get(); + bytecode = Span(bytecode.Get() + sizeof(DxShaderHeader), bytecode.Length() - sizeof(DxShaderHeader)); GPUShaderProgram* shader = nullptr; switch (type) { case ShaderStage::Vertex: { - // Load Input Layout (it may be empty) - byte inputLayoutSize; - stream.ReadByte(&inputLayoutSize); - ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS); - D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; - for (int32 a = 0; a < inputLayoutSize; a++) - { - // Read description - GPUShaderProgramVS::InputElement inputElement; - stream.Read(inputElement); - - // Get semantic name - const char* semanticName = nullptr; - // TODO: maybe use enum+mapping ? - switch (inputElement.Type) - { - case 1: - semanticName = "POSITION"; - break; - case 2: - semanticName = "COLOR"; - break; - case 3: - semanticName = "TEXCOORD"; - break; - case 4: - semanticName = "NORMAL"; - break; - case 5: - semanticName = "TANGENT"; - break; - case 6: - semanticName = "BITANGENT"; - break; - case 7: - semanticName = "ATTRIBUTE"; - break; - case 8: - semanticName = "BLENDINDICES"; - break; - case 9: - semanticName = "BLENDWEIGHT"; - break; - default: - LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type); - break; - } - - // Set data - inputLayout[a] = - { - semanticName, - static_cast(inputElement.Index), - static_cast(inputElement.Format), - static_cast(inputElement.InputSlot), - static_cast(inputElement.AlignedByteOffset), - static_cast(inputElement.InputSlotClass), - static_cast(inputElement.InstanceDataStepRate) - }; - } - - // Create object - shader = New(initializer, header, cacheBytes, cacheSize, inputLayout, inputLayoutSize); + GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); + shader = New(initializer, header, bytecode, vertexLayout); break; } #if GPU_ALLOW_TESSELLATION_SHADERS @@ -90,12 +28,12 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const { int32 controlPointsCount; stream.ReadInt32(&controlPointsCount); - shader = New(initializer, header, cacheBytes, cacheSize, controlPointsCount); + shader = New(initializer, header, bytecode, controlPointsCount); break; } case ShaderStage::Domain: { - shader = New(initializer, header, cacheBytes, cacheSize); + shader = New(initializer, header, bytecode); break; } #else @@ -109,18 +47,18 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const #if GPU_ALLOW_GEOMETRY_SHADERS case ShaderStage::Geometry: { - shader = New(initializer, header, cacheBytes, cacheSize); + shader = New(initializer, header, bytecode); break; } #endif case ShaderStage::Pixel: { - shader = New(initializer, header, cacheBytes, cacheSize); + shader = New(initializer, header, bytecode); break; } case ShaderStage::Compute: { - shader = New(_device, initializer, header, cacheBytes, cacheSize); + shader = New(_device, initializer, header, bytecode); break; } } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h index 48bf99f41..9727307a9 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.h @@ -46,7 +46,7 @@ public: protected: // [GPUShader] - GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override; + GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) override; }; #endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h index 5195394c1..01e21c4f2 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderProgramDX12.h @@ -5,6 +5,7 @@ #if GRAPHICS_API_DIRECTX12 #include "GPUDeviceDX12.h" +#include "Engine/Core/Types/DataContainer.h" #include "Engine/Graphics/Shaders/GPUShaderProgram.h" #include "Types.h" #include "../IncludeDirectXHeaders.h" @@ -15,30 +16,27 @@ template class GPUShaderProgramDX12 : public BaseType { -protected: - Array _data; - public: - GPUShaderProgramDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize) + GPUShaderProgramDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode) : Header(*header) { BaseType::Init(initializer); - _data.Set(cacheBytes, cacheSize); + Bytecode.Copy(bytecode); } public: + BytesContainer Bytecode; DxShaderHeader Header; public: // [BaseType] void* GetBufferHandle() const override { - return (void*)_data.Get(); + return (void*)Bytecode.Get(); } - uint32 GetBufferSize() const override { - return _data.Count(); + return Bytecode.Length(); } }; @@ -47,29 +45,11 @@ public: /// class GPUShaderProgramVSDX12 : public GPUShaderProgramDX12 { -private: - byte _inputLayoutSize; - D3D12_INPUT_ELEMENT_DESC _inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; - public: - GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize, D3D12_INPUT_ELEMENT_DESC* inputLayout, byte inputLayoutSize) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) - , _inputLayoutSize(inputLayoutSize) + GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode, GPUVertexLayout* vertexLayout) + : GPUShaderProgramDX12(initializer, header, bytecode) { - for (byte i = 0; i < inputLayoutSize; i++) - _inputLayout[i] = inputLayout[i]; - } - -public: - // [GPUShaderProgramDX12] - void* GetInputLayout() const override - { - return (void*)_inputLayout; - } - - byte GetInputLayoutSize() const override - { - return _inputLayoutSize; + Layout = vertexLayout; } }; @@ -80,8 +60,8 @@ public: class GPUShaderProgramHSDX12 : public GPUShaderProgramDX12 { public: - GPUShaderProgramHSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize, int32 controlPointsCount) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) + GPUShaderProgramHSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode, int32 controlPointsCount) + : GPUShaderProgramDX12(initializer, header, bytecode) { _controlPointsCount = controlPointsCount; } @@ -93,8 +73,8 @@ public: class GPUShaderProgramDSDX12 : public GPUShaderProgramDX12 { public: - GPUShaderProgramDSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) + GPUShaderProgramDSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode) + : GPUShaderProgramDX12(initializer, header, bytecode) { } }; @@ -107,8 +87,8 @@ public: class GPUShaderProgramGSDX12 : public GPUShaderProgramDX12 { public: - GPUShaderProgramGSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) + GPUShaderProgramGSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode) + : GPUShaderProgramDX12(initializer, header, bytecode) { } }; @@ -120,8 +100,8 @@ public: class GPUShaderProgramPSDX12 : public GPUShaderProgramDX12 { public: - GPUShaderProgramPSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) + GPUShaderProgramPSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode) + : GPUShaderProgramDX12(initializer, header, bytecode) { } }; @@ -137,8 +117,8 @@ private: ID3D12PipelineState* _state; public: - GPUShaderProgramCSDX12(GPUDeviceDX12* device, const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize) - : GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize) + GPUShaderProgramCSDX12(GPUDeviceDX12* device, const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span bytecode) + : GPUShaderProgramDX12(initializer, header, bytecode) , _device(device) , _state(nullptr) { diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/Types.h b/Source/Engine/GraphicsDevice/DirectX/DX12/Types.h index e1a4e1de1..2e3a6fdf4 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/Types.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/Types.h @@ -17,8 +17,6 @@ struct DxShaderHeader /// The UAV dimensions per-slot. /// byte UaDimensions[4]; - - // .. rest is just a actual data array }; #endif diff --git a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h index fc185a587..d8a5fb7a8 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h @@ -116,7 +116,7 @@ public: { } - void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override + void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override { } diff --git a/Source/Engine/GraphicsDevice/Null/GPUShaderNull.h b/Source/Engine/GraphicsDevice/Null/GPUShaderNull.h index 77912ad7a..526841d6d 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUShaderNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUShaderNull.h @@ -14,7 +14,7 @@ class GPUShaderNull : public GPUShader protected: // [GPUShader] - GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override + GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) override { return nullptr; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index 106ffadf8..ebf95f7cc 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -10,6 +10,7 @@ #include "GPUBufferVulkan.h" #include "GPUShaderVulkan.h" #include "GPUSamplerVulkan.h" +#include "GPUVertexLayoutVulkan.h" #include "GPUPipelineStateVulkan.h" #include "Engine/Profiler/RenderStats.h" #include "GPUShaderProgramVulkan.h" @@ -650,8 +651,14 @@ void GPUContextVulkan::OnDrawCall() } // Bind any missing vertex buffers to null if required by the current state - const auto vertexInputState = pipelineState->GetVertexInputState(); - const int32 missingVBs = vertexInputState->vertexBindingDescriptionCount - _vbCount; + GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexShaderLayout; +#if GPU_ENABLE_ASSERTION_LOW_LAYERS + if (!vertexLayout && pipelineState && !pipelineState->VertexShaderLayout && (pipelineState->UsedStagesMask & (1 << (int32)DescriptorSet::Vertex)) != 0 && !_vertexLayout && _vbCount) + { + LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals."); + } +#endif + const int32 missingVBs = vertexLayout ? (int32)vertexLayout->CreateInfo.vertexBindingDescriptionCount - _vbCount : 0; if (missingVBs > 0) { VkBuffer buffers[GPU_MAX_VB_BINDED]; @@ -676,7 +683,7 @@ void GPUContextVulkan::OnDrawCall() { _psDirtyFlag = false; const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); - const auto pipeline = pipelineState->GetState(_renderPass); + const auto pipeline = pipelineState->GetState(_renderPass, _vertexLayout); vkCmdBindPipeline(cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); RENDER_STAT_PS_STATE_CHANGE(); } @@ -715,6 +722,7 @@ void GPUContextVulkan::FrameBegin() _stencilRef = 0; _renderPass = nullptr; _currentState = nullptr; + _vertexLayout = nullptr; _rtDepth = nullptr; Platform::MemoryClear(_rtHandles, sizeof(_rtHandles)); Platform::MemoryClear(_cbHandles, sizeof(_cbHandles)); @@ -1023,9 +1031,10 @@ void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view) } } -void GPUContextVulkan::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets) +void GPUContextVulkan::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout) { _vbCount = vertexBuffers.Length(); + _vertexLayout = (GPUVertexLayoutVulkan*)(vertexLayout ? vertexLayout : GPUVertexLayout::Get(vertexBuffers)); if (vertexBuffers.Length() == 0) return; const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h index 07ffa330b..b90cd1571 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h @@ -14,6 +14,7 @@ class CmdBufferManagerVulkan; class ResourceOwnerVulkan; class GPUTextureViewVulkan; class GPUBufferVulkan; +class GPUVertexLayoutVulkan; class GPUPipelineStateVulkan; class ComputePipelineStateVulkan; class GPUConstantBufferVulkan; @@ -82,6 +83,7 @@ private: RenderPassVulkan* _renderPass; GPUPipelineStateVulkan* _currentState; + GPUVertexLayoutVulkan* _vertexLayout; GPUTextureViewVulkan* _rtDepth; GPUTextureViewVulkan* _rtHandles[GPU_MAX_RT_BINDED]; DescriptorOwnerResourceVulkan* _cbHandles[GPU_MAX_CB_BINDED]; @@ -168,7 +170,7 @@ public: void BindCB(int32 slot, GPUConstantBuffer* cb) override; void BindSR(int32 slot, GPUResourceView* view) override; void BindUA(int32 slot, GPUResourceView* view) override; - void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; + void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 319dd653f..283b48e67 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -922,10 +922,10 @@ GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType GPUBufferVulkan* HelperResourcesVulkan::GetDummyBuffer(PixelFormat format) { - if (_dummyBuffers.IsEmpty()) + if (!_dummyBuffers) { - _dummyBuffers.Resize((int32)PixelFormat::MAX); - Platform::MemoryClear((void*)_dummyBuffers.Get(), (int32)PixelFormat::MAX * sizeof(void*)); + _dummyBuffers = (GPUBufferVulkan**)Allocator::Allocate((int32)PixelFormat::MAX * sizeof(void*)); + Platform::MemoryClear(_dummyBuffers, (int32)PixelFormat::MAX * sizeof(void*)); } auto& dummyBuffer = _dummyBuffers[(int32)format]; if (!dummyBuffer) @@ -941,7 +941,7 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyVertexBuffer() if (!_dummyVB) { _dummyVB = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyVertexBuffer")); - _dummyVB->Init(GPUBufferDescription::Vertex(sizeof(Color32), 1, &Color32::Transparent)); + _dummyVB->Init(GPUBufferDescription::Vertex(nullptr, sizeof(Color32), 1, &Color32::Transparent)); } return _dummyVB; } @@ -950,9 +950,16 @@ void HelperResourcesVulkan::Dispose() { SAFE_DELETE_GPU_RESOURCES(_dummyTextures); SAFE_DELETE_GPU_RESOURCE(_dummyVB); - for (GPUBuffer* buffer : _dummyBuffers) - Delete(buffer); - _dummyBuffers.Clear(); + if (_dummyBuffers) + { + for (int32 i = 0; i < (int32)PixelFormat::MAX; i++) + { + if (GPUBufferVulkan* buffer = _dummyBuffers[i]) + Delete(buffer); + } + Allocator::Free(_dummyBuffers); + _dummyBuffers = nullptr; + } for (int32 i = 0; i < ARRAY_COUNT(_staticSamplers); i++) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index e5e9c7de8..8b64eeb9c 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -308,7 +308,7 @@ class HelperResourcesVulkan private: GPUDeviceVulkan* _device; GPUTextureVulkan* _dummyTextures[6]; - Array _dummyBuffers; + GPUBufferVulkan** _dummyBuffers = nullptr; GPUBufferVulkan* _dummyVB; VkSampler _staticSamplers[GPU_STATIC_SAMPLERS_COUNT]; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index 17fbd6a36..2b50ef626 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -3,10 +3,12 @@ #if GRAPHICS_API_VULKAN #include "GPUPipelineStateVulkan.h" +#include "GPUVertexLayoutVulkan.h" #include "RenderToolsVulkan.h" #include "DescriptorSetVulkan.h" #include "GPUShaderProgramVulkan.h" #include "Engine/Core/Log.h" +#include "Engine/Core/Types/Pair.h" #include "Engine/Profiler/ProfilerCPU.h" static VkStencilOp ToVulkanStencilOp(const StencilOperation value) @@ -169,7 +171,6 @@ ComputePipelineStateVulkan::~ComputePipelineStateVulkan() GPUPipelineStateVulkan::GPUPipelineStateVulkan(GPUDeviceVulkan* device) : GPUResourceVulkan(device, StringView::Empty) - , _pipelines(16) , _layout(nullptr) { } @@ -201,25 +202,30 @@ PipelineLayoutVulkan* GPUPipelineStateVulkan::GetLayout() return _layout; } -VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass) +VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVertexLayoutVulkan* vertexLayout) { ASSERT(renderPass); + if (!vertexLayout) + vertexLayout = VertexShaderLayout; // Try reuse cached version VkPipeline pipeline = VK_NULL_HANDLE; - if (_pipelines.TryGet(renderPass, pipeline)) + const Pair key(renderPass, vertexLayout); + if (_pipelines.TryGet(key, pipeline)) { #if BUILD_DEBUG // Verify - RenderPassVulkan* refKey = nullptr; + Pair refKey(nullptr, nullptr); _pipelines.KeyOf(pipeline, &refKey); - ASSERT(refKey == renderPass); + ASSERT(refKey == key); #endif return pipeline; } - PROFILE_CPU_NAMED("Create Pipeline"); + // Bind vertex input + _desc.pVertexInputState = vertexLayout ? &vertexLayout->CreateInfo : nullptr; + // Update description to match the pipeline _descColorBlend.attachmentCount = renderPass->Layout.RTsCount; _descMultisample.rasterizationSamples = (VkSampleCountFlagBits)renderPass->Layout.MSAA; @@ -245,7 +251,7 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass) } // Cache it - _pipelines.Add(renderPass, pipeline); + _pipelines.Add(key, pipeline); return pipeline; } @@ -278,12 +284,9 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) { ASSERT(!IsValid()); - // Create description + // Reset description RenderToolsVulkan::ZeroStruct(_desc, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO); - // Vertex Input - _desc.pVertexInputState = (VkPipelineVertexInputStateCreateInfo*)desc.VS->GetInputLayout(); - // Stages UsedStagesMask = 0; HasDescriptorsPerStageMask = 0; @@ -318,6 +321,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _desc.pStages = _shaderStages; // Input Assembly + VertexShaderLayout = desc.VS ? (GPUVertexLayoutVulkan*)desc.VS->Layout : nullptr; RenderToolsVulkan::ZeroStruct(_descInputAssembly, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO);; switch (desc.PrimitiveTopology) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h index 9e21adbb5..600cb1841 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h @@ -9,6 +9,7 @@ #if GRAPHICS_API_VULKAN +class GPUVertexLayoutVulkan; class PipelineLayoutVulkan; class ComputePipelineStateVulkan @@ -89,7 +90,7 @@ public: class GPUPipelineStateVulkan : public GPUResourceVulkan { private: - Dictionary _pipelines; + Dictionary, VkPipeline> _pipelines; VkGraphicsPipelineCreateInfo _desc; VkPipelineShaderStageCreateInfo _shaderStages[ShaderStage_Count - 1]; VkPipelineInputAssemblyStateCreateInfo _descInputAssembly; @@ -140,18 +141,13 @@ public: /// const SpirvShaderDescriptorInfo* DescriptorInfoPerStage[DescriptorSet::GraphicsStagesCount]; - const VkPipelineVertexInputStateCreateInfo* GetVertexInputState() const - { - return _desc.pVertexInputState; - } - DescriptorSetWriteContainerVulkan DSWriteContainer; DescriptorSetWriterVulkan DSWriter[DescriptorSet::GraphicsStagesCount]; const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr; TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr; + GPUVertexLayoutVulkan* VertexShaderLayout = nullptr; Array DescriptorSetHandles; - Array DynamicOffsets; public: @@ -184,8 +180,9 @@ public: /// Gets the Vulkan graphics pipeline object for the given rendering state. Uses depth buffer and render targets formats and multi-sample levels to setup a proper PSO. Uses caching. /// /// The render pass. + /// The vertex layout. /// Vulkan graphics pipeline object. - VkPipeline GetState(RenderPassVulkan* renderPass); + VkPipeline GetState(RenderPassVulkan* renderPass, GPUVertexLayoutVulkan* vertexLayout); public: // [GPUPipelineState] diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h index 457b8998a..9f6391265 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderProgramVulkan.h @@ -21,13 +21,6 @@ protected: GPUDeviceVulkan* _device; public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. GPUShaderProgramVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) : _device(device) , ShaderModule(shaderModule) @@ -36,9 +29,6 @@ public: BaseType::Init(initializer); } - /// - /// Finalizes an instance of the class. - /// ~GPUShaderProgramVulkan() { if (ShaderModule) @@ -64,7 +54,6 @@ public: { return 0; } - void* GetBufferHandle() const override { return (void*)ShaderModule; @@ -77,33 +66,10 @@ public: class GPUShaderProgramVSVulkan : public GPUShaderProgramVulkan { public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. - GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) + GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, GPUVertexLayout* vertexLayout) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) { - } - -public: - VkPipelineVertexInputStateCreateInfo VertexInputState; - VkVertexInputBindingDescription VertexBindingDescriptions[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; - VkVertexInputAttributeDescription VertexAttributeDescriptions[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; - -public: - // [GPUShaderProgramVulkan] - void* GetInputLayout() const override - { - return (void*)&VertexInputState; - } - - byte GetInputLayoutSize() const override - { - return 0; + Layout = vertexLayout; } }; @@ -114,14 +80,6 @@ public: class GPUShaderProgramHSVulkan : public GPUShaderProgramVulkan { public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. - /// The control points used by the hull shader for processing. GPUShaderProgramHSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, int32 controlPointsCount) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) { @@ -135,13 +93,6 @@ public: class GPUShaderProgramDSVulkan : public GPUShaderProgramVulkan { public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. GPUShaderProgramDSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) { @@ -156,13 +107,6 @@ public: class GPUShaderProgramGSVulkan : public GPUShaderProgramVulkan { public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. GPUShaderProgramGSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) { @@ -176,13 +120,6 @@ public: class GPUShaderProgramPSVulkan : public GPUShaderProgramVulkan { public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. GPUShaderProgramPSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) { @@ -198,29 +135,18 @@ private: ComputePipelineStateVulkan* _pipelineState; public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. - /// The program initialization data. - /// The program descriptors usage info. - /// The shader module object. GPUShaderProgramCSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) , _pipelineState(nullptr) { } - /// - /// Finalizes an instance of the class. - /// ~GPUShaderProgramCSVulkan(); public: /// /// Gets the state of the pipeline for the compute shader execution or creates a new one if missing. /// - /// The compute pipeline state. ComputePipelineStateVulkan* GetOrCreateState(); }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp index 854500527..d36919b5f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp @@ -98,17 +98,16 @@ void UniformBufferUploaderVulkan::OnReleaseGPU() } } -GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) +GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) { // Extract the SPIR-V shader header from the cache - SpirvShaderHeader* header = (SpirvShaderHeader*)cacheBytes; - cacheBytes += sizeof(SpirvShaderHeader); - cacheSize -= sizeof(SpirvShaderHeader); + SpirvShaderHeader* header = (SpirvShaderHeader*)bytecode.Get(); + bytecode = Span(bytecode.Get() + sizeof(SpirvShaderHeader), bytecode.Length() - sizeof(SpirvShaderHeader)); // Extract the SPIR-V bytecode BytesContainer spirv; ASSERT(header->Type == SpirvShaderHeader::Types::Raw); - spirv.Link(cacheBytes, cacheSize); + spirv.Link(bytecode); // Create shader module from SPIR-V bytecode VkShaderModule shaderModule = VK_NULL_HANDLE; @@ -139,59 +138,8 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons { case ShaderStage::Vertex: { - // Create object - auto vsShader = New(_device, initializer, header->DescriptorInfo, shaderModule); - shader = vsShader; - VkPipelineVertexInputStateCreateInfo& inputState = vsShader->VertexInputState; - VkVertexInputBindingDescription* vertexBindingDescriptions = vsShader->VertexBindingDescriptions; - VkVertexInputAttributeDescription* vertexAttributeDescriptions = vsShader->VertexAttributeDescriptions; - RenderToolsVulkan::ZeroStruct(inputState, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO); - for (int32 i = 0; i < VERTEX_SHADER_MAX_INPUT_ELEMENTS; i++) - { - vertexBindingDescriptions[i].binding = i; - vertexBindingDescriptions[i].stride = 0; - vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - } - - // Load Input Layout (it may be empty) - byte inputLayoutSize; - stream.ReadByte(&inputLayoutSize); - ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS); - uint32 attributesCount = inputLayoutSize; - uint32 bindingsCount = 0; - int32 offset = 0; - for (int32 a = 0; a < inputLayoutSize; a++) - { - // Read description - GPUShaderProgramVS::InputElement inputElement; - stream.Read(inputElement); - - const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)inputElement.Format); - if (inputElement.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN) - offset = inputElement.AlignedByteOffset; - - auto& vertexBindingDescription = vertexBindingDescriptions[inputElement.InputSlot]; - vertexBindingDescription.binding = inputElement.InputSlot; - vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size)); - vertexBindingDescription.inputRate = inputElement.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE; - ASSERT(inputElement.InstanceDataStepRate == 0 || inputElement.InstanceDataStepRate == 1); - - auto& vertexAttributeDescription = vertexAttributeDescriptions[a]; - vertexAttributeDescription.location = a; - vertexAttributeDescription.binding = inputElement.InputSlot; - vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)inputElement.Format); - vertexAttributeDescription.offset = offset; - - bindingsCount = Math::Max(bindingsCount, (uint32)inputElement.InputSlot + 1); - offset += size; - } - - inputState.vertexBindingDescriptionCount = bindingsCount; - inputState.pVertexBindingDescriptions = vertexBindingDescriptions; - - inputState.vertexAttributeDescriptionCount = attributesCount; - inputState.pVertexAttributeDescriptions = vertexAttributeDescriptions; - + GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); + shader = New(_device, initializer, header->DescriptorInfo, shaderModule, vertexLayout); break; } #if GPU_ALLOW_TESSELLATION_SHADERS diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h index ee70e8125..43017cd94 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h @@ -130,7 +130,7 @@ public: protected: // [GPUShader] - GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override; + GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) override; }; #endif diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 3840ab5ce..83abc6198 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -300,7 +300,7 @@ void StaticModel::FlushVertexColors() vertexColorsBuffer = GPUDevice::Instance->CreateBuffer(TEXT("VertexColors")); if (vertexColorsBuffer->GetSize() != size) { - if (vertexColorsBuffer->Init(GPUBufferDescription::Vertex(sizeof(Color32), vertexColorsData.Count()))) + if (vertexColorsBuffer->Init(GPUBufferDescription::Vertex(VB2ElementType::GetLayout(), sizeof(Color32), vertexColorsData.Count(), nullptr))) break; } GPUDevice::Instance->GetMainContext()->UpdateBuffer(vertexColorsBuffer, vertexColorsData.Get(), size); diff --git a/Source/Engine/Particles/Particles.cpp b/Source/Engine/Particles/Particles.cpp index 205c87a87..9305c7931 100644 --- a/Source/Engine/Particles/Particles.cpp +++ b/Source/Engine/Particles/Particles.cpp @@ -14,6 +14,7 @@ #include "Engine/Graphics/DynamicBuffer.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/RenderTools.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/RenderList.h" @@ -49,17 +50,22 @@ public: { if (VB) return false; - VB = GPUDevice::Instance->CreateBuffer(TEXT("SpriteParticleRenderer,VB")); + VB = GPUDevice::Instance->CreateBuffer(TEXT("SpriteParticleRenderer.VB")); IB = GPUDevice::Instance->CreateBuffer(TEXT("SpriteParticleRenderer.IB")); - static SpriteParticleVertex vertexBuffer[] = + SpriteParticleVertex vertexBuffer[] = { { -0.5f, -0.5f, 0.0f, 0.0f }, { +0.5f, -0.5f, 1.0f, 0.0f }, { +0.5f, +0.5f, 1.0f, 1.0f }, { -0.5f, +0.5f, 0.0f, 1.0f }, }; - static uint16 indexBuffer[] = { 0, 1, 2, 0, 2, 3, }; - return VB->Init(GPUBufferDescription::Vertex(sizeof(SpriteParticleVertex), VertexCount, vertexBuffer)) || IB->Init(GPUBufferDescription::Index(sizeof(uint16), IndexCount, indexBuffer)); + uint16 indexBuffer[] = { 0, 1, 2, 0, 2, 3, }; + auto layout = GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32_Float }, + { VertexElement::Types::TexCoord, 0, 0, 0, PixelFormat::R32G32_Float }, + }); + return VB->Init(GPUBufferDescription::Vertex(layout, sizeof(SpriteParticleVertex), VertexCount, vertexBuffer)) || + IB->Init(GPUBufferDescription::Index(sizeof(uint16), IndexCount, indexBuffer)); } void Dispose() diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 942cb9e0b..fd746225a 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -19,6 +19,7 @@ #include "Engine/Graphics/DynamicBuffer.h" #include "Engine/Graphics/Shaders/GPUShader.h" #include "Engine/Graphics/Shaders/GPUConstantBuffer.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Animations/AnimationUtils.h" #include "Engine/Core/Log.h" #include "Engine/Core/Math/Half.h" @@ -604,6 +605,14 @@ bool Render2DService::Init() GUIShader.Get()->OnReloading.Bind(); #endif + VB.SetLayout(GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R32G32_Float }, + { VertexElement::Types::TexCoord, 0, 0, 0, PixelFormat::R16G16_Float }, + { VertexElement::Types::Color, 0, 0, 0, PixelFormat::R32G32B32A32_Float }, + { VertexElement::Types::TexCoord1, 0, 0, 0, PixelFormat::R32G32B32A32_Float }, + { VertexElement::Types::TexCoord2, 0, 0, 0, PixelFormat::R32G32B32A32_Float }, + })); + DrawCalls.EnsureCapacity(RENDER2D_INITIAL_DRAW_CALL_CAPACITY); return false; diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index be5992bde..45a5efdb7 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -20,6 +20,7 @@ #include "Engine/Graphics/RenderTargetPool.h" #include "Engine/Graphics/Async/GPUSyncPoint.h" #include "Engine/Graphics/Shaders/GPUShader.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Level/Actors/StaticModel.h" #include "Engine/Level/Scene/SceneRendering.h" #include "Engine/Renderer/ColorGradingPass.h" @@ -767,7 +768,14 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co for (SceneRendering* scene : renderContext.List->Scenes) surfaceAtlasData.ListenSceneRendering(scene); if (!_vertexBuffer) - _vertexBuffer = New(0u, (uint32)sizeof(AtlasTileVertex), TEXT("GlobalSurfaceAtlas.VertexBuffer")); + { + auto layout = GPUVertexLayout::Get({ + { VertexElement::Types::Position, 0, 0, 0, PixelFormat::R16G16_Float }, + { VertexElement::Types::TexCoord0, 0, 0, 0, PixelFormat::R16G16_Float }, + { VertexElement::Types::TexCoord1, 0, 0, 0, PixelFormat::R32_UInt }, + }); + _vertexBuffer = New(0u, (uint32)sizeof(AtlasTileVertex), TEXT("GlobalSurfaceAtlas.VertexBuffer"), layout); + } // Ensure that async objects drawing ended _surfaceAtlasData = &surfaceAtlasData; diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index 69032a2b7..1d9f4301f 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -15,6 +15,7 @@ #include "Engine/Profiler/Profiler.h" #include "Engine/Content/Assets/CubeTexture.h" #include "Engine/Core/Log.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Level/Scene/Lightmap.h" #include "Engine/Level/Actors/PostFxVolume.h" @@ -444,7 +445,7 @@ RenderList::RenderList(const SpawnParams& params) , Blendable(32) , ObjectBuffer(0, PixelFormat::R32G32B32A32_Float, false, TEXT("Object Bufffer")) , TempObjectBuffer(0, PixelFormat::R32G32B32A32_Float, false, TEXT("Object Bufffer")) - , _instanceBuffer(0, sizeof(ShaderObjectDrawInstanceData), TEXT("Instance Buffer")) + , _instanceBuffer(0, sizeof(ShaderObjectDrawInstanceData), TEXT("Instance Buffer"), GPUVertexLayout::Get({ { VertexElement::Types::Attribute0, 3, 0, 1, PixelFormat::R32_UInt } })) { } diff --git a/Source/Engine/Renderer/VolumetricFogPass.cpp b/Source/Engine/Renderer/VolumetricFogPass.cpp index d9a77bc37..88e382481 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.cpp +++ b/Source/Engine/Renderer/VolumetricFogPass.cpp @@ -9,6 +9,7 @@ #include "Engine/Graphics/RenderTargetPool.h" #include "Engine/Graphics/GPULimits.h" #include "Engine/Graphics/GPUContext.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Content/Assets/CubeTexture.h" #include "Engine/Content/Content.h" #include "Engine/Engine/Engine.h" @@ -627,10 +628,11 @@ void VolumetricFogPass::InitCircleBuffer() } // Create buffers - ASSERT(_vbCircleRasterize == nullptr && _ibCircleRasterize == nullptr); + ASSERT_LOW_LAYER(_vbCircleRasterize == nullptr && _ibCircleRasterize == nullptr); _vbCircleRasterize = GPUDevice::Instance->CreateBuffer(TEXT("VolumetricFog.CircleRasterize.VB")); _ibCircleRasterize = GPUDevice::Instance->CreateBuffer(TEXT("VolumetricFog.CircleRasterize.IB")); - if (_vbCircleRasterize->Init(GPUBufferDescription::Vertex(sizeof(Float2), vertices, vbData)) + auto layout = GPUVertexLayout::Get({{ VertexElement::Types::TexCoord, 0, 0, 0, PixelFormat::R32G32_Float }}); + if (_vbCircleRasterize->Init(GPUBufferDescription::Vertex(layout, sizeof(Float2), vertices, vbData)) || _ibCircleRasterize->Init(GPUBufferDescription::Index(sizeof(uint16), triangles * 3, ibData))) { LOG(Fatal, "Failed to setup volumetric fog buffers."); diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.VS.h b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.VS.h index 591b5e59f..d0be836cc 100644 --- a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.VS.h +++ b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.VS.h @@ -84,6 +84,11 @@ namespace ShaderProcessing parser->OnError(TEXT("Cannot parse token.")); return; } + else if (element.AlignedByteOffset > MAX_uint8) + { + parser->OnError(TEXT("Too big vertex element byte offset.")); + return; + } // Input slot class text.ReadToken(&token); @@ -140,9 +145,9 @@ namespace ShaderProcessing void OnParseAfter(IShaderParser* parser, Reader& text) override { // Check if errors in specified input layout - if (_current.InputLayout.Count() > VERTEX_SHADER_MAX_INPUT_ELEMENTS) + if (_current.InputLayout.Count() > GPU_MAX_VS_ELEMENTS) { - parser->OnError(String::Format(TEXT("Vertex Shader \'{0}\' has too many input layout elements specified. Maximum allowed amount is {1}."), String(_current.Name), VERTEX_SHADER_MAX_INPUT_ELEMENTS)); + parser->OnError(String::Format(TEXT("Vertex Shader \'{0}\' has too many input layout elements specified. Maximum allowed amount is {1}."), String(_current.Name), GPU_MAX_VS_ELEMENTS)); return; } diff --git a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp index bf7456b9e..84c881092 100644 --- a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp +++ b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp @@ -10,9 +10,11 @@ #include "Engine/Platform/FileSystem.h" #include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/Shaders/GPUShader.h" +#include "Engine/Graphics/Shaders/VertexElement.h" #include "Engine/Threading/Threading.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Serialization/MemoryWriteStream.h" +#include "FlaxEngine.Gen.h" namespace IncludedFiles { @@ -65,14 +67,11 @@ bool ShaderCompiler::Compile(ShaderCompilationContext* context) return true; // [Output] Constant Buffers + output->WriteByte((byte)_constantBuffers.Count()); + for (const ShaderResourceBuffer& cb : _constantBuffers) { - ASSERT(_constantBuffers.Count() == meta->CB.Count()); - output->WriteByte((byte)_constantBuffers.Count()); - for (const ShaderResourceBuffer& cb : _constantBuffers) - { - output->WriteByte(cb.Slot); - output->WriteUint32(cb.Size); - } + output->WriteByte(cb.Slot); + output->WriteUint32(cb.Size); } // Additional Data Start @@ -314,13 +313,21 @@ bool ShaderCompiler::WriteShaderFunctionEnd(ShaderCompilationContext* context, S bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array& macros) { + // [Deprecated in v1.10] auto output = context->Output; auto& metaVS = *(VertexShaderMeta*)&meta; auto& layout = metaVS.InputLayout; +#if FLAXENGINE_VERSION_MAJOR > 2 || (FLAXENGINE_VERSION_MAJOR == 2 && FLAXENGINE_VERSION_MINOR >= 1) + if (layout.HasItems()) + LOG(Warning, "Vertex Shader '{}' (asset '{}') uses explicit vertex layout via 'META_VS_IN_ELEMENT' macros which has been deprecated. Remove this code and migrate to GPUVertexLayout with VertexElement array in code (assigned to vertex buffer).", String(meta.Name), context->Options->TargetName); +#elif FLAXENGINE_VERSION_MAJOR == 1 && FLAXENGINE_VERSION_MINOR >= 11 + if (layout.HasItems()) + LOG(Warning, "Vertex Shader '{}' (asset '{}') uses explicit vertex layout via 'META_VS_IN_ELEMENT' macros which has been deprecated. Remove this code and migrate to GPUVertexLayout with VertexElement array in code (assigned to vertex buffer).", String(meta.Name), context->Options->TargetName); +#endif // Get visible entries (based on `visible` flag switch) int32 layoutSize = 0; - bool layoutVisible[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; + bool layoutVisible[GPU_MAX_VS_ELEMENTS]; for (int32 i = 0; i < layout.Count(); i++) { auto& element = layout[i]; @@ -361,14 +368,93 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader auto& element = layout[a]; if (!layoutVisible[a]) continue; - GPUShaderProgramVS::InputElement data; - data.Type = static_cast(element.Type); - data.Index = element.Index; - data.Format = static_cast(element.Format); - data.InputSlot = element.InputSlot; - data.AlignedByteOffset = element.AlignedByteOffset; - data.InputSlotClass = element.InputSlotClass; - data.InstanceDataStepRate = element.InstanceDataStepRate; + VertexElement data; + switch (element.Type) + { + case VertexShaderMeta::InputType::POSITION: + data.Type = VertexElement::Types::Position; + break; + case VertexShaderMeta::InputType::COLOR: + data.Type = VertexElement::Types::Color; + break; + case VertexShaderMeta::InputType::TEXCOORD: + switch (element.Index) + { + case 0: + data.Type = VertexElement::Types::TexCoord0; + break; + case 1: + data.Type = VertexElement::Types::TexCoord1; + break; + case 2: + data.Type = VertexElement::Types::TexCoord2; + break; + case 3: + data.Type = VertexElement::Types::TexCoord3; + break; + case 4: + data.Type = VertexElement::Types::TexCoord4; + break; + case 5: + data.Type = VertexElement::Types::TexCoord5; + break; + case 6: + data.Type = VertexElement::Types::TexCoord6; + break; + case 7: + data.Type = VertexElement::Types::TexCoord7; + break; + default: + LOG(Error, "Vertex Shader '{}' (asset '{}') uses deprecated texcoord attribute index. Valid range is 0-7.", String(meta.Name), context->Options->TargetName); + data.Type = VertexElement::Types::TexCoord; + break; + } + break; + case VertexShaderMeta::InputType::NORMAL: + data.Type = VertexElement::Types::Normal; + break; + case VertexShaderMeta::InputType::TANGENT: + data.Type = VertexElement::Types::Tangent; + break; + case VertexShaderMeta::InputType::BITANGENT: + LOG(Error, "Vertex Shader '{}' (asset '{}') uses deprecated attribute 'BITANGENT'. Remapping it to `ATTRIBUTE`.", String(meta.Name), context->Options->TargetName); + data.Type = VertexElement::Types::Attribute; + break; + case VertexShaderMeta::InputType::ATTRIBUTE: + switch (element.Index) + { + case 0: + data.Type = VertexElement::Types::Attribute0; + break; + case 1: + data.Type = VertexElement::Types::Attribute1; + break; + case 2: + data.Type = VertexElement::Types::Attribute2; + break; + case 3: + data.Type = VertexElement::Types::Attribute3; + break; + default: + LOG(Error, "Vertex Shader '{}' (asset '{}') uses deprecated attribute index. Valid range is 0-3.", String(meta.Name), context->Options->TargetName); + data.Type = VertexElement::Types::Attribute; + break; + } + break; + case VertexShaderMeta::InputType::BLENDINDICES: + data.Type = VertexElement::Types::BlendIndices; + break; + case VertexShaderMeta::InputType::BLENDWEIGHT: + data.Type = VertexElement::Types::BlendWeight; + break; + default: + data.Type = VertexElement::Types::Unknown; + break; + } + data.Slot = element.InputSlot; + data.Offset = element.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN && element.AlignedByteOffset <= MAX_uint8 ? element.AlignedByteOffset : 0; + data.PerInstance = element.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA; + data.Format = element.Format; output->Write(data); } diff --git a/Source/Engine/Terrain/TerrainManager.cpp b/Source/Engine/Terrain/TerrainManager.cpp index 0c699cf67..116451f7e 100644 --- a/Source/Engine/Terrain/TerrainManager.cpp +++ b/Source/Engine/Terrain/TerrainManager.cpp @@ -13,6 +13,7 @@ #include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/AssetReference.h" #include "Engine/Core/Log.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Renderer/DrawCall.h" // Must match structure defined in Terrain.shader @@ -25,7 +26,6 @@ struct TerrainVertex class GeometryData { public: - GPUBuffer* VertexBuffer; GPUBuffer* IndexBuffer; uint32 IndicesCount; @@ -49,11 +49,11 @@ ChunkedArray Pool; Dictionary Lookup; Array TempData; AssetReference DefaultTerrainMaterial; +GPUVertexLayout* TerrainVertexLayout = nullptr; class TerrainManagerService : public EngineService { public: - TerrainManagerService() : EngineService(TEXT("Terrain Manager"), 40) { @@ -132,7 +132,14 @@ bool TerrainManager::GetChunkGeometry(DrawCall& drawCall, int32 chunkSize, int32 vertex++; } } - auto desc = GPUBufferDescription::Vertex(sizeof(TerrainVertex), vertexCount2, TempData.Get()); + if (!TerrainVertexLayout) + { + TerrainVertexLayout = GPUVertexLayout::Get({ + { VertexElement::Types::TexCoord0, 0, 0, 0, PixelFormat::R32G32_Float }, + { VertexElement::Types::TexCoord1, 0, 0, 0, PixelFormat::R8G8B8A8_UNorm }, + }); + } + auto desc = GPUBufferDescription::Vertex(TerrainVertexLayout, sizeof(TerrainVertex), vertexCount2, TempData.Get()); if (vb->Init(desc)) { Delete(vb); diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 5ff02cf36..70697adfd 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -2242,7 +2242,7 @@ void TerrainPatch::CacheDebugLines() typedef DebugDraw::Vertex Vertex; if (_debugLines->GetElementsCount() != count) { - if (_debugLines->Init(GPUBufferDescription::Vertex(sizeof(Vertex), count))) + if (_debugLines->Init(GPUBufferDescription::Vertex(Vertex::GetLayout(), sizeof(Vertex), count))) return; } Array debugLines; diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 05c6cdf73..9edb322f5 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -27,9 +27,9 @@ TextRender::TextRender(const SpawnParams& params) : Actor(params) , _size(32) , _ib(0, sizeof(uint16)) - , _vb0(0, sizeof(VB0ElementType)) - , _vb1(0, sizeof(VB1ElementType)) - , _vb2(0, sizeof(VB2ElementType)) + , _vb0(0, sizeof(VB0ElementType), String::Empty, VB0ElementType::GetLayout()) + , _vb1(0, sizeof(VB1ElementType), String::Empty, VB1ElementType::GetLayout()) + , _vb2(0, sizeof(VB2ElementType), String::Empty, VB2ElementType::GetLayout()) { _color = Color::White; _localBox = BoundingBox(Vector3::Zero); diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 11da02c41..0b4d3e2f8 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -33,7 +33,7 @@ // Meta macros used by shaders parser #define META_VS(isVisible, minFeatureLevel) -#define META_VS_IN_ELEMENT(type, index, format, slot, offset, slotClass, stepRate, isVisible) +#define META_VS_IN_ELEMENT(type, index, format, slot, offset, slotClass, stepRate, isVisible) // [Deprecated in v1.10] #define META_HS(isVisible, minFeatureLevel) #define META_HS_PATCH(inControlPoints) #define META_DS(isVisible, minFeatureLevel) diff --git a/Source/Shaders/DebugDraw.shader b/Source/Shaders/DebugDraw.shader index d10dbbf06..05e993fbc 100644 --- a/Source/Shaders/DebugDraw.shader +++ b/Source/Shaders/DebugDraw.shader @@ -18,8 +18,6 @@ struct VS2PS Texture2D SceneDepthTexture : register(t0); META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(COLOR, 0, R8G8B8A8_UNORM, 0, ALIGN, PER_VERTEX, 0, true) VS2PS VS(float3 Position : POSITION, float4 Color : COLOR) { VS2PS output; diff --git a/Source/Shaders/Editor/Grid.shader b/Source/Shaders/Editor/Grid.shader index f8b0b0b81..249e209ef 100644 --- a/Source/Shaders/Editor/Grid.shader +++ b/Source/Shaders/Editor/Grid.shader @@ -42,7 +42,6 @@ struct PixelInput // Vertex shader function for grid rendering META_VS(true, FEATURE_LEVEL_ES2) META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R16G16_FLOAT, 1, ALIGN, PER_VERTEX, 0, true) VertexOutput VS_Grid(ModelInput input) { VertexOutput output; diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.shader b/Source/Shaders/GI/GlobalSurfaceAtlas.shader index 0d9532041..360915d89 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.shader +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.shader @@ -40,9 +40,6 @@ struct AtlasVertexOutput // Vertex shader for Global Surface Atlas rendering (custom vertex buffer to render per-tile) META_VS(true, FEATURE_LEVEL_SM5) -META_VS_IN_ELEMENT(POSITION, 0, R16G16_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R16G16_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 1, R32_UINT, 0, ALIGN, PER_VERTEX, 0, true) AtlasVertexOutput VS_Atlas(AtlasVertexInput input) { AtlasVertexOutput output; diff --git a/Source/Shaders/GUI.shader b/Source/Shaders/GUI.shader index 10e0487fe..e4d60d0c3 100644 --- a/Source/Shaders/GUI.shader +++ b/Source/Shaders/GUI.shader @@ -23,11 +23,6 @@ META_CB_END Texture2D Image : register(t0); META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R16G16_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(COLOR, 0, R32G32B32A32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 1, R32G32B32A32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 2, R32G32B32A32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) VS2PS VS(Render2DVertex input) { VS2PS output; diff --git a/Source/Shaders/Quad.shader b/Source/Shaders/Quad.shader index 0a6c2ba80..607fa239d 100644 --- a/Source/Shaders/Quad.shader +++ b/Source/Shaders/Quad.shader @@ -16,30 +16,22 @@ META_CB_END // Vertex Shader for screen space quad rendering META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) Quad_VS2PS VS(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0) { Quad_VS2PS output; - output.Position = float4(Position, 0, 1); output.TexCoord = TexCoord; - return output; } // Vertex Shader function for postFx materials rendering META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) MaterialVertexOutput VS_PostFx(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0) { MaterialVertexOutput output; - output.Position = float4(Position, 0, 1); output.WorldPosition = output.Position.xyz; output.TexCoord = TexCoord; - return output; } diff --git a/Source/Shaders/VolumetricFog.shader b/Source/Shaders/VolumetricFog.shader index d04a2eb92..1c4f1cb58 100644 --- a/Source/Shaders/VolumetricFog.shader +++ b/Source/Shaders/VolumetricFog.shader @@ -112,7 +112,6 @@ float3 GetVolumeUV(float3 worldPosition, float4x4 worldToClip) // Vertex shader that writes to a range of slices of a volume texture META_VS(true, FEATURE_LEVEL_SM5) META_FLAG(VertexToGeometryShader) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) Quad_VS2GS VS_WriteToSlice(float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_InstanceID) { Quad_VS2GS output;