public static PipelineState New(GraphicsDevice graphicsDevice, ref PipelineStateDescription pipelineStateDescription)
        {
            // Hash the current state
            var hashedState = new PipelineStateDescriptionWithHash(pipelineStateDescription);

            // Store SamplerState in a cache (D3D seems to have quite bad concurrency when using CreateSampler while rendering)
            PipelineState pipelineState;

            lock (graphicsDevice.CachedPipelineStates)
            {
                if (graphicsDevice.CachedPipelineStates.TryGetValue(hashedState, out pipelineState))
                {
                    // TODO: Appropriate destroy
                    pipelineState.AddReferenceInternal();
                }
                else
                {
                    pipelineState = new PipelineState(graphicsDevice, pipelineStateDescription);
                    graphicsDevice.CachedPipelineStates.Add(hashedState, pipelineState);
                }
            }
            return(pipelineState);
        }
Example #2
0
 private void AdjustDefaultPipelineStateDescription(ref PipelineStateDescription pipelineStateDescription)
 {
     // On D3D, default state is Less instead of our LessEqual
     // Let's update default pipeline state so that it correspond to D3D state after a "ClearState()"
     pipelineStateDescription.DepthStencilState.DepthBufferFunction = CompareFunction.Less;
 }
 private void AdjustDefaultPipelineStateDescription(ref PipelineStateDescription pipelineStateDescription)
 {
 }
