/ src / Ryujinx.Graphics.Vulkan / PipelineDynamicState.cs
PipelineDynamicState.cs
  1  using Ryujinx.Common.Memory;
  2  using Silk.NET.Vulkan;
  3  using Silk.NET.Vulkan.Extensions.EXT;
  4  
  5  namespace Ryujinx.Graphics.Vulkan
  6  {
  7      struct PipelineDynamicState
  8      {
  9          private float _depthBiasSlopeFactor;
 10          private float _depthBiasConstantFactor;
 11          private float _depthBiasClamp;
 12  
 13          public int ScissorsCount;
 14          private Array16<Rect2D> _scissors;
 15  
 16          private uint _backCompareMask;
 17          private uint _backWriteMask;
 18          private uint _backReference;
 19          private uint _frontCompareMask;
 20          private uint _frontWriteMask;
 21          private uint _frontReference;
 22  
 23          private Array4<float> _blendConstants;
 24  
 25          private FeedbackLoopAspects _feedbackLoopAspects;
 26  
 27          public uint ViewportsCount;
 28          public Array16<Viewport> Viewports;
 29  
 30          private enum DirtyFlags
 31          {
 32              None = 0,
 33              Blend = 1 << 0,
 34              DepthBias = 1 << 1,
 35              Scissor = 1 << 2,
 36              Stencil = 1 << 3,
 37              Viewport = 1 << 4,
 38              FeedbackLoop = 1 << 5,
 39              All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
 40          }
 41  
 42          private DirtyFlags _dirty;
 43  
 44          public void SetBlendConstants(float r, float g, float b, float a)
 45          {
 46              _blendConstants[0] = r;
 47              _blendConstants[1] = g;
 48              _blendConstants[2] = b;
 49              _blendConstants[3] = a;
 50  
 51              _dirty |= DirtyFlags.Blend;
 52          }
 53  
 54          public void SetDepthBias(float slopeFactor, float constantFactor, float clamp)
 55          {
 56              _depthBiasSlopeFactor = slopeFactor;
 57              _depthBiasConstantFactor = constantFactor;
 58              _depthBiasClamp = clamp;
 59  
 60              _dirty |= DirtyFlags.DepthBias;
 61          }
 62  
 63          public void SetScissor(int index, Rect2D scissor)
 64          {
 65              _scissors[index] = scissor;
 66  
 67              _dirty |= DirtyFlags.Scissor;
 68          }
 69  
 70          public void SetStencilMasks(
 71              uint backCompareMask,
 72              uint backWriteMask,
 73              uint backReference,
 74              uint frontCompareMask,
 75              uint frontWriteMask,
 76              uint frontReference)
 77          {
 78              _backCompareMask = backCompareMask;
 79              _backWriteMask = backWriteMask;
 80              _backReference = backReference;
 81              _frontCompareMask = frontCompareMask;
 82              _frontWriteMask = frontWriteMask;
 83              _frontReference = frontReference;
 84  
 85              _dirty |= DirtyFlags.Stencil;
 86          }
 87  
 88          public void SetViewport(int index, Viewport viewport)
 89          {
 90              Viewports[index] = viewport;
 91  
 92              _dirty |= DirtyFlags.Viewport;
 93          }
 94  
 95          public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
 96          {
 97              Viewports = viewports;
 98              ViewportsCount = viewportsCount;
 99  
100              if (ViewportsCount != 0)
101              {
102                  _dirty |= DirtyFlags.Viewport;
103              }
104          }
105  
106          public void SetFeedbackLoop(FeedbackLoopAspects aspects)
107          {
108              _feedbackLoopAspects = aspects;
109  
110              _dirty |= DirtyFlags.FeedbackLoop;
111          }
112  
113          public void ForceAllDirty()
114          {
115              _dirty = DirtyFlags.All;
116          }
117  
118          public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
119          {
120              Vk api = gd.Api;
121  
122              if (_dirty.HasFlag(DirtyFlags.Blend))
123              {
124                  RecordBlend(api, commandBuffer);
125              }
126  
127              if (_dirty.HasFlag(DirtyFlags.DepthBias))
128              {
129                  RecordDepthBias(api, commandBuffer);
130              }
131  
132              if (_dirty.HasFlag(DirtyFlags.Scissor))
133              {
134                  RecordScissor(api, commandBuffer);
135              }
136  
137              if (_dirty.HasFlag(DirtyFlags.Stencil))
138              {
139                  RecordStencilMasks(api, commandBuffer);
140              }
141  
142              if (_dirty.HasFlag(DirtyFlags.Viewport))
143              {
144                  RecordViewport(api, commandBuffer);
145              }
146  
147              if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
148              {
149                  RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
150              }
151  
152              _dirty = DirtyFlags.None;
153          }
154  
155          private void RecordBlend(Vk api, CommandBuffer commandBuffer)
156          {
157              api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan());
158          }
159  
160          private readonly void RecordDepthBias(Vk api, CommandBuffer commandBuffer)
161          {
162              api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
163          }
164  
165          private void RecordScissor(Vk api, CommandBuffer commandBuffer)
166          {
167              if (ScissorsCount != 0)
168              {
169                  api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
170              }
171          }
172  
173          private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
174          {
175              api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
176              api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
177              api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceBackBit, _backReference);
178              api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontCompareMask);
179              api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontWriteMask);
180              api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
181          }
182  
183          private void RecordViewport(Vk api, CommandBuffer commandBuffer)
184          {
185              if (ViewportsCount != 0)
186              {
187                  api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
188              }
189          }
190  
191          private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
192          {
193              ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
194  
195              if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
196              {
197                  aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
198              }
199  
200              api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
201          }
202      }
203  }