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); }
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) { }
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; }
internal PipelineState(GraphicsDevice graphicsDevice, PipelineStateDescription pipelineStateDescription) : base(graphicsDevice) { Description = pipelineStateDescription.Clone(); Recreate(); }
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); }
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); }
public static PipelineState New(GraphicsDevice graphicsDevice, ref PipelineStateDescription pipelineStateDescription) { return(new PipelineState(graphicsDevice, pipelineStateDescription)); }