Example #4
0
        internal unsafe PipelineState(GraphicsDevice graphicsDevice, PipelineStateDescription pipelineStateDescription) : base(graphicsDevice)
        {
            if (pipelineStateDescription.RootSignature != null)
            {
                var effectReflection = pipelineStateDescription.EffectBytecode.Reflection;

                var rootSignatureParameters = new List <RootParameter>();
                var immutableSamplers       = new List <StaticSamplerDescription>();
                SrvBindCounts     = new int[pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.Layouts.Count];
                SamplerBindCounts = new int[pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.Layouts.Count];
                for (int layoutIndex = 0; layoutIndex < pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.Layouts.Count; layoutIndex++)
                {
                    var layout = pipelineStateDescription.RootSignature.EffectDescriptorSetReflection.Layouts[layoutIndex];
                    if (layout.Layout == null)
                    {
                        continue;
                    }

                    // TODO D3D12 for now, we don't control register so we simply generate one resource table per shader stage and per descriptor set layout
                    //            we should switch to a model where we make sure VS/PS don't overlap for common descriptors so that they can be shared
                    var srvDescriptorRangesVS     = new List <DescriptorRange>();
                    var srvDescriptorRangesPS     = new List <DescriptorRange>();
                    var samplerDescriptorRangesVS = new List <DescriptorRange>();
                    var samplerDescriptorRangesPS = new List <DescriptorRange>();

                    int descriptorSrvOffset     = 0;
                    int descriptorSamplerOffset = 0;
                    foreach (var item in layout.Layout.Entries)
                    {
                        var isSampler = item.Class == EffectParameterClass.Sampler;

                        // Find matching resource bindings
                        foreach (var binding in effectReflection.ResourceBindings)
                        {
                            if (binding.Stage == ShaderStage.None || binding.Param.Key != item.Key)
                            {
                                continue;
                            }

                            List <DescriptorRange> descriptorRanges;
                            switch (binding.Stage)
                            {
                            case ShaderStage.Vertex:
                                descriptorRanges = isSampler ? samplerDescriptorRangesVS : srvDescriptorRangesVS;
                                break;

                            case ShaderStage.Pixel:
                                descriptorRanges = isSampler ? samplerDescriptorRangesPS : srvDescriptorRangesPS;
                                break;

                            default:
                                throw new NotImplementedException();
                            }

                            if (isSampler)
                            {
                                if (item.ImmutableSampler != null)
                                {
                                    immutableSamplers.Add(new StaticSamplerDescription((ShaderVisibility)binding.Stage, binding.SlotStart, 0)
                                    {
                                        // TODO D3D12 other states
                                        // TODO D3D12 ImmutableSampler should only be a state description instead of a GPU object?
                                        Filter        = (Filter)item.ImmutableSampler.Description.Filter,
                                        AddressU      = (SharpDX.Direct3D12.TextureAddressMode)item.ImmutableSampler.Description.AddressU,
                                        AddressV      = (SharpDX.Direct3D12.TextureAddressMode)item.ImmutableSampler.Description.AddressV,
                                        AddressW      = (SharpDX.Direct3D12.TextureAddressMode)item.ImmutableSampler.Description.AddressW,
                                        MinLOD        = item.ImmutableSampler.Description.MinMipLevel,
                                        MaxLOD        = item.ImmutableSampler.Description.MaxMipLevel,
                                        MipLODBias    = item.ImmutableSampler.Description.MipMapLevelOfDetailBias,
                                        MaxAnisotropy = item.ImmutableSampler.Description.MaxAnisotropy,
                                    });
                                }
                                else
                                {
                                    // Add descriptor range
                                    descriptorRanges.Add(new DescriptorRange(DescriptorRangeType.Sampler, item.ArraySize, binding.SlotStart, 0, descriptorSamplerOffset));
                                }
                            }
                            else
                            {
                                DescriptorRangeType descriptorRangeType;
                                switch (binding.Param.Class)
                                {
                                case EffectParameterClass.ConstantBuffer:
                                    descriptorRangeType = DescriptorRangeType.ConstantBufferView;
                                    break;

                                case EffectParameterClass.ShaderResourceView:
                                    descriptorRangeType = DescriptorRangeType.ShaderResourceView;
                                    break;

                                case EffectParameterClass.UnorderedAccessView:
                                    descriptorRangeType = DescriptorRangeType.UnorderedAccessView;
                                    break;

                                default:
                                    throw new NotImplementedException();
                                }

                                // Add descriptor range
                                descriptorRanges.Add(new DescriptorRange(descriptorRangeType, item.ArraySize, binding.SlotStart, 0, descriptorSrvOffset));
                            }
                        }

                        // Move to next element (mirror what is done in DescriptorSetLayout)
                        if (isSampler)
                        {
                            if (item.ImmutableSampler == null)
                            {
                                descriptorSamplerOffset += item.ArraySize;
                            }
                        }
                        else
                        {
                            descriptorSrvOffset += item.ArraySize;
                        }
                    }
                    if (srvDescriptorRangesVS.Count > 0)
                    {
                        rootSignatureParameters.Add(new RootParameter(ShaderVisibility.Vertex, srvDescriptorRangesVS.ToArray()));
                        SrvBindCounts[layoutIndex]++;
                    }
                    if (srvDescriptorRangesPS.Count > 0)
                    {
                        rootSignatureParameters.Add(new RootParameter(ShaderVisibility.Pixel, srvDescriptorRangesPS.ToArray()));
                        SrvBindCounts[layoutIndex]++;
                    }
                    if (samplerDescriptorRangesVS.Count > 0)
                    {
                        rootSignatureParameters.Add(new RootParameter(ShaderVisibility.Vertex, samplerDescriptorRangesVS.ToArray()));
                        SamplerBindCounts[layoutIndex]++;
                    }
                    if (samplerDescriptorRangesPS.Count > 0)
                    {
                        rootSignatureParameters.Add(new RootParameter(ShaderVisibility.Pixel, samplerDescriptorRangesPS.ToArray()));
                        SamplerBindCounts[layoutIndex]++;
                    }
                }
                var rootSignatureDesc = new RootSignatureDescription(RootSignatureFlags.AllowInputAssemblerInputLayout, rootSignatureParameters.ToArray(), immutableSamplers.ToArray());

                var rootSignature = NativeDevice.CreateRootSignature(0, rootSignatureDesc.Serialize());

                var inputElements = new InputElement[pipelineStateDescription.InputElements.Length];
                for (int i = 0; i < inputElements.Length; ++i)
                {
                    var inputElement = pipelineStateDescription.InputElements[i];
                    inputElements[i] = new InputElement
                    {
                        Format            = (SharpDX.DXGI.Format)inputElement.Format,
                        AlignedByteOffset = inputElement.AlignedByteOffset,
                        SemanticName      = inputElement.SemanticName,
                        SemanticIndex     = inputElement.SemanticIndex,
                        Slot                 = inputElement.InputSlot,
                        Classification       = (SharpDX.Direct3D12.InputClassification)inputElement.InputSlotClass,
                        InstanceDataStepRate = inputElement.InstanceDataStepRate,
                    };
                }

                PrimitiveTopologyType primitiveTopologyType;
                switch (pipelineStateDescription.PrimitiveType)
                {
                case PrimitiveType.Undefined:
                    throw new ArgumentOutOfRangeException();

                case PrimitiveType.PointList:
                    primitiveTopologyType = PrimitiveTopologyType.Point;
                    break;

                case PrimitiveType.LineList:
                case PrimitiveType.LineStrip:
                case PrimitiveType.LineListWithAdjacency:
                case PrimitiveType.LineStripWithAdjacency:
                    primitiveTopologyType = PrimitiveTopologyType.Line;
                    break;

                case PrimitiveType.TriangleList:
                case PrimitiveType.TriangleStrip:
                case PrimitiveType.TriangleListWithAdjacency:
                case PrimitiveType.TriangleStripWithAdjacency:
                    primitiveTopologyType = PrimitiveTopologyType.Triangle;
                    break;

                default:
                    if (pipelineStateDescription.PrimitiveType >= PrimitiveType.PatchList && pipelineStateDescription.PrimitiveType < PrimitiveType.PatchList + 32)
                    {
                        primitiveTopologyType = PrimitiveTopologyType.Patch;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("pipelineStateDescription.PrimitiveType");
                    }
                    break;
                }

                var nativePipelineStateDescription = new GraphicsPipelineStateDescription
                {
                    InputLayout        = new InputLayoutDescription(inputElements),
                    RootSignature      = rootSignature,
                    RasterizerState    = CreateRasterizerState(pipelineStateDescription.RasterizerState),
                    BlendState         = CreateBlendState(pipelineStateDescription.BlendState),
                    SampleMask         = (int)pipelineStateDescription.SampleMask,
                    DepthStencilFormat = (SharpDX.DXGI.Format)pipelineStateDescription.Output.DepthStencilFormat,
                    DepthStencilState  = CreateDepthStencilState(pipelineStateDescription.DepthStencilState),
                    RenderTargetCount  = pipelineStateDescription.Output.RenderTargetCount,
                    // TODO D3D12 hardcoded
                    StreamOutput          = new StreamOutputDescription(),
                    PrimitiveTopologyType = primitiveTopologyType,
                    // TODO D3D12 hardcoded
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                };

                fixed(PixelFormat *renderTargetFormats = &pipelineStateDescription.Output.RenderTargetFormat0)
                {
                    for (int i = 0; i < pipelineStateDescription.Output.RenderTargetCount; ++i)
                    {
                        nativePipelineStateDescription.RenderTargetFormats[i] = (SharpDX.DXGI.Format)renderTargetFormats[i];
                    }
                }

                foreach (var stage in pipelineStateDescription.EffectBytecode.Stages)
                {
                    switch (stage.Stage)
                    {
                    case ShaderStage.Vertex:
                        nativePipelineStateDescription.VertexShader = stage.Data;
                        break;

                    case ShaderStage.Hull:
                        nativePipelineStateDescription.HullShader = stage.Data;
                        break;

                    case ShaderStage.Domain:
                        nativePipelineStateDescription.DomainShader = stage.Data;
                        break;

                    case ShaderStage.Geometry:
                        nativePipelineStateDescription.GeometryShader = stage.Data;
                        break;

                    case ShaderStage.Pixel:
                        nativePipelineStateDescription.PixelShader = stage.Data;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                CompiledState     = NativeDevice.CreateGraphicsPipelineState(nativePipelineStateDescription);
                RootSignature     = rootSignature;
                PrimitiveTopology = (PrimitiveTopology)pipelineStateDescription.PrimitiveType;
            }
        }
 public PipelineStateDescriptionWithHash(PipelineStateDescription state)
 {
     Hash  = state.GetHashCode();
     State = state;
 }
Example #6
0
 internal PipelineState(GraphicsDevice graphicsDevice, PipelineStateDescription pipelineStateDescription) : base(graphicsDevice)
 {
     Description = pipelineStateDescription.Clone();
     Recreate();
 }
Example #7
0
        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);
        }
