aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/PipelineConverter.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/PipelineConverter.cs278
1 files changed, 278 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
new file mode 100644
index 00000000..ff194d71
--- /dev/null
+++ b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
@@ -0,0 +1,278 @@
+using Ryujinx.Graphics.GAL;
+using Silk.NET.Vulkan;
+using System;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ static class PipelineConverter
+ {
+ public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
+ {
+ const int MaxAttachments = Constants.MaxRenderTargets + 1;
+
+ AttachmentDescription[] attachmentDescs = null;
+
+ var subpass = new SubpassDescription()
+ {
+ PipelineBindPoint = PipelineBindPoint.Graphics
+ };
+
+ AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
+
+ Span<int> attachmentIndices = stackalloc int[MaxAttachments];
+ Span<Silk.NET.Vulkan.Format> attachmentFormats = stackalloc Silk.NET.Vulkan.Format[MaxAttachments];
+
+ int attachmentCount = 0;
+ int colorCount = 0;
+ int maxColorAttachmentIndex = 0;
+
+ for (int i = 0; i < state.AttachmentEnable.Length; i++)
+ {
+ if (state.AttachmentEnable[i])
+ {
+ maxColorAttachmentIndex = i;
+
+ attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]);
+
+ attachmentIndices[attachmentCount++] = i;
+ colorCount++;
+ }
+ }
+
+ if (state.DepthStencilEnable)
+ {
+ attachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat);
+ }
+
+ if (attachmentCount != 0)
+ {
+ attachmentDescs = new AttachmentDescription[attachmentCount];
+
+ for (int i = 0; i < attachmentCount; i++)
+ {
+ int bindIndex = attachmentIndices[i];
+
+ attachmentDescs[i] = new AttachmentDescription(
+ 0,
+ attachmentFormats[i],
+ TextureStorage.ConvertToSampleCountFlags((uint)state.SamplesCount),
+ AttachmentLoadOp.Load,
+ AttachmentStoreOp.Store,
+ AttachmentLoadOp.Load,
+ AttachmentStoreOp.Store,
+ ImageLayout.General,
+ ImageLayout.General);
+ }
+
+ int colorAttachmentsCount = colorCount;
+
+ if (colorAttachmentsCount > MaxAttachments - 1)
+ {
+ colorAttachmentsCount = MaxAttachments - 1;
+ }
+
+ if (colorAttachmentsCount != 0)
+ {
+ int maxAttachmentIndex = Constants.MaxRenderTargets - 1;
+ subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1;
+ subpass.PColorAttachments = &attachmentReferences[0];
+
+ // Fill with VK_ATTACHMENT_UNUSED to cover any gaps.
+ for (int i = 0; i <= maxAttachmentIndex; i++)
+ {
+ subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined);
+ }
+
+ for (int i = 0; i < colorAttachmentsCount; i++)
+ {
+ int bindIndex = attachmentIndices[i];
+
+ subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General);
+ }
+ }
+
+ if (state.DepthStencilEnable)
+ {
+ uint dsIndex = (uint)attachmentCount - 1;
+
+ subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1];
+ *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General);
+ }
+ }
+
+ var subpassDependency = new SubpassDependency(
+ 0,
+ 0,
+ PipelineStageFlags.PipelineStageAllGraphicsBit,
+ PipelineStageFlags.PipelineStageAllGraphicsBit,
+ AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
+ AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
+ 0);
+
+ fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs)
+ {
+ var renderPassCreateInfo = new RenderPassCreateInfo()
+ {
+ SType = StructureType.RenderPassCreateInfo,
+ PAttachments = pAttachmentDescs,
+ AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0,
+ PSubpasses = &subpass,
+ SubpassCount = 1,
+ PDependencies = &subpassDependency,
+ DependencyCount = 1
+ };
+
+ gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
+
+ return new DisposableRenderPass(gd.Api, device, renderPass);
+ }
+ }
+
+ public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd)
+ {
+ PipelineState pipeline = new PipelineState();
+ pipeline.Initialize();
+
+ // It is assumed that Dynamic State is enabled when this conversion is used.
+
+ pipeline.BlendConstantA = state.BlendDescriptors[0].BlendConstant.Alpha;
+ pipeline.BlendConstantB = state.BlendDescriptors[0].BlendConstant.Blue;
+ pipeline.BlendConstantG = state.BlendDescriptors[0].BlendConstant.Green;
+ pipeline.BlendConstantR = state.BlendDescriptors[0].BlendConstant.Red;
+
+ pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone;
+
+ pipeline.DepthBoundsTestEnable = false; // Not implemented.
+
+ pipeline.DepthClampEnable = state.DepthClampEnable;
+
+ pipeline.DepthTestEnable = state.DepthTest.TestEnable;
+ pipeline.DepthWriteEnable = state.DepthTest.WriteEnable;
+ pipeline.DepthCompareOp = state.DepthTest.Func.Convert();
+
+ pipeline.FrontFace = state.FrontFace.Convert();
+
+ pipeline.HasDepthStencil = state.DepthStencilEnable;
+ pipeline.LineWidth = state.LineWidth;
+ pipeline.LogicOpEnable = state.LogicOpEnable;
+ pipeline.LogicOp = state.LogicOp.Convert();
+
+ pipeline.MinDepthBounds = 0f; // Not implemented.
+ pipeline.MaxDepthBounds = 0f; // Not implemented.
+
+ pipeline.PatchControlPoints = state.PatchControlPoints;
+ pipeline.PolygonMode = Silk.NET.Vulkan.PolygonMode.Fill; // Not implemented.
+ pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
+ pipeline.RasterizerDiscardEnable = state.RasterizerDiscard;
+ pipeline.SamplesCount = (uint)state.SamplesCount;
+
+ if (gd.Capabilities.SupportsMultiView)
+ {
+ pipeline.ScissorsCount = Constants.MaxViewports;
+ pipeline.ViewportsCount = Constants.MaxViewports;
+ }
+ else
+ {
+ pipeline.ScissorsCount = 1;
+ pipeline.ViewportsCount = 1;
+ }
+
+ pipeline.DepthBiasEnable = state.BiasEnable != 0;
+
+ // Stencil masks and ref are dynamic, so are 0 in the Vulkan pipeline.
+
+ pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert();
+ pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
+ pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert();
+ pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert();
+ pipeline.StencilFrontCompareMask = 0;
+ pipeline.StencilFrontWriteMask = 0;
+ pipeline.StencilFrontReference = 0;
+
+ pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert();
+ pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
+ pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
+ pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
+ pipeline.StencilBackCompareMask = 0;
+ pipeline.StencilBackWriteMask = 0;
+ pipeline.StencilBackReference = 0;
+
+ pipeline.StencilTestEnable = state.StencilTest.TestEnable;
+
+ pipeline.Topology = state.Topology.Convert();
+
+ int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
+
+ for (int i = 0; i < vaCount; i++)
+ {
+ var attribute = state.VertexAttribs[i];
+ var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
+
+ pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
+ (uint)i,
+ (uint)bufferIndex,
+ FormatTable.GetFormat(attribute.Format),
+ (uint)attribute.Offset);
+ }
+
+ int descriptorIndex = 1;
+ pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
+
+ int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
+
+ for (int i = 0; i < vbCount; i++)
+ {
+ var vertexBuffer = state.VertexBuffers[i];
+
+ if (vertexBuffer.Enable)
+ {
+ var inputRate = vertexBuffer.Divisor != 0 ? VertexInputRate.Instance : VertexInputRate.Vertex;
+
+ // TODO: Support divisor > 1
+ pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
+ (uint)i + 1,
+ (uint)vertexBuffer.Stride,
+ inputRate);
+ }
+ }
+
+ pipeline.VertexBindingDescriptionsCount = (uint)descriptorIndex;
+
+ // NOTE: Viewports, Scissors are dynamic.
+
+ for (int i = 0; i < 8; i++)
+ {
+ var blend = state.BlendDescriptors[i];
+
+ pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
+ blend.Enable,
+ blend.ColorSrcFactor.Convert(),
+ blend.ColorDstFactor.Convert(),
+ blend.ColorOp.Convert(),
+ blend.AlphaSrcFactor.Convert(),
+ blend.AlphaDstFactor.Convert(),
+ blend.AlphaOp.Convert(),
+ (ColorComponentFlags)state.ColorWriteMask[i]);
+ }
+
+ int maxAttachmentIndex = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (state.AttachmentEnable[i])
+ {
+ pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]);
+ }
+ }
+
+ if (state.DepthStencilEnable)
+ {
+ pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat);
+ }
+
+ pipeline.ColorBlendAttachmentStateCount = 8;
+ pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
+
+ return pipeline;
+ }
+ }
+}