| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- using Silk.NET.Vulkan;
- using System;
- namespace Ryujinx.Graphics.Vulkan
- {
- struct PipelineState : IDisposable
- {
- private const int RequiredSubgroupSize = 32;
- public PipelineUid Internal;
- public float LineWidth
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 0) & 0xFFFFFFFF));
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
- }
- public float DepthBiasClamp
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 32) & 0xFFFFFFFF));
- set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
- }
- public float DepthBiasConstantFactor
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 0) & 0xFFFFFFFF));
- set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
- }
- public float DepthBiasSlopeFactor
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 32) & 0xFFFFFFFF));
- set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
- }
- public uint StencilFrontCompareMask
- {
- get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF);
- set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
- }
- public uint StencilFrontWriteMask
- {
- get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF);
- set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32);
- }
- public uint StencilFrontReference
- {
- get => (uint)((Internal.Id3 >> 0) & 0xFFFFFFFF);
- set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
- }
- public uint StencilBackCompareMask
- {
- get => (uint)((Internal.Id3 >> 32) & 0xFFFFFFFF);
- set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF) | ((ulong)value << 32);
- }
- public uint StencilBackWriteMask
- {
- get => (uint)((Internal.Id4 >> 0) & 0xFFFFFFFF);
- set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
- }
- public uint StencilBackReference
- {
- get => (uint)((Internal.Id4 >> 32) & 0xFFFFFFFF);
- set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
- }
- public float MinDepthBounds
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 0) & 0xFFFFFFFF));
- set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
- }
- public float MaxDepthBounds
- {
- get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 32) & 0xFFFFFFFF));
- set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
- }
- public PolygonMode PolygonMode
- {
- get => (PolygonMode)((Internal.Id6 >> 0) & 0x3FFFFFFF);
- set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
- }
- public uint StagesCount
- {
- get => (byte)((Internal.Id6 >> 30) & 0xFF);
- set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
- }
- public uint VertexAttributeDescriptionsCount
- {
- get => (byte)((Internal.Id6 >> 38) & 0xFF);
- set => Internal.Id6 = (Internal.Id6 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
- }
- public uint VertexBindingDescriptionsCount
- {
- get => (byte)((Internal.Id6 >> 46) & 0xFF);
- set => Internal.Id6 = (Internal.Id6 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
- }
- public uint ViewportsCount
- {
- get => (byte)((Internal.Id6 >> 54) & 0xFF);
- set => Internal.Id6 = (Internal.Id6 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
- }
- public uint ScissorsCount
- {
- get => (byte)((Internal.Id7 >> 0) & 0xFF);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
- }
- public uint ColorBlendAttachmentStateCount
- {
- get => (byte)((Internal.Id7 >> 8) & 0xFF);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
- }
- public PrimitiveTopology Topology
- {
- get => (PrimitiveTopology)((Internal.Id7 >> 16) & 0xF);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
- }
- public LogicOp LogicOp
- {
- get => (LogicOp)((Internal.Id7 >> 20) & 0xF);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
- }
- public CompareOp DepthCompareOp
- {
- get => (CompareOp)((Internal.Id7 >> 24) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
- }
- public StencilOp StencilFrontFailOp
- {
- get => (StencilOp)((Internal.Id7 >> 27) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
- }
- public StencilOp StencilFrontPassOp
- {
- get => (StencilOp)((Internal.Id7 >> 30) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
- }
- public StencilOp StencilFrontDepthFailOp
- {
- get => (StencilOp)((Internal.Id7 >> 33) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
- }
- public CompareOp StencilFrontCompareOp
- {
- get => (CompareOp)((Internal.Id7 >> 36) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
- }
- public StencilOp StencilBackFailOp
- {
- get => (StencilOp)((Internal.Id7 >> 39) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
- }
- public StencilOp StencilBackPassOp
- {
- get => (StencilOp)((Internal.Id7 >> 42) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
- }
- public StencilOp StencilBackDepthFailOp
- {
- get => (StencilOp)((Internal.Id7 >> 45) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
- }
- public CompareOp StencilBackCompareOp
- {
- get => (CompareOp)((Internal.Id7 >> 48) & 0x7);
- set => Internal.Id7 = (Internal.Id7 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
- }
- public CullModeFlags CullMode
- {
- get => (CullModeFlags)((Internal.Id7 >> 51) & 0x3);
- set => Internal.Id7 = (Internal.Id7 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
- }
- public bool PrimitiveRestartEnable
- {
- get => ((Internal.Id7 >> 53) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
- }
- public bool DepthClampEnable
- {
- get => ((Internal.Id7 >> 54) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
- }
- public bool RasterizerDiscardEnable
- {
- get => ((Internal.Id7 >> 55) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
- }
- public FrontFace FrontFace
- {
- get => (FrontFace)((Internal.Id7 >> 56) & 0x1);
- set => Internal.Id7 = (Internal.Id7 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
- }
- public bool DepthBiasEnable
- {
- get => ((Internal.Id7 >> 57) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
- }
- public bool DepthTestEnable
- {
- get => ((Internal.Id7 >> 58) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
- }
- public bool DepthWriteEnable
- {
- get => ((Internal.Id7 >> 59) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
- }
- public bool DepthBoundsTestEnable
- {
- get => ((Internal.Id7 >> 60) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
- }
- public bool StencilTestEnable
- {
- get => ((Internal.Id7 >> 61) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
- }
- public bool LogicOpEnable
- {
- get => ((Internal.Id7 >> 62) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
- }
- public bool HasDepthStencil
- {
- get => ((Internal.Id7 >> 63) & 0x1) != 0UL;
- set => Internal.Id7 = (Internal.Id7 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
- }
- public uint PatchControlPoints
- {
- get => (uint)((Internal.Id8 >> 0) & 0xFFFFFFFF);
- set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
- }
- public uint SamplesCount
- {
- get => (uint)((Internal.Id8 >> 32) & 0xFFFFFFFF);
- set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF) | ((ulong)value << 32);
- }
- public bool AlphaToCoverageEnable
- {
- get => ((Internal.Id9 >> 0) & 0x1) != 0UL;
- set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
- }
- public bool AlphaToOneEnable
- {
- get => ((Internal.Id9 >> 1) & 0x1) != 0UL;
- set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
- }
- public NativeArray<PipelineShaderStageCreateInfo> Stages;
- public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
- public PipelineLayout PipelineLayout;
- public SpecData SpecializationData;
- public void Initialize()
- {
- Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
- StageRequiredSubgroupSizes = new NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(Constants.MaxShaderStages);
- for (int index = 0; index < Constants.MaxShaderStages; index++)
- {
- StageRequiredSubgroupSizes[index] = new PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT()
- {
- SType = StructureType.PipelineShaderStageRequiredSubgroupSizeCreateInfoExt,
- RequiredSubgroupSize = RequiredSubgroupSize
- };
- }
- }
- public unsafe Auto<DisposablePipeline> CreateComputePipeline(
- VulkanRenderer gd,
- Device device,
- ShaderCollection program,
- PipelineCache cache)
- {
- if (program.TryGetComputePipeline(ref SpecializationData, out var pipeline))
- {
- return pipeline;
- }
- if (gd.Capabilities.SupportsSubgroupSizeControl)
- {
- UpdateStageRequiredSubgroupSizes(gd, 1);
- }
- var pipelineCreateInfo = new ComputePipelineCreateInfo()
- {
- SType = StructureType.ComputePipelineCreateInfo,
- Stage = Stages[0],
- BasePipelineIndex = -1,
- Layout = PipelineLayout
- };
- Pipeline pipelineHandle = default;
- bool hasSpec = program.SpecDescriptions != null;
- var desc = hasSpec ? program.SpecDescriptions[0] : SpecDescription.Empty;
- if (hasSpec && SpecializationData.Length < (int)desc.Info.DataSize)
- {
- throw new InvalidOperationException("Specialization data size does not match description");
- }
- fixed (SpecializationInfo* info = &desc.Info)
- fixed (SpecializationMapEntry* map = desc.Map)
- fixed (byte* data = SpecializationData.Span)
- {
- if (hasSpec)
- {
- info->PMapEntries = map;
- info->PData = data;
- pipelineCreateInfo.Stage.PSpecializationInfo = info;
- }
- gd.Api.CreateComputePipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
- }
- pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
- program.AddComputePipeline(ref SpecializationData, pipeline);
- return pipeline;
- }
- public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
- VulkanRenderer gd,
- Device device,
- ShaderCollection program,
- PipelineCache cache,
- RenderPass renderPass)
- {
- if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline))
- {
- return pipeline;
- }
- Pipeline pipelineHandle = default;
- fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0])
- fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0])
- fixed (Viewport* pViewports = &Internal.Viewports[0])
- fixed (Rect2D* pScissors = &Internal.Scissors[0])
- fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0])
- {
- var vertexInputState = new PipelineVertexInputStateCreateInfo
- {
- SType = StructureType.PipelineVertexInputStateCreateInfo,
- VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
- PVertexAttributeDescriptions = pVertexAttributeDescriptions,
- VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
- PVertexBindingDescriptions = pVertexBindingDescriptions
- };
- bool primitiveRestartEnable = PrimitiveRestartEnable;
- primitiveRestartEnable &= Topology == PrimitiveTopology.LineStrip ||
- Topology == PrimitiveTopology.TriangleStrip ||
- Topology == PrimitiveTopology.TriangleFan ||
- Topology == PrimitiveTopology.LineStripWithAdjacency ||
- Topology == PrimitiveTopology.TriangleStripWithAdjacency;
- var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo()
- {
- SType = StructureType.PipelineInputAssemblyStateCreateInfo,
- PrimitiveRestartEnable = primitiveRestartEnable,
- Topology = Topology
- };
- var tessellationState = new PipelineTessellationStateCreateInfo()
- {
- SType = StructureType.PipelineTessellationStateCreateInfo,
- PatchControlPoints = PatchControlPoints
- };
- var rasterizationState = new PipelineRasterizationStateCreateInfo()
- {
- SType = StructureType.PipelineRasterizationStateCreateInfo,
- DepthClampEnable = DepthClampEnable,
- RasterizerDiscardEnable = RasterizerDiscardEnable,
- PolygonMode = PolygonMode,
- LineWidth = LineWidth,
- CullMode = CullMode,
- FrontFace = FrontFace,
- DepthBiasEnable = DepthBiasEnable,
- DepthBiasClamp = DepthBiasClamp,
- DepthBiasConstantFactor = DepthBiasConstantFactor,
- DepthBiasSlopeFactor = DepthBiasSlopeFactor
- };
- var viewportState = new PipelineViewportStateCreateInfo()
- {
- SType = StructureType.PipelineViewportStateCreateInfo,
- ViewportCount = ViewportsCount,
- PViewports = pViewports,
- ScissorCount = ScissorsCount,
- PScissors = pScissors
- };
- var multisampleState = new PipelineMultisampleStateCreateInfo
- {
- SType = StructureType.PipelineMultisampleStateCreateInfo,
- SampleShadingEnable = false,
- RasterizationSamples = TextureStorage.ConvertToSampleCountFlags(SamplesCount),
- MinSampleShading = 1,
- AlphaToCoverageEnable = AlphaToCoverageEnable,
- AlphaToOneEnable = AlphaToOneEnable
- };
- var stencilFront = new StencilOpState(
- StencilFrontFailOp,
- StencilFrontPassOp,
- StencilFrontDepthFailOp,
- StencilFrontCompareOp,
- StencilFrontCompareMask,
- StencilFrontWriteMask,
- StencilFrontReference);
- var stencilBack = new StencilOpState(
- StencilBackFailOp,
- StencilBackPassOp,
- StencilBackDepthFailOp,
- StencilBackCompareOp,
- StencilBackCompareMask,
- StencilBackWriteMask,
- StencilBackReference);
- var depthStencilState = new PipelineDepthStencilStateCreateInfo()
- {
- SType = StructureType.PipelineDepthStencilStateCreateInfo,
- DepthTestEnable = DepthTestEnable,
- DepthWriteEnable = DepthWriteEnable,
- DepthCompareOp = DepthCompareOp,
- DepthBoundsTestEnable = DepthBoundsTestEnable,
- StencilTestEnable = StencilTestEnable,
- Front = stencilFront,
- Back = stencilBack,
- MinDepthBounds = MinDepthBounds,
- MaxDepthBounds = MaxDepthBounds
- };
- var colorBlendState = new PipelineColorBlendStateCreateInfo()
- {
- SType = StructureType.PipelineColorBlendStateCreateInfo,
- LogicOpEnable = LogicOpEnable,
- LogicOp = LogicOp,
- AttachmentCount = ColorBlendAttachmentStateCount,
- PAttachments = pColorBlendAttachmentState
- };
- bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
- int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
- DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
- dynamicStates[0] = DynamicState.Viewport;
- dynamicStates[1] = DynamicState.Scissor;
- dynamicStates[2] = DynamicState.DepthBias;
- dynamicStates[3] = DynamicState.DepthBounds;
- dynamicStates[4] = DynamicState.StencilCompareMask;
- dynamicStates[5] = DynamicState.StencilWriteMask;
- dynamicStates[6] = DynamicState.StencilReference;
- dynamicStates[7] = DynamicState.BlendConstants;
- if (supportsExtDynamicState)
- {
- dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
- }
- var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo()
- {
- SType = StructureType.PipelineDynamicStateCreateInfo,
- DynamicStateCount = (uint)dynamicStatesCount,
- PDynamicStates = dynamicStates
- };
- if (gd.Capabilities.SupportsSubgroupSizeControl)
- {
- UpdateStageRequiredSubgroupSizes(gd, (int)StagesCount);
- }
- var pipelineCreateInfo = new GraphicsPipelineCreateInfo()
- {
- SType = StructureType.GraphicsPipelineCreateInfo,
- StageCount = StagesCount,
- PStages = Stages.Pointer,
- PVertexInputState = &vertexInputState,
- PInputAssemblyState = &inputAssemblyState,
- PTessellationState = &tessellationState,
- PViewportState = &viewportState,
- PRasterizationState = &rasterizationState,
- PMultisampleState = &multisampleState,
- PDepthStencilState = &depthStencilState,
- PColorBlendState = &colorBlendState,
- PDynamicState = &pipelineDynamicStateCreateInfo,
- Layout = PipelineLayout,
- RenderPass = renderPass,
- BasePipelineIndex = -1
- };
- gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
- }
- pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
- program.AddGraphicsPipeline(ref Internal, pipeline);
- return pipeline;
- }
- private unsafe void UpdateStageRequiredSubgroupSizes(VulkanRenderer gd, int count)
- {
- for (int index = 0; index < count; index++)
- {
- bool canUseExplicitSubgroupSize =
- (gd.Capabilities.RequiredSubgroupSizeStages & Stages[index].Stage) != 0 &&
- gd.Capabilities.MinSubgroupSize <= RequiredSubgroupSize &&
- gd.Capabilities.MaxSubgroupSize >= RequiredSubgroupSize;
- Stages[index].PNext = canUseExplicitSubgroupSize ? StageRequiredSubgroupSizes.Pointer + index : null;
- }
- }
- public void Dispose()
- {
- Stages.Dispose();
- StageRequiredSubgroupSizes.Dispose();
- }
- }
- }
|