Improve GPU vertex layout binding in case of missing element from the mesh
This commit is contained in:
@@ -401,7 +401,7 @@ public:
|
||||
/// Creates the vertex buffer layout.
|
||||
/// </summary>
|
||||
/// <returns>The vertex buffer layout.</returns>
|
||||
API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array<struct VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>>& elements) = 0;
|
||||
API_FUNCTION() virtual GPUVertexLayout* CreateVertexLayout(const Array<struct VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>>& elements, bool explicitOffsets = false) = 0;
|
||||
typedef Array<VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>> VertexElements;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,6 +45,26 @@ namespace
|
||||
CriticalSection CacheLocker;
|
||||
Dictionary<uint32, GPUVertexLayout*> LayoutCache;
|
||||
Dictionary<VertexBufferLayouts, GPUVertexLayout*> VertexBufferCache;
|
||||
|
||||
GPUVertexLayout* AddCache(const VertexBufferLayouts& key, int32 count)
|
||||
{
|
||||
GPUVertexLayout::Elements elements;
|
||||
bool anyValid = false;
|
||||
for (int32 slot = 0; slot < count; slot++)
|
||||
{
|
||||
if (key.Layouts[slot])
|
||||
{
|
||||
anyValid = true;
|
||||
int32 start = elements.Count();
|
||||
elements.Add(key.Layouts[slot]->GetElements());
|
||||
for (int32 j = start; j < elements.Count(); j++)
|
||||
elements.Get()[j].Slot = (byte)slot;
|
||||
}
|
||||
}
|
||||
GPUVertexLayout* result = anyValid ? GPUVertexLayout::Get(elements) : nullptr;
|
||||
VertexBufferCache.Add(key, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
String VertexElement::ToString() const
|
||||
@@ -76,22 +96,27 @@ GPUVertexLayout::GPUVertexLayout()
|
||||
{
|
||||
}
|
||||
|
||||
void GPUVertexLayout::SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS])
|
||||
void GPUVertexLayout::SetElements(const Elements& elements, bool explicitOffsets)
|
||||
{
|
||||
uint32 offsets[GPU_MAX_VB_BINDED] = {};
|
||||
_elements = elements;
|
||||
uint32 strides[GPU_MAX_VB_BINDED] = {};
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
for (int32 i = 0; i < _elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& e = elements[i];
|
||||
VertexElement& e = _elements[i];
|
||||
ASSERT(e.Slot < GPU_MAX_VB_BINDED);
|
||||
strides[e.Slot] = Math::Max(strides[e.Slot], offsets[e.Slot]);
|
||||
uint32& offset = offsets[e.Slot];
|
||||
if (e.Offset != 0 || explicitOffsets)
|
||||
offset = e.Offset;
|
||||
else
|
||||
e.Offset = (byte)offset;
|
||||
offset += PixelFormatExtensions::SizeInBytes(e.Format);
|
||||
}
|
||||
_stride = 0;
|
||||
for (uint32 stride : strides)
|
||||
_stride += stride;
|
||||
for (uint32 offset : offsets)
|
||||
_stride += offset;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
|
||||
GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements, bool explicitOffsets)
|
||||
{
|
||||
// Hash input layout
|
||||
uint32 hash = 0;
|
||||
@@ -105,7 +130,7 @@ GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
|
||||
GPUVertexLayout* result;
|
||||
if (!LayoutCache.TryGet(hash, result))
|
||||
{
|
||||
result = GPUDevice::Instance->CreateVertexLayout(elements);
|
||||
result = GPUDevice::Instance->CreateVertexLayout(elements, explicitOffsets);
|
||||
if (!result)
|
||||
{
|
||||
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
|
||||
@@ -118,16 +143,6 @@ GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
|
||||
}
|
||||
LayoutCache.Add(hash, result);
|
||||
}
|
||||
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
|
||||
else if (result->GetElements() != elements)
|
||||
{
|
||||
for (auto& e : result->GetElements())
|
||||
LOG(Error, " (a) {}", e.ToString());
|
||||
for (auto& e : elements)
|
||||
LOG(Error, " (b) {}", e.ToString());
|
||||
LOG(Fatal, "Vertex layout cache collision for hash {}", hash);
|
||||
}
|
||||
#endif
|
||||
CacheLocker.Unlock();
|
||||
|
||||
return result;
|
||||
@@ -141,38 +156,94 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUBuffer*>& vertexBuffers)
|
||||
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;
|
||||
VertexBufferLayouts key;
|
||||
for (int32 i = 0; i < vertexBuffers.Length() && i < GPU_MAX_VB_BINDED; i++)
|
||||
key.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;
|
||||
key.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);
|
||||
}
|
||||
if (!VertexBufferCache.TryGet(key, result))
|
||||
result = AddCache(key, vertexBuffers.Length());
|
||||
CacheLocker.Unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUVertexLayout*>& layouts)
|
||||
{
|
||||
if (layouts.Length() == 0)
|
||||
return nullptr;
|
||||
if (layouts.Length() == 1)
|
||||
return layouts.Get()[0] ? layouts.Get()[0] : nullptr;
|
||||
|
||||
// Build hash key for set of buffers (in case there is layout sharing by different sets of buffers)
|
||||
VertexBufferLayouts key;
|
||||
for (int32 i = 0; i < layouts.Length() && i < GPU_MAX_VB_BINDED; i++)
|
||||
key.Layouts[i] = layouts.Get()[i];
|
||||
for (int32 i = layouts.Length(); i < GPU_MAX_VB_BINDED; i++)
|
||||
key.Layouts[i] = nullptr;
|
||||
|
||||
// Lookup existing cache
|
||||
CacheLocker.Lock();
|
||||
GPUVertexLayout* result;
|
||||
if (!VertexBufferCache.TryGet(key, result))
|
||||
result = AddCache(key, layouts.Length());
|
||||
CacheLocker.Unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, const GPUVertexLayout* reference)
|
||||
{
|
||||
if (!reference || !base || base == reference)
|
||||
return base;
|
||||
GPUVertexLayout* result = base;
|
||||
if (base && reference)
|
||||
{
|
||||
bool anyMissing = false;
|
||||
const Elements& baseElements = base->GetElements();
|
||||
Elements newElements = baseElements;
|
||||
for (const VertexElement& e : reference->GetElements())
|
||||
{
|
||||
bool missing = true;
|
||||
for (const VertexElement& ee : baseElements)
|
||||
{
|
||||
if (ee.Type == e.Type)
|
||||
{
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
// Insert any missing elements
|
||||
VertexElement ne = { e.Type, e.Slot, 0, e.PerInstance, e.Format };
|
||||
if (e.Type == VertexElement::Types::TexCoord1 || e.Type == VertexElement::Types::TexCoord2 || e.Type == VertexElement::Types::TexCoord3)
|
||||
{
|
||||
// Alias missing texcoords with existing texcoords
|
||||
for (const VertexElement& ee : newElements)
|
||||
{
|
||||
if (ee.Type == VertexElement::Types::TexCoord0)
|
||||
{
|
||||
ne = ee;
|
||||
ne.Type = e.Type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
newElements.Add(ne);
|
||||
anyMissing = true;
|
||||
}
|
||||
}
|
||||
if (anyMissing)
|
||||
result = Get(newElements, true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClearVertexLayoutCache()
|
||||
{
|
||||
for (const auto& e : LayoutCache)
|
||||
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
protected:
|
||||
GPUVertexLayout();
|
||||
|
||||
void SetElements(const Elements& elements, uint32 offsets[GPU_MAX_VS_ELEMENTS]);
|
||||
void SetElements(const Elements& elements, bool explicitOffsets);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -46,8 +46,9 @@ public:
|
||||
/// Gets the vertex layout for a given list of elements. Uses internal cache to skip creating layout if it's already exists for a given list.
|
||||
/// </summary>
|
||||
/// <param name="elements">The list of elements for the layout.</param>
|
||||
/// <param name="explicitOffsets">If set to true, input elements offsets will be used without automatic calculations (offsets with value 0).</param>
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
API_FUNCTION() static GPUVertexLayout* Get(const Array<VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>>& elements);
|
||||
API_FUNCTION() static GPUVertexLayout* Get(const Array<VertexElement, FixedAllocation<GPU_MAX_VS_ELEMENTS>>& elements, bool explicitOffsets = false);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
@@ -56,6 +57,21 @@ public:
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
API_FUNCTION() static GPUVertexLayout* Get(const Span<GPUBuffer*>& vertexBuffers);
|
||||
|
||||
/// <summary>
|
||||
/// Merges list of layouts in a single one. Uses internal cache to skip creating layout if it's already exists for a given list.
|
||||
/// </summary>
|
||||
/// <param name="layouts">The list of layouts to merge.</param>
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
API_FUNCTION() static GPUVertexLayout* Get(const Span<GPUVertexLayout*>& layouts);
|
||||
|
||||
/// <summary>
|
||||
/// Merges reference vertex elements into the given set of elements to ensure the reference list is satisfied (vertex shader input requirement). Returns base layout if it's valid.
|
||||
/// </summary>
|
||||
/// <param name="base">The list of vertex buffers for the layout.</param>
|
||||
/// <param name="reference">The list of reference inputs.</param>
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, const GPUVertexLayout* reference);
|
||||
|
||||
public:
|
||||
// [GPUResource]
|
||||
GPUResourceType GetResourceType() const override
|
||||
|
||||
@@ -66,7 +66,7 @@ PACK_BEGIN() struct FLAXENGINE_API VertexElement
|
||||
API_FIELD() Types Type;
|
||||
// Index of the input vertex buffer slot (as provided in GPUContext::BindVB).
|
||||
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 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 (except when explicitOffsets is false).
|
||||
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).
|
||||
API_FIELD() byte PerInstance;
|
||||
|
||||
@@ -148,27 +148,22 @@ static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureL
|
||||
return false;
|
||||
}
|
||||
|
||||
GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements)
|
||||
GPUVertexLayoutDX11::GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements, bool explicitOffsets)
|
||||
: GPUResourceBase<GPUDeviceDX11, GPUVertexLayout>(device, StringView::Empty)
|
||||
, InputElementsCount(elements.Count())
|
||||
{
|
||||
uint32 offsets[GPU_MAX_VB_BINDED] = {};
|
||||
SetElements(elements, explicitOffsets);
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& src = elements.Get()[i];
|
||||
const VertexElement& src = GetElements().Get()[i];
|
||||
D3D11_INPUT_ELEMENT_DESC& dst = InputElements[i];
|
||||
uint32& offset = offsets[src.Slot];
|
||||
if (src.Offset != 0)
|
||||
offset = src.Offset;
|
||||
dst.SemanticName = RenderToolsDX::GetVertexInputSemantic(src.Type, dst.SemanticIndex);
|
||||
dst.Format = RenderToolsDX::ToDxgiFormat(src.Format);
|
||||
dst.InputSlot = src.Slot;
|
||||
dst.AlignedByteOffset = offset;
|
||||
dst.AlignedByteOffset = src.Offset;
|
||||
dst.InputSlotClass = src.PerInstance ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
|
||||
dst.InstanceDataStepRate = src.PerInstance ? 1 : 0;
|
||||
offset += PixelFormatExtensions::SizeInBytes(src.Format);
|
||||
}
|
||||
SetElements(elements, offsets);
|
||||
}
|
||||
|
||||
GPUDevice* GPUDeviceDX11::Create()
|
||||
@@ -832,9 +827,9 @@ GPUSampler* GPUDeviceDX11::CreateSampler()
|
||||
return New<GPUSamplerDX11>(this);
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUDeviceDX11::CreateVertexLayout(const VertexElements& elements)
|
||||
GPUVertexLayout* GPUDeviceDX11::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets)
|
||||
{
|
||||
return New<GPUVertexLayoutDX11>(this, elements);
|
||||
return New<GPUVertexLayoutDX11>(this, elements, explicitOffsets);
|
||||
}
|
||||
|
||||
GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window)
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
GPUTimerQuery* CreateTimerQuery() override;
|
||||
GPUBuffer* CreateBuffer(const StringView& name) override;
|
||||
GPUSampler* CreateSampler() override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override;
|
||||
GPUSwapChain* CreateSwapChain(Window* window) override;
|
||||
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
|
||||
};
|
||||
|
||||
@@ -11,19 +11,23 @@
|
||||
GPUShaderProgramVSDX11::~GPUShaderProgramVSDX11()
|
||||
{
|
||||
for (const auto& e : _cache)
|
||||
e.Value->Release();
|
||||
{
|
||||
if (e.Value)
|
||||
e.Value->Release();
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* vertexLayout)
|
||||
{
|
||||
if (!vertexLayout)
|
||||
vertexLayout = (GPUVertexLayoutDX11*)Layout;
|
||||
ID3D11InputLayout* inputLayout = nullptr;
|
||||
if (!_cache.TryGet(vertexLayout, inputLayout))
|
||||
{
|
||||
if (!vertexLayout)
|
||||
vertexLayout = (GPUVertexLayoutDX11*)Layout;
|
||||
if (vertexLayout && vertexLayout->InputElementsCount)
|
||||
{
|
||||
VALIDATE_DIRECTX_CALL(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(vertexLayout->InputElements, vertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout));
|
||||
auto actualLayout = (GPUVertexLayoutDX11*)GPUVertexLayout::Merge(vertexLayout, Layout);
|
||||
LOG_DIRECTX_RESULT(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(actualLayout->InputElements, actualLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout));
|
||||
}
|
||||
_cache.Add(vertexLayout, inputLayout);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class GPUVertexLayoutDX11 : public GPUResourceBase<GPUDeviceDX11, GPUVertexLayout>
|
||||
{
|
||||
public:
|
||||
GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements);
|
||||
GPUVertexLayoutDX11(GPUDeviceDX11* device, const Elements& elements, bool explicitOffsets);
|
||||
|
||||
uint32 InputElementsCount;
|
||||
D3D11_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS];
|
||||
|
||||
@@ -36,27 +36,22 @@ static bool CheckDX12Support(IDXGIAdapter* adapter)
|
||||
return false;
|
||||
}
|
||||
|
||||
GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements)
|
||||
GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements, bool explicitOffsets)
|
||||
: GPUResourceDX12<GPUVertexLayout>(device, StringView::Empty)
|
||||
, InputElementsCount(elements.Count())
|
||||
{
|
||||
uint32 offsets[GPU_MAX_VB_BINDED] = {};
|
||||
SetElements(elements, explicitOffsets);
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& src = elements.Get()[i];
|
||||
const VertexElement& src = GetElements().Get()[i];
|
||||
D3D12_INPUT_ELEMENT_DESC& dst = InputElements[i];
|
||||
uint32& offset = offsets[src.Slot];
|
||||
if (src.Offset != 0)
|
||||
offset = src.Offset;
|
||||
dst.SemanticName = RenderToolsDX::GetVertexInputSemantic(src.Type, dst.SemanticIndex);
|
||||
dst.Format = RenderToolsDX::ToDxgiFormat(src.Format);
|
||||
dst.InputSlot = src.Slot;
|
||||
dst.AlignedByteOffset = offset;
|
||||
dst.AlignedByteOffset = src.Offset;
|
||||
dst.InputSlotClass = src.PerInstance ? D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA : D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
dst.InstanceDataStepRate = src.PerInstance ? 1 : 0;
|
||||
offset += PixelFormatExtensions::SizeInBytes(src.Format);
|
||||
}
|
||||
SetElements(elements, offsets);
|
||||
}
|
||||
|
||||
GPUDevice* GPUDeviceDX12::Create()
|
||||
@@ -868,9 +863,9 @@ GPUSampler* GPUDeviceDX12::CreateSampler()
|
||||
return New<GPUSamplerDX12>(this);
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUDeviceDX12::CreateVertexLayout(const VertexElements& elements)
|
||||
GPUVertexLayout* GPUDeviceDX12::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets)
|
||||
{
|
||||
return New<GPUVertexLayoutDX12>(this, elements);
|
||||
return New<GPUVertexLayoutDX12>(this, elements, explicitOffsets);
|
||||
}
|
||||
|
||||
GPUSwapChain* GPUDeviceDX12::CreateSwapChain(Window* window)
|
||||
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
GPUTimerQuery* CreateTimerQuery() override;
|
||||
GPUBuffer* CreateBuffer(const StringView& name) override;
|
||||
GPUSampler* CreateSampler() override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override;
|
||||
GPUSwapChain* CreateSwapChain(Window* window) override;
|
||||
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class GPUVertexLayoutDX12 : public GPUResourceDX12<GPUVertexLayout>
|
||||
{
|
||||
public:
|
||||
GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements);
|
||||
GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements, bool explicitOffsets);
|
||||
|
||||
uint32 InputElementsCount;
|
||||
D3D12_INPUT_ELEMENT_DESC InputElements[GPU_MAX_VS_ELEMENTS];
|
||||
|
||||
@@ -173,7 +173,7 @@ GPUSampler* GPUDeviceNull::CreateSampler()
|
||||
return New<GPUSamplerNull>();
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUDeviceNull::CreateVertexLayout(const VertexElements& elements)
|
||||
GPUVertexLayout* GPUDeviceNull::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets)
|
||||
{
|
||||
return New<GPUVertexLayoutNull>(elements);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
GPUTimerQuery* CreateTimerQuery() override;
|
||||
GPUBuffer* CreateBuffer(const StringView& name) override;
|
||||
GPUSampler* CreateSampler() override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override;
|
||||
GPUSwapChain* CreateSwapChain(Window* window) override;
|
||||
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
GPUVertexLayoutNull(const Elements& elements)
|
||||
: GPUVertexLayout()
|
||||
{
|
||||
SetElements(elements, {});
|
||||
SetElements(elements, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -449,10 +449,10 @@ uint32 GetHash(const FramebufferVulkan::Key& key)
|
||||
return hash;
|
||||
}
|
||||
|
||||
GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements)
|
||||
GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements, bool explicitOffsets)
|
||||
: GPUResourceVulkan<GPUVertexLayout>(device, StringView::Empty)
|
||||
{
|
||||
uint32 offsets[GPU_MAX_VB_BINDED] = {};
|
||||
SetElements(elements, explicitOffsets);
|
||||
for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
|
||||
{
|
||||
VkVertexInputBindingDescription& binding = Bindings[i];
|
||||
@@ -463,28 +463,23 @@ GPUVertexLayoutVulkan::GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elem
|
||||
uint32 bindingsCount = 0;
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& src = elements.Get()[i];
|
||||
uint32& offset = offsets[src.Slot];
|
||||
if (src.Offset != 0)
|
||||
offset = src.Offset;
|
||||
const VertexElement& src = GetElements().Get()[i];
|
||||
const int32 size = PixelFormatExtensions::SizeInBytes(src.Format);
|
||||
|
||||
ASSERT_LOW_LAYER(src.Slot < GPU_MAX_VB_BINDED);
|
||||
VkVertexInputBindingDescription& binding = Bindings[src.Slot];
|
||||
binding.binding = src.Slot;
|
||||
binding.stride = Math::Max(binding.stride, (uint32_t)(offset + size));
|
||||
binding.stride = Math::Max(binding.stride, (uint32_t)(src.Offset + size));
|
||||
binding.inputRate = src.PerInstance ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
VkVertexInputAttributeDescription& attribute = Attributes[i];
|
||||
attribute.location = i;
|
||||
attribute.binding = src.Slot;
|
||||
attribute.format = RenderToolsVulkan::ToVulkanFormat(src.Format);
|
||||
attribute.offset = offset;
|
||||
attribute.offset = src.Offset;
|
||||
|
||||
bindingsCount = Math::Max(bindingsCount, (uint32)src.Slot + 1);
|
||||
offset += size;
|
||||
}
|
||||
SetElements(elements, offsets);
|
||||
|
||||
RenderToolsVulkan::ZeroStruct(CreateInfo, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
|
||||
CreateInfo.vertexBindingDescriptionCount = bindingsCount;
|
||||
@@ -2129,9 +2124,9 @@ GPUSampler* GPUDeviceVulkan::CreateSampler()
|
||||
return New<GPUSamplerVulkan>(this);
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUDeviceVulkan::CreateVertexLayout(const VertexElements& elements)
|
||||
GPUVertexLayout* GPUDeviceVulkan::CreateVertexLayout(const VertexElements& elements, bool explicitOffsets)
|
||||
{
|
||||
return New<GPUVertexLayoutVulkan>(this, elements);
|
||||
return New<GPUVertexLayoutVulkan>(this, elements, explicitOffsets);
|
||||
}
|
||||
|
||||
GPUSwapChain* GPUDeviceVulkan::CreateSwapChain(Window* window)
|
||||
|
||||
@@ -610,7 +610,7 @@ public:
|
||||
GPUTimerQuery* CreateTimerQuery() override;
|
||||
GPUBuffer* CreateBuffer(const StringView& name) override;
|
||||
GPUSampler* CreateSampler() override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements) override;
|
||||
GPUVertexLayout* CreateVertexLayout(const VertexElements& elements, bool explicitOffsets) override;
|
||||
GPUSwapChain* CreateSwapChain(Window* window) override;
|
||||
GPUConstantBuffer* CreateConstantBuffer(uint32 size, const StringView& name) override;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class GPUVertexLayoutVulkan : public GPUResourceVulkan<GPUVertexLayout>
|
||||
{
|
||||
public:
|
||||
GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements);
|
||||
GPUVertexLayoutVulkan(GPUDeviceVulkan* device, const Elements& elements, bool explicitOffsets);
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo CreateInfo;
|
||||
VkVertexInputBindingDescription Bindings[GPU_MAX_VB_BINDED];
|
||||
|
||||
Reference in New Issue
Block a user