using Ryujinx.Common.Memory; using Silk.NET.Vulkan; namespace Ryujinx.Graphics.Vulkan { struct PipelineDynamicState { private float _depthBiasSlopeFactor; private float _depthBiasConstantFactor; private float _depthBiasClamp; public int ScissorsCount; private Array16 _scissors; private uint _backCompareMask; private uint _backWriteMask; private uint _backReference; private uint _frontCompareMask; private uint _frontWriteMask; private uint _frontReference; private Array4 _blendConstants; public uint ViewportsCount; public Array16 Viewports; private enum DirtyFlags { None = 0, Blend = 1 << 0, DepthBias = 1 << 1, Scissor = 1 << 2, Stencil = 1 << 3, Viewport = 1 << 4, All = Blend | DepthBias | Scissor | Stencil | Viewport } private DirtyFlags _dirty; public void SetBlendConstants(float r, float g, float b, float a) { _blendConstants[0] = r; _blendConstants[1] = g; _blendConstants[2] = b; _blendConstants[3] = a; _dirty |= DirtyFlags.Blend; } public void SetDepthBias(float slopeFactor, float constantFactor, float clamp) { _depthBiasSlopeFactor = slopeFactor; _depthBiasConstantFactor = constantFactor; _depthBiasClamp = clamp; _dirty |= DirtyFlags.DepthBias; } public void SetScissor(int index, Rect2D scissor) { _scissors[index] = scissor; _dirty |= DirtyFlags.Scissor; } public void SetStencilMasks( uint backCompareMask, uint backWriteMask, uint backReference, uint frontCompareMask, uint frontWriteMask, uint frontReference) { _backCompareMask = backCompareMask; _backWriteMask = backWriteMask; _backReference = backReference; _frontCompareMask = frontCompareMask; _frontWriteMask = frontWriteMask; _frontReference = frontReference; _dirty |= DirtyFlags.Stencil; } public void SetViewport(int index, Viewport viewport) { Viewports[index] = viewport; _dirty |= DirtyFlags.Viewport; } public void SetViewports(ref Array16 viewports, uint viewportsCount) { Viewports = viewports; ViewportsCount = viewportsCount; if (ViewportsCount != 0) { _dirty |= DirtyFlags.Viewport; } } public void ForceAllDirty() { _dirty = DirtyFlags.All; } public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer) { if (_dirty.HasFlag(DirtyFlags.Blend)) { RecordBlend(api, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.DepthBias)) { RecordDepthBias(api, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.Scissor)) { RecordScissor(api, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.Stencil)) { RecordStencilMasks(api, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.Viewport)) { RecordViewport(api, commandBuffer); } _dirty = DirtyFlags.None; } private void RecordBlend(Vk api, CommandBuffer commandBuffer) { api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan()); } private void RecordDepthBias(Vk api, CommandBuffer commandBuffer) { api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor); } private void RecordScissor(Vk api, CommandBuffer commandBuffer) { api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan()); } private void RecordStencilMasks(Vk api, CommandBuffer commandBuffer) { api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask); api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask); api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceBackBit, _backReference); api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontCompareMask); api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontWriteMask); api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference); } private void RecordViewport(Vk api, CommandBuffer commandBuffer) { if (ViewportsCount != 0) { api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan()); } } } }