OGLFrameBuffer.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. using OpenTK;
  2. using OpenTK.Graphics.OpenGL;
  3. using System;
  4. using System.Collections.Generic;
  5. namespace Ryujinx.Graphics.Gal.OpenGL
  6. {
  7. public class OGLFrameBuffer : IGalFrameBuffer
  8. {
  9. private struct Rect
  10. {
  11. public int X { get; private set; }
  12. public int Y { get; private set; }
  13. public int Width { get; private set; }
  14. public int Height { get; private set; }
  15. public Rect(int X, int Y, int Width, int Height)
  16. {
  17. this.X = X;
  18. this.Y = Y;
  19. this.Width = Width;
  20. this.Height = Height;
  21. }
  22. }
  23. private class FrameBuffer
  24. {
  25. public int Width { get; set; }
  26. public int Height { get; set; }
  27. public int Handle { get; private set; }
  28. public int RbHandle { get; private set; }
  29. public int TexHandle { get; private set; }
  30. public FrameBuffer(int Width, int Height, bool HasRenderBuffer)
  31. {
  32. this.Width = Width;
  33. this.Height = Height;
  34. Handle = GL.GenFramebuffer();
  35. TexHandle = GL.GenTexture();
  36. if (HasRenderBuffer)
  37. {
  38. RbHandle = GL.GenRenderbuffer();
  39. }
  40. }
  41. }
  42. private const int NativeWidth = 1280;
  43. private const int NativeHeight = 720;
  44. private Dictionary<long, FrameBuffer> Fbs;
  45. private Rect Viewport;
  46. private Rect Window;
  47. private FrameBuffer CurrFb;
  48. private FrameBuffer CurrReadFb;
  49. private FrameBuffer RawFb;
  50. private bool FlipX;
  51. private bool FlipY;
  52. private int CropTop;
  53. private int CropLeft;
  54. private int CropRight;
  55. private int CropBottom;
  56. public OGLFrameBuffer()
  57. {
  58. Fbs = new Dictionary<long, FrameBuffer>();
  59. }
  60. public void Create(long Key, int Width, int Height)
  61. {
  62. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  63. {
  64. if (Fb.Width != Width ||
  65. Fb.Height != Height)
  66. {
  67. SetupTexture(Fb.TexHandle, Width, Height);
  68. Fb.Width = Width;
  69. Fb.Height = Height;
  70. }
  71. return;
  72. }
  73. Fb = new FrameBuffer(Width, Height, true);
  74. SetupTexture(Fb.TexHandle, Width, Height);
  75. GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
  76. GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
  77. GL.RenderbufferStorage(
  78. RenderbufferTarget.Renderbuffer,
  79. RenderbufferStorage.Depth24Stencil8,
  80. Width,
  81. Height);
  82. GL.FramebufferRenderbuffer(
  83. FramebufferTarget.Framebuffer,
  84. FramebufferAttachment.DepthStencilAttachment,
  85. RenderbufferTarget.Renderbuffer,
  86. Fb.RbHandle);
  87. GL.FramebufferTexture(
  88. FramebufferTarget.Framebuffer,
  89. FramebufferAttachment.ColorAttachment0,
  90. Fb.TexHandle,
  91. 0);
  92. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  93. Fbs.Add(Key, Fb);
  94. }
  95. public void Bind(long Key)
  96. {
  97. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  98. {
  99. GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
  100. CurrFb = Fb;
  101. }
  102. }
  103. public void BindTexture(long Key, int Index)
  104. {
  105. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  106. {
  107. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  108. GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
  109. }
  110. }
  111. public void Set(long Key)
  112. {
  113. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  114. {
  115. CurrReadFb = Fb;
  116. }
  117. }
  118. public void Set(byte[] Data, int Width, int Height)
  119. {
  120. if (RawFb == null)
  121. {
  122. CreateRawFb(Width, Height);
  123. }
  124. if (RawFb.Width != Width ||
  125. RawFb.Height != Height)
  126. {
  127. SetupTexture(RawFb.TexHandle, Width, Height);
  128. RawFb.Width = Width;
  129. RawFb.Height = Height;
  130. }
  131. GL.ActiveTexture(TextureUnit.Texture0);
  132. GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle);
  133. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  134. GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
  135. CurrReadFb = RawFb;
  136. }
  137. public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
  138. {
  139. this.FlipX = FlipX;
  140. this.FlipY = FlipY;
  141. CropTop = Top;
  142. CropLeft = Left;
  143. CropRight = Right;
  144. CropBottom = Bottom;
  145. }
  146. public void SetWindowSize(int Width, int Height)
  147. {
  148. Window = new Rect(0, 0, Width, Height);
  149. }
  150. public void SetViewport(int X, int Y, int Width, int Height)
  151. {
  152. Viewport = new Rect(X, Y, Width, Height);
  153. SetViewport(Viewport);
  154. }
  155. private void SetViewport(Rect Viewport)
  156. {
  157. GL.Viewport(
  158. Viewport.X,
  159. Viewport.Y,
  160. Viewport.Width,
  161. Viewport.Height);
  162. }
  163. public void Render()
  164. {
  165. if (CurrReadFb != null)
  166. {
  167. int SrcX0, SrcX1, SrcY0, SrcY1;
  168. if (CropLeft == 0 && CropRight == 0)
  169. {
  170. SrcX0 = 0;
  171. SrcX1 = CurrReadFb.Width;
  172. }
  173. else
  174. {
  175. SrcX0 = CropLeft;
  176. SrcX1 = CropRight;
  177. }
  178. if (CropTop == 0 && CropBottom == 0)
  179. {
  180. SrcY0 = 0;
  181. SrcY1 = CurrReadFb.Height;
  182. }
  183. else
  184. {
  185. SrcY0 = CropTop;
  186. SrcY1 = CropBottom;
  187. }
  188. float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
  189. float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
  190. int DstWidth = (int)(Window.Width * RatioX);
  191. int DstHeight = (int)(Window.Height * RatioY);
  192. int DstPaddingX = (Window.Width - DstWidth) / 2;
  193. int DstPaddingY = (Window.Height - DstHeight) / 2;
  194. int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
  195. int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
  196. int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
  197. int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
  198. GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
  199. GL.Viewport(0, 0, Window.Width, Window.Height);
  200. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle);
  201. GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
  202. GL.BlitFramebuffer(
  203. SrcX0, SrcY0, SrcX1, SrcY1,
  204. DstX0, DstY0, DstX1, DstY1,
  205. ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
  206. }
  207. }
  208. public void Copy(
  209. long SrcKey,
  210. long DstKey,
  211. int SrcX0,
  212. int SrcY0,
  213. int SrcX1,
  214. int SrcY1,
  215. int DstX0,
  216. int DstY0,
  217. int DstX1,
  218. int DstY1)
  219. {
  220. if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) &&
  221. Fbs.TryGetValue(DstKey, out FrameBuffer DstFb))
  222. {
  223. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle);
  224. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle);
  225. GL.Clear(ClearBufferMask.ColorBufferBit);
  226. GL.BlitFramebuffer(
  227. SrcX0, SrcY0, SrcX1, SrcY1,
  228. DstX0, DstY0, DstX1, DstY1,
  229. ClearBufferMask.ColorBufferBit,
  230. BlitFramebufferFilter.Linear);
  231. }
  232. }
  233. public void GetBufferData(long Key, Action<byte[]> Callback)
  234. {
  235. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  236. {
  237. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
  238. byte[] Data = new byte[Fb.Width * Fb.Height * 4];
  239. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  240. GL.ReadPixels(
  241. 0,
  242. 0,
  243. Fb.Width,
  244. Fb.Height,
  245. Format,
  246. Type,
  247. Data);
  248. Callback(Data);
  249. }
  250. }
  251. public void SetBufferData(
  252. long Key,
  253. int Width,
  254. int Height,
  255. GalTextureFormat Format,
  256. byte[] Buffer)
  257. {
  258. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  259. {
  260. GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
  261. const int Level = 0;
  262. const int Border = 0;
  263. const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
  264. (PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format);
  265. GL.TexImage2D(
  266. TextureTarget.Texture2D,
  267. Level,
  268. InternalFmt,
  269. Width,
  270. Height,
  271. Border,
  272. GlFormat,
  273. Type,
  274. Buffer);
  275. }
  276. }
  277. private void CreateRawFb(int Width, int Height)
  278. {
  279. if (RawFb == null)
  280. {
  281. RawFb = new FrameBuffer(Width, Height, false);
  282. SetupTexture(RawFb.TexHandle, Width, Height);
  283. RawFb.Width = Width;
  284. RawFb.Height = Height;
  285. GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle);
  286. GL.FramebufferTexture(
  287. FramebufferTarget.Framebuffer,
  288. FramebufferAttachment.ColorAttachment0,
  289. RawFb.TexHandle,
  290. 0);
  291. GL.Viewport(0, 0, Width, Height);
  292. }
  293. }
  294. private void SetupTexture(int Handle, int Width, int Height)
  295. {
  296. GL.BindTexture(TextureTarget.Texture2D, Handle);
  297. const int MinFilter = (int)TextureMinFilter.Linear;
  298. const int MagFilter = (int)TextureMagFilter.Linear;
  299. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
  300. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
  301. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  302. const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
  303. const int Level = 0;
  304. const int Border = 0;
  305. GL.TexImage2D(
  306. TextureTarget.Texture2D,
  307. Level,
  308. InternalFmt,
  309. Width,
  310. Height,
  311. Border,
  312. Format,
  313. Type,
  314. IntPtr.Zero);
  315. }
  316. }
  317. }