// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= VulkanVertexDeclaration.cpp: Vulkan vertex declaration RHI implementation. =============================================================================*/ #include "VulkanRHIPrivate.h" struct FVulkanVertexDeclarationKey { FVertexDeclarationElementList VertexElements; uint32 Hash; uint32 HashNoStride; explicit FVulkanVertexDeclarationKey(const FVertexDeclarationElementList& InElements) : VertexElements(InElements) { Hash = FCrc::MemCrc_DEPRECATED(VertexElements.GetData(), VertexElements.Num()*sizeof(FVertexElement)); HashNoStride = 0; for (int32 ElementIndex = 0; ElementIndex < VertexElements.Num(); ElementIndex++) { FVertexElement Element = VertexElements[ElementIndex]; Element.Stride = 0; HashNoStride = FCrc::MemCrc32(&Element, sizeof(Element), HashNoStride); } } }; inline uint32 GetTypeHash(const FVulkanVertexDeclarationKey& Key) { return Key.Hash; } bool operator==(const FVulkanVertexDeclarationKey& A, const FVulkanVertexDeclarationKey& B) { return (A.VertexElements.Num() == B.VertexElements.Num() && !memcmp(A.VertexElements.GetData(), B.VertexElements.GetData(), A.VertexElements.Num() * sizeof(FVertexElement))); } FVulkanVertexDeclaration::FVulkanVertexDeclaration(const FVertexDeclarationElementList& InElements, uint32 InHash, uint32 InHashNoStrides) : Elements(InElements) , Hash(InHash) , HashNoStrides(InHashNoStrides) { } TMap GVertexDeclarationCache; void FVulkanVertexDeclaration::EmptyCache() { GVertexDeclarationCache.Empty(0); } FVertexDeclarationRHIRef FVulkanDynamicRHI::RHICreateVertexDeclaration(const FVertexDeclarationElementList& Elements) { FVulkanVertexDeclarationKey Key(Elements); static FCriticalSection CS; FScopeLock ScopeLock(&CS); FVertexDeclarationRHIRef* VertexDeclarationRefPtr = GVertexDeclarationCache.Find(Key); if (VertexDeclarationRefPtr == nullptr) { VertexDeclarationRefPtr = &GVertexDeclarationCache.Add(Key, new FVulkanVertexDeclaration(Elements, Key.Hash, Key.HashNoStride)); } check(VertexDeclarationRefPtr); check(IsValidRef(*VertexDeclarationRefPtr)); return *VertexDeclarationRefPtr; } FVulkanVertexInputStateInfo::~FVulkanVertexInputStateInfo() { } FVulkanVertexInputStateInfo::FVulkanVertexInputStateInfo() : Hash(0) , BindingsNum(0) , BindingsMask(0) , AttributesNum(0) { FMemory::Memzero(Info); FMemory::Memzero(Attributes); FMemory::Memzero(Bindings); } bool FVulkanVertexInputStateInfo::operator ==(const FVulkanVertexInputStateInfo& Other) { if(AttributesNum != Other.AttributesNum) { return false; } for(uint32 i = 0; i < AttributesNum; ++i) { if(0 != FMemory::Memcmp(&Attributes[i], &Other.Attributes[i], sizeof(Attributes[i]))) { return false; } } return true; } void FVulkanVertexInputStateInfo::Generate(FVulkanVertexDeclaration* VertexDeclaration, uint32 VertexHeaderInOutAttributeMask) { // GenerateVertexInputState is expected to be called only once! check(Info.sType == 0); // Generate vertex attribute Layout const FVertexDeclarationElementList& VertexInput = VertexDeclaration->Elements; // Generate Bindings for (const FVertexElement& Element : VertexInput) { if ((1< 0); Info.vertexAttributeDescriptionCount = AttributesNum; Info.pVertexAttributeDescriptions = Attributes; Hash = FCrc::MemCrc32(Bindings, BindingsNum * sizeof(Bindings[0])); check(AttributesNum > 0); Hash = FCrc::MemCrc32(Attributes, AttributesNum * sizeof(Attributes[0]), Hash); }