internal static unsafe SharpVulkan.DescriptorSetLayout CreateNativeDescriptorSetLayout(GraphicsDevice device, IList <DescriptorSetLayoutBuilder.Entry> entries, out uint[] typeCounts) { var bindings = new DescriptorSetLayoutBinding[entries.Count]; var immutableSamplers = new Sampler[entries.Count]; int usedBindingCount = 0; typeCounts = new uint[DescriptorTypeCount]; fixed(Sampler *immutableSamplersPointer = &immutableSamplers[0]) { for (int i = 0; i < entries.Count; i++) { var entry = entries[i]; // TODO VULKAN: Special case for unused bindings in PipelineState. Handle more nicely. if (entry.ArraySize == 0) { continue; } bindings[usedBindingCount] = new DescriptorSetLayoutBinding { DescriptorType = VulkanConvertExtensions.ConvertDescriptorType(entry.Class, entry.Type), StageFlags = ShaderStageFlags.All, // TODO VULKAN: Filter? Binding = (uint)i, DescriptorCount = (uint)entry.ArraySize }; if (entry.ImmutableSampler != null) { // TODO VULKAN: Handle immutable samplers for DescriptorCount > 1 if (entry.ArraySize > 1) { throw new NotImplementedException(); } // Remember this, so we can choose the right DescriptorType in DescriptorSet.SetShaderResourceView immutableSamplers[i] = entry.ImmutableSampler.NativeSampler; //bindings[i].DescriptorType = DescriptorType.CombinedImageSampler; bindings[usedBindingCount].ImmutableSamplers = new IntPtr(immutableSamplersPointer + i); } typeCounts[(int)bindings[usedBindingCount].DescriptorType] += bindings[usedBindingCount].DescriptorCount; usedBindingCount++; } var createInfo = new DescriptorSetLayoutCreateInfo { StructureType = StructureType.DescriptorSetLayoutCreateInfo, BindingCount = (uint)usedBindingCount, Bindings = usedBindingCount > 0 ? new IntPtr(Interop.Fixed(bindings)) : IntPtr.Zero }; return(device.NativeDevice.CreateDescriptorSetLayout(ref createInfo)); } }
private unsafe void CreatePipelineLayout(PipelineStateDescription pipelineStateDescription) { // Remap descriptor set indices to those in the shader. This ordering generated by the ShaderCompiler var resourceGroups = pipelineStateDescription.EffectBytecode.Reflection.ResourceBindings.Select(x => x.ResourceGroup ?? "Globals").Distinct().ToList(); ResourceGroupCount = resourceGroups.Count; var layouts = pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.Layouts; // Get binding indices used by the shader var destinationBindings = pipelineStateDescription.EffectBytecode.Stages .SelectMany(x => BinarySerialization.Read <ShaderInputBytecode>(x.Data).ResourceBindings) .GroupBy(x => x.Key, x => x.Value) .ToDictionary(x => x.Key, x => x.First()); var maxBindingIndex = destinationBindings.Max(x => x.Value); var destinationEntries = new DescriptorSetLayoutBuilder.Entry[maxBindingIndex + 1]; DescriptorBindingMapping = new List <DescriptorSetInfo>(); for (int i = 0; i < resourceGroups.Count; i++) { var resourceGroupName = resourceGroups[i] == "Globals" ? pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.DefaultSetSlot : resourceGroups[i]; var layoutIndex = resourceGroups[i] == null ? 0 : layouts.FindIndex(x => x.Name == resourceGroupName); // Check if the resource group is used by the shader if (layoutIndex == -1) { continue; } var sourceEntries = layouts[layoutIndex].Layout.Entries; for (int sourceBinding = 0; sourceBinding < sourceEntries.Count; sourceBinding++) { var sourceEntry = sourceEntries[sourceBinding]; int destinationBinding; if (destinationBindings.TryGetValue(sourceEntry.Key.Name, out destinationBinding)) { destinationEntries[destinationBinding] = sourceEntry; // No need to umpdate immutable samplers if (sourceEntry.Class == EffectParameterClass.Sampler && sourceEntry.ImmutableSampler != null) { continue; } DescriptorBindingMapping.Add(new DescriptorSetInfo { SourceSet = layoutIndex, SourceBinding = sourceBinding, DestinationBinding = destinationBinding, DescriptorType = VulkanConvertExtensions.ConvertDescriptorType(sourceEntry.Class, sourceEntry.Type) }); } } } // Create default sampler, used by texture and buffer loads destinationEntries[0] = new DescriptorSetLayoutBuilder.Entry { Class = EffectParameterClass.Sampler, Type = EffectParameterType.Sampler, ImmutableSampler = GraphicsDevice.SamplerStates.PointWrap, ArraySize = 1, }; // Create descriptor set layout NativeDescriptorSetLayout = DescriptorSetLayout.CreateNativeDescriptorSetLayout(GraphicsDevice, destinationEntries, out DescriptorTypeCounts); // Create pipeline layout var nativeDescriptorSetLayout = NativeDescriptorSetLayout; var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo { StructureType = StructureType.PipelineLayoutCreateInfo, SetLayoutCount = 1, SetLayouts = new IntPtr(&nativeDescriptorSetLayout) }; NativeLayout = GraphicsDevice.NativeDevice.CreatePipelineLayout(ref pipelineLayoutCreateInfo); }