Framebuffer.cs
1 using OpenTK.Graphics.OpenGL; 2 using Ryujinx.Graphics.GAL; 3 using Ryujinx.Graphics.OpenGL.Image; 4 using System; 5 using System.Runtime.CompilerServices; 6 7 namespace Ryujinx.Graphics.OpenGL 8 { 9 class Framebuffer : IDisposable 10 { 11 public int Handle { get; private set; } 12 private int _clearFbHandle; 13 private bool _clearFbInitialized; 14 15 private FramebufferAttachment _lastDsAttachment; 16 17 private readonly TextureView[] _colors; 18 private TextureView _depthStencil; 19 20 private int _colorsCount; 21 private bool _dualSourceBlend; 22 23 public Framebuffer() 24 { 25 Handle = GL.GenFramebuffer(); 26 _clearFbHandle = GL.GenFramebuffer(); 27 28 _colors = new TextureView[8]; 29 } 30 31 public int Bind() 32 { 33 GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle); 34 return Handle; 35 } 36 37 [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 public void AttachColor(int index, TextureView color) 39 { 40 if (_colors[index] == color) 41 { 42 return; 43 } 44 45 FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index; 46 47 GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.Handle ?? 0, 0); 48 49 _colors[index] = color; 50 } 51 52 public void AttachDepthStencil(TextureView depthStencil) 53 { 54 // Detach the last depth/stencil buffer if there is any. 55 if (_lastDsAttachment != 0) 56 { 57 GL.FramebufferTexture(FramebufferTarget.Framebuffer, _lastDsAttachment, 0, 0); 58 } 59 60 if (depthStencil != null) 61 { 62 FramebufferAttachment attachment = GetAttachment(depthStencil.Format); 63 64 GL.FramebufferTexture( 65 FramebufferTarget.Framebuffer, 66 attachment, 67 depthStencil.Handle, 68 0); 69 70 _lastDsAttachment = attachment; 71 } 72 else 73 { 74 _lastDsAttachment = 0; 75 } 76 77 _depthStencil = depthStencil; 78 } 79 80 public void SetDualSourceBlend(bool enable) 81 { 82 bool oldEnable = _dualSourceBlend; 83 84 _dualSourceBlend = enable; 85 86 // When dual source blend is used, 87 // we can only have one draw buffer. 88 if (enable) 89 { 90 GL.DrawBuffer(DrawBufferMode.ColorAttachment0); 91 } 92 else if (oldEnable) 93 { 94 SetDrawBuffersImpl(_colorsCount); 95 } 96 } 97 98 public void SetDrawBuffers(int colorsCount) 99 { 100 if (_colorsCount != colorsCount && !_dualSourceBlend) 101 { 102 SetDrawBuffersImpl(colorsCount); 103 } 104 105 _colorsCount = colorsCount; 106 } 107 108 private static void SetDrawBuffersImpl(int colorsCount) 109 { 110 DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[colorsCount]; 111 112 for (int index = 0; index < colorsCount; index++) 113 { 114 drawBuffers[index] = DrawBuffersEnum.ColorAttachment0 + index; 115 } 116 117 GL.DrawBuffers(colorsCount, drawBuffers); 118 } 119 120 private static FramebufferAttachment GetAttachment(Format format) 121 { 122 if (FormatTable.IsPackedDepthStencil(format)) 123 { 124 return FramebufferAttachment.DepthStencilAttachment; 125 } 126 else if (FormatTable.IsDepthOnly(format)) 127 { 128 return FramebufferAttachment.DepthAttachment; 129 } 130 else 131 { 132 return FramebufferAttachment.StencilAttachment; 133 } 134 } 135 136 public int GetColorLayerCount(int index) 137 { 138 return _colors[index]?.Info.GetDepthOrLayers() ?? 0; 139 } 140 141 public int GetDepthStencilLayerCount() 142 { 143 return _depthStencil?.Info.GetDepthOrLayers() ?? 0; 144 } 145 146 public void AttachColorLayerForClear(int index, int layer) 147 { 148 TextureView color = _colors[index]; 149 150 if (!IsLayered(color)) 151 { 152 return; 153 } 154 155 BindClearFb(); 156 GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, color.Handle, 0, layer); 157 } 158 159 public void DetachColorLayerForClear(int index) 160 { 161 TextureView color = _colors[index]; 162 163 if (!IsLayered(color)) 164 { 165 return; 166 } 167 168 GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, 0, 0); 169 Bind(); 170 } 171 172 public void AttachDepthStencilLayerForClear(int layer) 173 { 174 TextureView depthStencil = _depthStencil; 175 176 if (!IsLayered(depthStencil)) 177 { 178 return; 179 } 180 181 BindClearFb(); 182 GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), depthStencil.Handle, 0, layer); 183 } 184 185 public void DetachDepthStencilLayerForClear() 186 { 187 TextureView depthStencil = _depthStencil; 188 189 if (!IsLayered(depthStencil)) 190 { 191 return; 192 } 193 194 GL.FramebufferTexture(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), 0, 0); 195 Bind(); 196 } 197 198 private void BindClearFb() 199 { 200 GL.BindFramebuffer(FramebufferTarget.Framebuffer, _clearFbHandle); 201 202 if (!_clearFbInitialized) 203 { 204 SetDrawBuffersImpl(Constants.MaxRenderTargets); 205 _clearFbInitialized = true; 206 } 207 } 208 209 private static bool IsLayered(TextureView view) 210 { 211 return view != null && 212 view.Target != Target.Texture1D && 213 view.Target != Target.Texture2D && 214 view.Target != Target.Texture2DMultisample && 215 view.Target != Target.TextureBuffer; 216 } 217 218 public void Dispose() 219 { 220 if (Handle != 0) 221 { 222 GL.DeleteFramebuffer(Handle); 223 224 Handle = 0; 225 } 226 227 if (_clearFbHandle != 0) 228 { 229 GL.DeleteFramebuffer(_clearFbHandle); 230 231 _clearFbHandle = 0; 232 } 233 } 234 } 235 }