Memory Changes part 2 (ryubing/ryujinx!123)

See merge request ryubing/ryujinx!123
This commit is contained in:
LotP
2025-08-25 17:44:15 -05:00
parent d499449f57
commit 50ab108ee1
90 changed files with 2133 additions and 1159 deletions

View File

@@ -26,13 +26,17 @@ namespace Ryujinx.Graphics.Vulkan
public bool BecomesUnsetFrom(in BitMapStruct<T> from, ref BitMapStruct<T> into)
{
bool result = false;
Span<long> masksSpan = _masks.AsSpan();
Span<long> fMasksSpan = from._masks.AsSpan();
Span<long> iMasksSpan = into._masks.AsSpan();
int masks = _masks.Length;
int masks = masksSpan.Length;
for (int i = 0; i < masks; i++)
{
long fromMask = from._masks[i];
long unsetMask = (~fromMask) & (fromMask ^ _masks[i]);
into._masks[i] = unsetMask;
long fromMask = fMasksSpan[i];
long unsetMask = (~fromMask) & (fromMask ^ masksSpan[i]);
iMasksSpan[i] = unsetMask;
result |= unsetMask != 0;
}
@@ -49,11 +53,11 @@ namespace Ryujinx.Graphics.Vulkan
// Iterate the set bits in the result, and signal them.
int offset = 0;
int masks = _masks.Length;
ref T resultMasks = ref result._masks;
Span<long> rMasksSpan = result._masks.AsSpan();
int masks = rMasksSpan.Length;
for (int i = 0; i < masks; i++)
{
long value = resultMasks[i];
long value = rMasksSpan[i];
while (value != 0)
{
int bit = BitOperations.TrailingZeroCount((ulong)value);
@@ -75,10 +79,11 @@ namespace Ryujinx.Graphics.Vulkan
// Iterate the set bits in the result, and signal them.
int offset = 0;
int masks = _masks.Length;
Span<long> masksSpan = _masks.AsSpan();
int masks = masksSpan.Length;
for (int i = 0; i < masks; i++)
{
long value = _masks[i];
long value = masksSpan[i];
while (value != 0)
{
int bit = BitOperations.TrailingZeroCount((ulong)value);
@@ -94,9 +99,11 @@ namespace Ryujinx.Graphics.Vulkan
public bool AnySet()
{
for (int i = 0; i < _masks.Length; i++)
Span<long> masksSpan = _masks.AsSpan();
for (int i = 0; i < masksSpan.Length; i++)
{
if (_masks[i] != 0)
if (masksSpan[i] != 0)
{
return true;
}
@@ -139,10 +146,12 @@ namespace Ryujinx.Graphics.Vulkan
{
return true;
}
Span<long> masksSpan = _masks.AsSpan();
for (int i = startIndex + 1; i < endIndex; i++)
{
if (_masks[i] != 0)
if (masksSpan[i] != 0)
{
return true;
}
@@ -200,21 +209,23 @@ namespace Ryujinx.Graphics.Vulkan
int endIndex = end >> IntShift;
int endBit = end & IntMask;
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
Span<long> masksSpan = _masks.AsSpan();
if (startIndex == endIndex)
{
_masks[startIndex] |= startMask & endMask;
masksSpan[startIndex] |= startMask & endMask;
}
else
{
_masks[startIndex] |= startMask;
masksSpan[startIndex] |= startMask;
for (int i = startIndex + 1; i < endIndex; i++)
{
_masks[i] |= -1L;
masksSpan[i] |= -1L;
}
_masks[endIndex] |= endMask;
masksSpan[endIndex] |= endMask;
}
}
@@ -222,13 +233,13 @@ namespace Ryujinx.Graphics.Vulkan
{
BitMapStruct<T> result = new();
ref T masks = ref _masks;
ref T otherMasks = ref other._masks;
ref T newMasks = ref result._masks;
Span<long> masksSpan = _masks.AsSpan();
Span<long> oMasksSpan = other._masks.AsSpan();
Span<long> nMasksSpan = result._masks.AsSpan();
for (int i = 0; i < masks.Length; i++)
for (int i = 0; i < masksSpan.Length; i++)
{
newMasks[i] = masks[i] | otherMasks[i];
nMasksSpan[i] = masksSpan[i] | oMasksSpan[i];
}
return result;
@@ -246,17 +257,21 @@ namespace Ryujinx.Graphics.Vulkan
public void Clear()
{
for (int i = 0; i < _masks.Length; i++)
Span<long> masksSpan = _masks.AsSpan();
for (int i = 0; i < masksSpan.Length; i++)
{
_masks[i] = 0;
masksSpan[i] = 0;
}
}
public void ClearInt(int start, int end)
{
Span<long> masksSpan = _masks.AsSpan();
for (int i = start; i <= end; i++)
{
_masks[i] = 0;
masksSpan[i] = 0;
}
}
}

View File

@@ -680,7 +680,7 @@ namespace Ryujinx.Graphics.Vulkan
ShaderCollection program = _program;
if (_dirty.HasFlag(DirtyFlags.Uniform))
if ((_dirty & DirtyFlags.Uniform) == DirtyFlags.Uniform)
{
if (program.UsePushDescriptors)
{
@@ -692,12 +692,12 @@ namespace Ryujinx.Graphics.Vulkan
}
}
if (_dirty.HasFlag(DirtyFlags.Storage))
if ((_dirty & DirtyFlags.Storage) == DirtyFlags.Storage)
{
UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
}
if (_dirty.HasFlag(DirtyFlags.Texture))
if ((_dirty & DirtyFlags.Texture) == DirtyFlags.Texture)
{
if (program.UpdateTexturesWithoutTemplate)
{
@@ -709,7 +709,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
if (_dirty.HasFlag(DirtyFlags.Image))
if ((_dirty & DirtyFlags.Image) == DirtyFlags.Image)
{
UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
}

View File

@@ -710,9 +710,11 @@ namespace Ryujinx.Graphics.Vulkan
public void SetBlendState(AdvancedBlendDescriptor blend)
{
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = _newState.Internal.ColorBlendAttachmentState.AsSpan();
for (int index = 0; index < Constants.MaxRenderTargets; index++)
{
ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
ref PipelineColorBlendAttachmentState vkBlend = ref colorBlendAttachmentStateSpan[index];
if (index == 0)
{
@@ -985,10 +987,12 @@ namespace Ryujinx.Graphics.Vulkan
{
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
int writtenAttachments = 0;
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = _newState.Internal.ColorBlendAttachmentState.AsSpan();
for (int i = 0; i < count; i++)
{
ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
ref PipelineColorBlendAttachmentState vkBlend = ref colorBlendAttachmentStateSpan[i];
ColorComponentFlags newMask = (ColorComponentFlags)componentMask[i];
// When color write mask is 0, remove all blend state to help the pipeline cache.
@@ -1166,6 +1170,8 @@ namespace Ryujinx.Graphics.Vulkan
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
uint dirtyVbSizes = 0;
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = _newState.Internal.VertexAttributeDescriptions.AsSpan();
for (int i = 0; i < count; i++)
{
@@ -1179,7 +1185,7 @@ namespace Ryujinx.Graphics.Vulkan
dirtyVbSizes |= 1u << rawIndex;
}
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
vertexAttributeDescriptionsSpan[i] = new VertexInputAttributeDescription(
(uint)i,
(uint)bufferIndex,
formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
@@ -1214,7 +1220,9 @@ namespace Ryujinx.Graphics.Vulkan
int validCount = 1;
BufferHandle lastHandle = default;
Auto<DisposableBuffer> lastBuffer = default;
Auto<DisposableBuffer> lastBuffer = null;
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan = _newState.Internal.VertexBindingDescriptions.AsSpan();
for (int i = 0; i < count; i++)
{
@@ -1236,7 +1244,7 @@ namespace Ryujinx.Graphics.Vulkan
int binding = i + 1;
int descriptorIndex = validCount++;
_newState.Internal.VertexBindingDescriptions[descriptorIndex] = new VertexInputBindingDescription(
vertexBindingDescriptionsSpan[descriptorIndex] = new VertexInputBindingDescription(
(uint)binding,
(uint)vertexBuffer.Stride,
inputRate);
@@ -1405,6 +1413,9 @@ namespace Ryujinx.Graphics.Vulkan
// Look for textures that are masked out.
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan =
_newState.Internal.ColorBlendAttachmentState.AsSpan();
for (int i = 0; i < colors.Length; i++)
{
if (colors[i] == null)
@@ -1412,7 +1423,7 @@ namespace Ryujinx.Graphics.Vulkan
continue;
}
ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
ref PipelineColorBlendAttachmentState vkBlend = ref colorBlendAttachmentStateSpan[i];
for (int j = 0; j < i; j++)
{
@@ -1421,7 +1432,7 @@ namespace Ryujinx.Graphics.Vulkan
if (colors[i] == colors[j])
{
// Prefer the binding with no write mask.
ref PipelineColorBlendAttachmentState vkBlend2 = ref _newState.Internal.ColorBlendAttachmentState[j];
ref PipelineColorBlendAttachmentState vkBlend2 = ref colorBlendAttachmentStateSpan[j];
if (vkBlend.ColorWriteMask == 0)
{
colors[i] = null;

View File

@@ -2,7 +2,8 @@ using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using Format = Silk.NET.Vulkan.Format;
using VulkanFormat = Silk.NET.Vulkan.Format;
using GALFormat = Ryujinx.Graphics.GAL.Format;
using PolygonMode = Silk.NET.Vulkan.PolygonMode;
namespace Ryujinx.Graphics.Vulkan
@@ -23,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
Span<int> attachmentIndices = stackalloc int[MaxAttachments];
Span<Format> attachmentFormats = stackalloc Format[MaxAttachments];
Span<VulkanFormat> attachmentFormats = stackalloc VulkanFormat[MaxAttachments];
int attachmentCount = 0;
int colorCount = 0;
@@ -32,14 +33,17 @@ namespace Ryujinx.Graphics.Vulkan
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
!state.DepthStencilFormat.IsImageCompatible();
for (int i = 0; i < state.AttachmentEnable.Length; i++)
Span<bool> attachmentEnableSpan = state.AttachmentEnable.AsSpan();
Span<GALFormat> attachmentFormatsSpan = state.AttachmentFormats.AsSpan();
for (int i = 0; i < attachmentEnableSpan.Length; i++)
{
if (state.AttachmentEnable[i])
if (attachmentEnableSpan[i])
{
bool isNotMsOrSupportsStorageAttachments = gd.Capabilities.SupportsShaderStorageImageMultisample ||
!state.AttachmentFormats[i].IsImageCompatible();
!attachmentFormatsSpan[i].IsImageCompatible();
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorageAttachments);
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorageAttachments);
attachmentIndices[attachmentCount++] = i;
colorCount++;
@@ -222,13 +226,15 @@ namespace Ryujinx.Graphics.Vulkan
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
Span<int> vbScalarSizes = stackalloc int[vbCount];
Span<VertexAttribDescriptor> vertexAttribsSpan = state.VertexAttribs.AsSpan();
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = pipeline.Internal.VertexAttributeDescriptions.AsSpan();
for (int i = 0; i < vaCount; i++)
{
VertexAttribDescriptor attribute = state.VertexAttribs[i];
VertexAttribDescriptor attribute = vertexAttribsSpan[i];
int bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
vertexAttributeDescriptionsSpan[i] = new VertexInputAttributeDescription(
(uint)i,
(uint)bufferIndex,
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
@@ -243,9 +249,12 @@ namespace Ryujinx.Graphics.Vulkan
int descriptorIndex = 1;
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
Span<BufferPipelineDescriptor> vertexBuffersSpan = state.VertexBuffers.AsSpan();
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan = pipeline.Internal.VertexBindingDescriptions.AsSpan();
for (int i = 0; i < vbCount; i++)
{
BufferPipelineDescriptor vertexBuffer = state.VertexBuffers[i];
BufferPipelineDescriptor vertexBuffer = vertexBuffersSpan[i];
if (vertexBuffer.Enable)
{
@@ -259,7 +268,7 @@ namespace Ryujinx.Graphics.Vulkan
}
// TODO: Support divisor > 1
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
vertexBindingDescriptionsSpan[descriptorIndex++] = new VertexInputBindingDescription(
(uint)i + 1,
(uint)alignedStride,
inputRate);
@@ -268,15 +277,19 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.VertexBindingDescriptionsCount = (uint)descriptorIndex;
Span<BlendDescriptor> blendDescriptorsSpan = state.BlendDescriptors.AsSpan();
Span<uint> colorWriteMaskSpan = state.ColorWriteMask.AsSpan();
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = pipeline.Internal.ColorBlendAttachmentState.AsSpan();
// NOTE: Viewports, Scissors are dynamic.
for (int i = 0; i < Constants.MaxRenderTargets; i++)
{
BlendDescriptor blend = state.BlendDescriptors[i];
BlendDescriptor blend = blendDescriptorsSpan[i];
if (blend.Enable && state.ColorWriteMask[i] != 0)
if (blend.Enable && colorWriteMaskSpan[i] != 0)
{
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
colorBlendAttachmentStateSpan[i] = new PipelineColorBlendAttachmentState(
blend.Enable,
blend.ColorSrcFactor.Convert(),
blend.ColorDstFactor.Convert(),
@@ -284,12 +297,12 @@ namespace Ryujinx.Graphics.Vulkan
blend.AlphaSrcFactor.Convert(),
blend.AlphaDstFactor.Convert(),
blend.AlphaOp.Convert(),
(ColorComponentFlags)state.ColorWriteMask[i]);
(ColorComponentFlags)colorWriteMaskSpan[i]);
}
else
{
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
colorBlendAttachmentStateSpan[i] = new PipelineColorBlendAttachmentState(
colorWriteMask: (ColorComponentFlags)colorWriteMaskSpan[i]);
}
}
@@ -297,23 +310,27 @@ namespace Ryujinx.Graphics.Vulkan
int maxColorAttachmentIndex = -1;
uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = true;
Span<bool> attachmentEnableSpan = state.AttachmentEnable.AsSpan();
Span<GALFormat> attachmentFormatsSpan = state.AttachmentFormats.AsSpan();
Span<VulkanFormat> pAttachmentFormatsSpan = pipeline.Internal.AttachmentFormats.AsSpan();
for (int i = 0; i < Constants.MaxRenderTargets; i++)
{
if (state.AttachmentEnable[i])
if (attachmentEnableSpan[i])
{
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
!state.AttachmentFormats[i].IsImageCompatible();
!attachmentFormatsSpan[i].IsImageCompatible();
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorage);
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorage);
maxColorAttachmentIndex = i;
if (state.AttachmentFormats[i].IsInteger())
if (attachmentFormatsSpan[i].IsInteger())
{
attachmentIntegerFormatMask |= 1u << i;
}
allFormatsFloatOrSrgb &= state.AttachmentFormats[i].IsFloatOrSrgb();
allFormatsFloatOrSrgb &= attachmentFormatsSpan[i].IsFloatOrSrgb();
}
}
@@ -322,7 +339,7 @@ namespace Ryujinx.Graphics.Vulkan
bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible() ||
gd.Capabilities.SupportsShaderStorageImageMultisample;
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage);
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage);
}
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);

View File

@@ -121,32 +121,32 @@ namespace Ryujinx.Graphics.Vulkan
{
Vk api = gd.Api;
if (_dirty.HasFlag(DirtyFlags.Blend))
if ((_dirty & DirtyFlags.Blend) == DirtyFlags.Blend)
{
RecordBlend(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.DepthBias))
if ((_dirty & DirtyFlags.DepthBias) == DirtyFlags.DepthBias)
{
RecordDepthBias(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.Scissor))
if ((_dirty & DirtyFlags.Scissor) == DirtyFlags.Scissor)
{
RecordScissor(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.Stencil))
if ((_dirty & DirtyFlags.Stencil) == DirtyFlags.Stencil)
{
RecordStencilMasks(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.Viewport))
if ((_dirty & DirtyFlags.Viewport) == DirtyFlags.Viewport)
{
RecordViewport(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
if ((_dirty & DirtyFlags.FeedbackLoop) == DirtyFlags.FeedbackLoop && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
{
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
}

View File

@@ -520,6 +520,9 @@ namespace Ryujinx.Graphics.Vulkan
};
uint blendEnables = 0;
Span<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan =
Internal.ColorBlendAttachmentState.AsSpan();
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
{
@@ -530,12 +533,12 @@ namespace Ryujinx.Graphics.Vulkan
{
int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
if (Internal.ColorBlendAttachmentState[i].BlendEnable)
if (colorBlendAttachmentStateSpan[i].BlendEnable)
{
blendEnables |= 1u << i;
}
Internal.ColorBlendAttachmentState[i].BlendEnable = false;
colorBlendAttachmentStateSpan[i].BlendEnable = false;
attachmentIntegerFormatMask &= ~(1u << i);
}
}
@@ -656,7 +659,7 @@ namespace Ryujinx.Graphics.Vulkan
{
int i = BitOperations.TrailingZeroCount(blendEnables);
Internal.ColorBlendAttachmentState[i].BlendEnable = true;
colorBlendAttachmentStateSpan[i].BlendEnable = true;
blendEnables &= ~(1u << i);
}
}
@@ -675,14 +678,21 @@ namespace Ryujinx.Graphics.Vulkan
// To work around this, we reduce the format to something that doesn't exceed the stride if possible.
// The assumption is that the exceeding components are not actually accessed on the shader.
Span<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan =
Internal.VertexAttributeDescriptions.AsSpan();
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan =
Internal.VertexBindingDescriptions.AsSpan();
Span<VertexInputAttributeDescription> vertexAttributeDescriptions2Span =
_vertexAttributeDescriptions2.AsSpan();
for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
{
VertexInputAttributeDescription attribute = Internal.VertexAttributeDescriptions[index];
VertexInputAttributeDescription attribute = vertexAttributeDescriptionsSpan[index];
int vbIndex = GetVertexBufferIndex(attribute.Binding);
if (vbIndex >= 0)
{
ref VertexInputBindingDescription vb = ref Internal.VertexBindingDescriptions[vbIndex];
ref VertexInputBindingDescription vb = ref vertexBindingDescriptionsSpan[vbIndex];
Format format = attribute.Format;
@@ -707,15 +717,18 @@ namespace Ryujinx.Graphics.Vulkan
}
}
_vertexAttributeDescriptions2[index] = attribute;
vertexAttributeDescriptions2Span[index] = attribute;
}
}
private int GetVertexBufferIndex(uint binding)
{
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan =
Internal.VertexBindingDescriptions.AsSpan();
for (int index = 0; index < VertexBindingDescriptionsCount; index++)
{
if (Internal.VertexBindingDescriptions[index].Binding == binding)
if (vertexBindingDescriptionsSpan[index].Binding == binding)
{
return index;
}

View File

@@ -86,37 +86,45 @@ namespace Ryujinx.Graphics.Vulkan
Id6 * 23 ^
Id7 * 23 ^
Id8 * 23;
ReadOnlySpan<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = VertexAttributeDescriptions.AsSpan();
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
{
hash64 ^= VertexAttributeDescriptions[i].Binding * 23;
hash64 ^= (uint)VertexAttributeDescriptions[i].Format * 23;
hash64 ^= VertexAttributeDescriptions[i].Location * 23;
hash64 ^= VertexAttributeDescriptions[i].Offset * 23;
hash64 ^= vertexAttributeDescriptionsSpan[i].Binding * 23;
hash64 ^= (uint)vertexAttributeDescriptionsSpan[i].Format * 23;
hash64 ^= vertexAttributeDescriptionsSpan[i].Location * 23;
hash64 ^= vertexAttributeDescriptionsSpan[i].Offset * 23;
}
ReadOnlySpan<VertexInputBindingDescription> vertexBindingDescriptionsSpan = VertexBindingDescriptions.AsSpan();
for (int i = 0; i < (int)VertexBindingDescriptionsCount; i++)
{
hash64 ^= VertexBindingDescriptions[i].Binding * 23;
hash64 ^= (uint)VertexBindingDescriptions[i].InputRate * 23;
hash64 ^= VertexBindingDescriptions[i].Stride * 23;
hash64 ^= vertexBindingDescriptionsSpan[i].Binding * 23;
hash64 ^= (uint)vertexBindingDescriptionsSpan[i].InputRate * 23;
hash64 ^= vertexBindingDescriptionsSpan[i].Stride * 23;
}
ReadOnlySpan<PipelineColorBlendAttachmentState> colorBlendAttachmentStateSpan = ColorBlendAttachmentState.AsSpan();
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
{
hash64 ^= ColorBlendAttachmentState[i].BlendEnable * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].SrcColorBlendFactor * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].DstColorBlendFactor * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].ColorBlendOp * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].SrcAlphaBlendFactor * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].DstAlphaBlendFactor * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].AlphaBlendOp * 23;
hash64 ^= (uint)ColorBlendAttachmentState[i].ColorWriteMask * 23;
hash64 ^= colorBlendAttachmentStateSpan[i].BlendEnable * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].SrcColorBlendFactor * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].DstColorBlendFactor * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].ColorBlendOp * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].SrcAlphaBlendFactor * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].DstAlphaBlendFactor * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].AlphaBlendOp * 23;
hash64 ^= (uint)colorBlendAttachmentStateSpan[i].ColorWriteMask * 23;
}
ReadOnlySpan<Format> attachmentFormatsSpan = AttachmentFormats.AsSpan();
for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++)
{
hash64 ^= (uint)AttachmentFormats[i] * 23;
hash64 ^= (uint)attachmentFormatsSpan[i] * 23;
}
return (int)hash64 ^ ((int)(hash64 >> 32) * 17);