OGLFrameBuffer.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. using OpenTK.Graphics.OpenGL;
  2. using System;
  3. namespace Ryujinx.Graphics.Gal.OpenGL
  4. {
  5. class OGLFrameBuffer : IGalFrameBuffer
  6. {
  7. private struct Rect
  8. {
  9. public int X { get; private set; }
  10. public int Y { get; private set; }
  11. public int Width { get; private set; }
  12. public int Height { get; private set; }
  13. public Rect(int X, int Y, int Width, int Height)
  14. {
  15. this.X = X;
  16. this.Y = Y;
  17. this.Width = Width;
  18. this.Height = Height;
  19. }
  20. }
  21. private const int NativeWidth = 1280;
  22. private const int NativeHeight = 720;
  23. private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8_UNORM_PACK32;
  24. private OGLTexture Texture;
  25. private ImageHandler RawTex;
  26. private ImageHandler ReadTex;
  27. private Rect Viewport;
  28. private Rect Window;
  29. private bool FlipX;
  30. private bool FlipY;
  31. private int CropTop;
  32. private int CropLeft;
  33. private int CropRight;
  34. private int CropBottom;
  35. //This framebuffer is used to attach guest rendertargets,
  36. //think of it as a dummy OpenGL VAO
  37. private int DummyFrameBuffer;
  38. //These framebuffers are used to blit images
  39. private int SrcFb;
  40. private int DstFb;
  41. //Holds current attachments, used to avoid unnecesary calls to OpenGL
  42. private int[] ColorAttachments;
  43. private int DepthAttachment;
  44. private int StencilAttachment;
  45. public OGLFrameBuffer(OGLTexture Texture)
  46. {
  47. ColorAttachments = new int[8];
  48. this.Texture = Texture;
  49. }
  50. public void BindColor(long Key, int Attachment)
  51. {
  52. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  53. {
  54. EnsureFrameBuffer();
  55. Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
  56. }
  57. else
  58. {
  59. UnbindColor(Attachment);
  60. }
  61. }
  62. public void UnbindColor(int Attachment)
  63. {
  64. EnsureFrameBuffer();
  65. Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
  66. }
  67. public void BindZeta(long Key)
  68. {
  69. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  70. {
  71. EnsureFrameBuffer();
  72. if (Tex.HasDepth && Tex.HasStencil)
  73. {
  74. if (DepthAttachment != Tex.Handle ||
  75. StencilAttachment != Tex.Handle)
  76. {
  77. GL.FramebufferTexture(
  78. FramebufferTarget.DrawFramebuffer,
  79. FramebufferAttachment.DepthStencilAttachment,
  80. Tex.Handle,
  81. 0);
  82. DepthAttachment = Tex.Handle;
  83. StencilAttachment = Tex.Handle;
  84. }
  85. }
  86. else if (Tex.HasDepth)
  87. {
  88. Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
  89. Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
  90. }
  91. else if (Tex.HasStencil)
  92. {
  93. Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
  94. Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
  95. }
  96. else
  97. {
  98. throw new InvalidOperationException();
  99. }
  100. }
  101. else
  102. {
  103. UnbindZeta();
  104. }
  105. }
  106. public void UnbindZeta()
  107. {
  108. EnsureFrameBuffer();
  109. if (DepthAttachment != 0 ||
  110. StencilAttachment != 0)
  111. {
  112. GL.FramebufferTexture(
  113. FramebufferTarget.DrawFramebuffer,
  114. FramebufferAttachment.DepthStencilAttachment,
  115. 0,
  116. 0);
  117. DepthAttachment = 0;
  118. StencilAttachment = 0;
  119. }
  120. }
  121. public void BindTexture(long Key, int Index)
  122. {
  123. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  124. {
  125. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  126. GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
  127. }
  128. }
  129. public void Set(long Key)
  130. {
  131. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  132. {
  133. ReadTex = Tex;
  134. }
  135. }
  136. public void Set(byte[] Data, int Width, int Height)
  137. {
  138. if (RawTex == null)
  139. {
  140. RawTex = new ImageHandler();
  141. }
  142. RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
  143. GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
  144. GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
  145. ReadTex = RawTex;
  146. }
  147. public void SetMap(int[] Map)
  148. {
  149. if (Map != null && Map.Length > 0)
  150. {
  151. DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
  152. for (int i = 0; i < Map.Length; i++)
  153. {
  154. Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
  155. }
  156. GL.DrawBuffers(Mode.Length, Mode);
  157. }
  158. else
  159. {
  160. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  161. }
  162. }
  163. public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
  164. {
  165. this.FlipX = FlipX;
  166. this.FlipY = FlipY;
  167. CropTop = Top;
  168. CropLeft = Left;
  169. CropRight = Right;
  170. CropBottom = Bottom;
  171. }
  172. public void SetWindowSize(int Width, int Height)
  173. {
  174. Window = new Rect(0, 0, Width, Height);
  175. }
  176. public void SetViewport(int X, int Y, int Width, int Height)
  177. {
  178. Viewport = new Rect(X, Y, Width, Height);
  179. SetViewport(Viewport);
  180. }
  181. private void SetViewport(Rect Viewport)
  182. {
  183. GL.Viewport(
  184. Viewport.X,
  185. Viewport.Y,
  186. Viewport.Width,
  187. Viewport.Height);
  188. }
  189. public void Render()
  190. {
  191. if (ReadTex == null)
  192. {
  193. return;
  194. }
  195. int SrcX0, SrcX1, SrcY0, SrcY1;
  196. if (CropLeft == 0 && CropRight == 0)
  197. {
  198. SrcX0 = 0;
  199. SrcX1 = ReadTex.Width;
  200. }
  201. else
  202. {
  203. SrcX0 = CropLeft;
  204. SrcX1 = CropRight;
  205. }
  206. if (CropTop == 0 && CropBottom == 0)
  207. {
  208. SrcY0 = 0;
  209. SrcY1 = ReadTex.Height;
  210. }
  211. else
  212. {
  213. SrcY0 = CropTop;
  214. SrcY1 = CropBottom;
  215. }
  216. float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
  217. float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
  218. int DstWidth = (int)(Window.Width * RatioX);
  219. int DstHeight = (int)(Window.Height * RatioY);
  220. int DstPaddingX = (Window.Width - DstWidth) / 2;
  221. int DstPaddingY = (Window.Height - DstHeight) / 2;
  222. int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
  223. int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
  224. int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
  225. int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
  226. if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
  227. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
  228. GL.Viewport(0, 0, Window.Width, Window.Height);
  229. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
  230. GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
  231. GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
  232. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  233. GL.Clear(ClearBufferMask.ColorBufferBit);
  234. GL.BlitFramebuffer(
  235. SrcX0, SrcY0, SrcX1, SrcY1,
  236. DstX0, DstY0, DstX1, DstY1,
  237. ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
  238. EnsureFrameBuffer();
  239. }
  240. public void Copy(
  241. long SrcKey,
  242. long DstKey,
  243. int SrcX0,
  244. int SrcY0,
  245. int SrcX1,
  246. int SrcY1,
  247. int DstX0,
  248. int DstY0,
  249. int DstX1,
  250. int DstY1)
  251. {
  252. if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
  253. Texture.TryGetImage(DstKey, out ImageHandler DstTex))
  254. {
  255. if (SrcTex.HasColor != DstTex.HasColor ||
  256. SrcTex.HasDepth != DstTex.HasDepth ||
  257. SrcTex.HasStencil != DstTex.HasStencil)
  258. {
  259. throw new NotImplementedException();
  260. }
  261. if (SrcTex.HasColor)
  262. {
  263. CopyTextures(
  264. SrcX0, SrcY0, SrcX1, SrcY1,
  265. DstX0, DstY0, DstX1, DstY1,
  266. SrcTex.Handle,
  267. DstTex.Handle,
  268. FramebufferAttachment.ColorAttachment0,
  269. ClearBufferMask.ColorBufferBit,
  270. true);
  271. }
  272. else if (SrcTex.HasDepth && SrcTex.HasStencil)
  273. {
  274. CopyTextures(
  275. SrcX0, SrcY0, SrcX1, SrcY1,
  276. DstX0, DstY0, DstX1, DstY1,
  277. SrcTex.Handle,
  278. DstTex.Handle,
  279. FramebufferAttachment.DepthStencilAttachment,
  280. ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
  281. false);
  282. }
  283. else if (SrcTex.HasDepth)
  284. {
  285. CopyTextures(
  286. SrcX0, SrcY0, SrcX1, SrcY1,
  287. DstX0, DstY0, DstX1, DstY1,
  288. SrcTex.Handle,
  289. DstTex.Handle,
  290. FramebufferAttachment.DepthAttachment,
  291. ClearBufferMask.DepthBufferBit,
  292. false);
  293. }
  294. else if (SrcTex.HasStencil)
  295. {
  296. CopyTextures(
  297. SrcX0, SrcY0, SrcX1, SrcY1,
  298. DstX0, DstY0, DstX1, DstY1,
  299. SrcTex.Handle,
  300. DstTex.Handle,
  301. FramebufferAttachment.StencilAttachment,
  302. ClearBufferMask.StencilBufferBit,
  303. false);
  304. }
  305. else
  306. {
  307. throw new InvalidOperationException();
  308. }
  309. }
  310. }
  311. public void GetBufferData(long Key, Action<byte[]> Callback)
  312. {
  313. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  314. {
  315. byte[] Data = new byte[Tex.Width * Tex.Height * ImageHandler.MaxBpp];
  316. GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
  317. GL.GetTexImage(
  318. TextureTarget.Texture2D,
  319. 0,
  320. Tex.PixelFormat,
  321. Tex.PixelType,
  322. Data);
  323. Callback(Data);
  324. }
  325. }
  326. public void SetBufferData(
  327. long Key,
  328. int Width,
  329. int Height,
  330. byte[] Buffer)
  331. {
  332. if (Texture.TryGetImage(Key, out ImageHandler Tex))
  333. {
  334. GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
  335. const int Level = 0;
  336. const int Border = 0;
  337. GL.TexImage2D(
  338. TextureTarget.Texture2D,
  339. Level,
  340. Tex.InternalFormat,
  341. Width,
  342. Height,
  343. Border,
  344. Tex.PixelFormat,
  345. Tex.PixelType,
  346. Buffer);
  347. }
  348. }
  349. private void EnsureFrameBuffer()
  350. {
  351. if (DummyFrameBuffer == 0)
  352. {
  353. DummyFrameBuffer = GL.GenFramebuffer();
  354. }
  355. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
  356. }
  357. private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
  358. {
  359. if (OldHandle != NewHandle)
  360. {
  361. GL.FramebufferTexture(
  362. FramebufferTarget.DrawFramebuffer,
  363. FbAttachment,
  364. NewHandle,
  365. 0);
  366. OldHandle = NewHandle;
  367. }
  368. }
  369. private void CopyTextures(
  370. int SrcX0,
  371. int SrcY0,
  372. int SrcX1,
  373. int SrcY1,
  374. int DstX0,
  375. int DstY0,
  376. int DstX1,
  377. int DstY1,
  378. int SrcTexture,
  379. int DstTexture,
  380. FramebufferAttachment Attachment,
  381. ClearBufferMask Mask,
  382. bool Color)
  383. {
  384. if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
  385. if (DstFb == 0) DstFb = GL.GenFramebuffer();
  386. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
  387. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
  388. GL.FramebufferTexture(
  389. FramebufferTarget.ReadFramebuffer,
  390. Attachment,
  391. SrcTexture,
  392. 0);
  393. GL.FramebufferTexture(
  394. FramebufferTarget.DrawFramebuffer,
  395. Attachment,
  396. DstTexture,
  397. 0);
  398. if (Color)
  399. {
  400. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  401. }
  402. GL.Clear(Mask);
  403. GL.BlitFramebuffer(
  404. SrcX0, SrcY0, SrcX1, SrcY1,
  405. DstX0, DstY0, DstX1, DstY1,
  406. Mask,
  407. Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
  408. EnsureFrameBuffer();
  409. }
  410. }
  411. }