Example #8
0
        private unsafe void CreateRenderPass(PipelineStateDescription pipelineStateDescription)
        {
            bool hasDepthStencilAttachment = pipelineStateDescription.Output.DepthStencilFormat != PixelFormat.None;

            var renderTargetCount = pipelineStateDescription.Output.RenderTargetCount;

            var attachmentCount = renderTargetCount;

            if (hasDepthStencilAttachment)
            {
                attachmentCount++;
            }

            var attachments = new AttachmentDescription[attachmentCount];
            var colorAttachmentReferences = new AttachmentReference[renderTargetCount];

            fixed(PixelFormat *renderTargetFormat = &pipelineStateDescription.Output.RenderTargetFormat0)
            fixed(BlendStateRenderTargetDescription * blendDescription = &pipelineStateDescription.BlendState.RenderTarget0)
            {
                for (int i = 0; i < renderTargetCount; i++)
                {
                    var currentBlendDesc = pipelineStateDescription.BlendState.IndependentBlendEnable ? (blendDescription + i) : blendDescription;

                    attachments[i] = new AttachmentDescription
                    {
                        Format                = VulkanConvertExtensions.ConvertPixelFormat(*(renderTargetFormat + i)),
                        Samples               = SampleCountFlags.Sample1,
                        LoadOperation         = currentBlendDesc->BlendEnable ? AttachmentLoadOperation.Load : AttachmentLoadOperation.DontCare, // TODO VULKAN: Only if any destination blend?
                        StoreOperation        = AttachmentStoreOperation.Store,
                        StencilLoadOperation  = AttachmentLoadOperation.DontCare,
                        StencilStoreOperation = AttachmentStoreOperation.DontCare,
                        InitialLayout         = ImageLayout.ColorAttachmentOptimal,
                        FinalLayout           = ImageLayout.ColorAttachmentOptimal,
                    };

                    colorAttachmentReferences[i] = new AttachmentReference
                    {
                        Attachment = (uint)i,
                        Layout     = ImageLayout.ColorAttachmentOptimal,
                    };
                }
            }

            if (hasDepthStencilAttachment)
            {
                attachments[attachmentCount - 1] = new AttachmentDescription
                {
                    Format                = Texture.GetFallbackDepthStencilFormat(GraphicsDevice, VulkanConvertExtensions.ConvertPixelFormat(pipelineStateDescription.Output.DepthStencilFormat)),
                    Samples               = SampleCountFlags.Sample1,
                    LoadOperation         = AttachmentLoadOperation.Load,     // TODO VULKAN: Only if depth read enabled?
                    StoreOperation        = AttachmentStoreOperation.Store,   // TODO VULKAN: Only if depth write enabled?
                    StencilLoadOperation  = AttachmentLoadOperation.DontCare, // TODO VULKAN: Handle stencil
                    StencilStoreOperation = AttachmentStoreOperation.DontCare,
                    InitialLayout         = ImageLayout.DepthStencilAttachmentOptimal,
                    FinalLayout           = ImageLayout.DepthStencilAttachmentOptimal,
                };
            }

            var depthAttachmentReference = new AttachmentReference
            {
                Attachment = (uint)attachments.Length - 1,
                Layout     = ImageLayout.DepthStencilAttachmentOptimal,
            };

            var subpass = new SubpassDescription
            {
                PipelineBindPoint      = PipelineBindPoint.Graphics,
                ColorAttachmentCount   = (uint)renderTargetCount,
                ColorAttachments       = colorAttachmentReferences.Length > 0 ? new IntPtr(Interop.Fixed(colorAttachmentReferences)) : IntPtr.Zero,
                DepthStencilAttachment = hasDepthStencilAttachment ? new IntPtr(&depthAttachmentReference) : IntPtr.Zero,
            };

            var renderPassCreateInfo = new RenderPassCreateInfo
            {
                StructureType   = StructureType.RenderPassCreateInfo,
                AttachmentCount = (uint)attachmentCount,
                Attachments     = attachments.Length > 0 ? new IntPtr(Interop.Fixed(attachments)) : IntPtr.Zero,
                SubpassCount    = 1,
                Subpasses       = new IntPtr(&subpass)
            };

            NativeRenderPass = GraphicsDevice.NativeDevice.CreateRenderPass(ref renderPassCreateInfo);
        }
Example #9
0
 public static PipelineState New(GraphicsDevice graphicsDevice, ref PipelineStateDescription pipelineStateDescription)
 {
     return(new PipelineState(graphicsDevice, pipelineStateDescription));
 }