OGLRenderTarget.cs 14 KB

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