SupportBufferUpdater.cs
1 using Ryujinx.Graphics.GAL; 2 using Ryujinx.Graphics.Shader; 3 using System; 4 using System.Runtime.CompilerServices; 5 using System.Runtime.InteropServices; 6 7 namespace Ryujinx.Graphics.Gpu.Memory 8 { 9 /// <summary> 10 /// Support buffer data updater. 11 /// </summary> 12 class SupportBufferUpdater : BufferUpdater 13 { 14 private SupportBuffer _data; 15 16 /// <summary> 17 /// Creates a new instance of the support buffer updater. 18 /// </summary> 19 /// <param name="renderer">Renderer that the support buffer will be used with</param> 20 public SupportBufferUpdater(IRenderer renderer) : base(renderer) 21 { 22 var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f }; 23 _data.RenderScale.AsSpan().Fill(defaultScale); 24 DirtyRenderScale(0, SupportBuffer.RenderScaleMaxCount); 25 } 26 27 /// <summary> 28 /// Marks the fragment render scale count as being modified. 29 /// </summary> 30 private void DirtyFragmentRenderScaleCount() 31 { 32 MarkDirty(SupportBuffer.FragmentRenderScaleCountOffset, sizeof(int)); 33 } 34 35 /// <summary> 36 /// Marks data of a given type as being modified. 37 /// </summary> 38 /// <typeparam name="T">Type of the data</typeparam> 39 /// <param name="baseOffset">Base offset of the data in bytes</param> 40 /// <param name="offset">Index of the data, in elements</param> 41 /// <param name="count">Number of elements</param> 42 private void DirtyGenericField<T>(int baseOffset, int offset, int count) where T : unmanaged 43 { 44 int elemSize = Unsafe.SizeOf<T>(); 45 46 MarkDirty(baseOffset + offset * elemSize, count * elemSize); 47 } 48 49 /// <summary> 50 /// Marks render scales as being modified. 51 /// </summary> 52 /// <param name="offset">Index of the first scale that was modified</param> 53 /// <param name="count">Number of modified scales</param> 54 private void DirtyRenderScale(int offset, int count) 55 { 56 DirtyGenericField<Vector4<float>>(SupportBuffer.GraphicsRenderScaleOffset, offset, count); 57 } 58 59 /// <summary> 60 /// Marks render target BGRA format state as modified. 61 /// </summary> 62 /// <param name="offset">Index of the first render target that had its BGRA format modified</param> 63 /// <param name="count">Number of render targets</param> 64 private void DirtyFragmentIsBgra(int offset, int count) 65 { 66 DirtyGenericField<Vector4<int>>(SupportBuffer.FragmentIsBgraOffset, offset, count); 67 } 68 69 /// <summary> 70 /// Updates the inverse viewport vector. 71 /// </summary> 72 /// <param name="data">Inverse viewport vector</param> 73 private void UpdateViewportInverse(Vector4<float> data) 74 { 75 _data.ViewportInverse = data; 76 77 MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize); 78 } 79 80 /// <summary> 81 /// Updates the viewport size vector. 82 /// </summary> 83 /// <param name="data">Viewport size vector</param> 84 private void UpdateViewportSize(Vector4<float> data) 85 { 86 _data.ViewportSize = data; 87 88 MarkDirty(SupportBuffer.ViewportSizeOffset, SupportBuffer.FieldSize); 89 } 90 91 /// <summary> 92 /// Sets the scale of all output render targets (they should all have the same scale). 93 /// </summary> 94 /// <param name="scale">Scale value</param> 95 public void SetRenderTargetScale(float scale) 96 { 97 _data.RenderScale[0].X = scale; 98 DirtyRenderScale(0, 1); // Just the first element. 99 } 100 101 /// <summary> 102 /// Updates the render scales for shader input textures or images. 103 /// </summary> 104 /// <param name="index">Index of the scale</param> 105 /// <param name="scale">Scale value</param> 106 public void UpdateRenderScale(int index, float scale) 107 { 108 if (_data.RenderScale[1 + index].X != scale) 109 { 110 _data.RenderScale[1 + index].X = scale; 111 DirtyRenderScale(1 + index, 1); 112 } 113 } 114 115 /// <summary> 116 /// Updates the render scales for shader input textures or images. 117 /// </summary> 118 /// <param name="totalCount">Total number of scales across all stages</param> 119 /// <param name="fragmentCount">Total number of scales on the fragment shader stage</param> 120 public void UpdateRenderScaleFragmentCount(int totalCount, int fragmentCount) 121 { 122 // Only update fragment count if there are scales after it for the vertex stage. 123 if (fragmentCount != totalCount && fragmentCount != _data.FragmentRenderScaleCount.X) 124 { 125 _data.FragmentRenderScaleCount.X = fragmentCount; 126 DirtyFragmentRenderScaleCount(); 127 } 128 } 129 130 /// <summary> 131 /// Sets whether the format of a given render target is a BGRA format. 132 /// </summary> 133 /// <param name="index">Render target index</param> 134 /// <param name="isBgra">True if the format is BGRA< false otherwise</param> 135 public void SetRenderTargetIsBgra(int index, bool isBgra) 136 { 137 bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra; 138 139 if (isBgraChanged) 140 { 141 _data.FragmentIsBgra[index].X = isBgra ? 1 : 0; 142 DirtyFragmentIsBgra(index, 1); 143 } 144 } 145 146 /// <summary> 147 /// Sets whether a viewport has transform disabled. 148 /// </summary> 149 /// <param name="viewportWidth">Value used as viewport width</param> 150 /// <param name="viewportHeight">Value used as viewport height</param> 151 /// <param name="scale">Render target scale</param> 152 /// <param name="disableTransform">True if transform is disabled, false otherwise</param> 153 public void SetViewportTransformDisable(float viewportWidth, float viewportHeight, float scale, bool disableTransform) 154 { 155 float disableTransformF = disableTransform ? 1.0f : 0.0f; 156 if (_data.ViewportInverse.W != disableTransformF || disableTransform) 157 { 158 UpdateViewportInverse(new Vector4<float> 159 { 160 X = scale * 2f / viewportWidth, 161 Y = scale * 2f / viewportHeight, 162 Z = 1, 163 W = disableTransformF, 164 }); 165 } 166 } 167 168 /// <summary> 169 /// Sets the viewport size, used to invert the fragment coordinates Y value. 170 /// </summary> 171 /// <param name="viewportWidth">Value used as viewport width</param> 172 /// <param name="viewportHeight">Value used as viewport height</param> 173 public void SetViewportSize(float viewportWidth, float viewportHeight) 174 { 175 if (_data.ViewportSize.X != viewportWidth || _data.ViewportSize.Y != viewportHeight) 176 { 177 UpdateViewportSize(new Vector4<float> 178 { 179 X = viewportWidth, 180 Y = viewportHeight, 181 Z = 1, 182 W = 0 183 }); 184 } 185 } 186 187 /// <summary> 188 /// Sets offset for the misaligned portion of a transform feedback buffer, and the buffer size, for transform feedback emulation. 189 /// </summary> 190 /// <param name="bufferIndex">Index of the transform feedback buffer</param> 191 /// <param name="offset">Misaligned offset of the buffer</param> 192 public void SetTfeOffset(int bufferIndex, int offset) 193 { 194 ref int currentOffset = ref GetElementRef(ref _data.TfeOffset, bufferIndex); 195 196 if (currentOffset != offset) 197 { 198 currentOffset = offset; 199 MarkDirty(SupportBuffer.TfeOffsetOffset + bufferIndex * sizeof(int), sizeof(int)); 200 } 201 } 202 203 /// <summary> 204 /// Sets the vertex count used for transform feedback emulation with instanced draws. 205 /// </summary> 206 /// <param name="vertexCount">Vertex count of the instanced draw</param> 207 public void SetTfeVertexCount(int vertexCount) 208 { 209 if (_data.TfeVertexCount.X != vertexCount) 210 { 211 _data.TfeVertexCount.X = vertexCount; 212 MarkDirty(SupportBuffer.TfeVertexCountOffset, sizeof(int)); 213 } 214 } 215 216 /// <summary> 217 /// Submits all pending buffer updates to the GPU. 218 /// </summary> 219 public void Commit() 220 { 221 Commit(MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref _data, 1)), SupportBuffer.Binding); 222 } 223 } 224 }