OGLRenderTarget.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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 const int NativeWidth = 1280;
  23. private const int NativeHeight = 720;
  24. private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
  25. private OGLTexture Texture;
  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 OGLRenderTarget(OGLTexture Texture)
  46. {
  47. ColorAttachments = new int[8];
  48. this.Texture = Texture;
  49. }
  50. public void BindColor(long Key, int Attachment, GalImage Image)
  51. {
  52. if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
  53. {
  54. EnsureFrameBuffer();
  55. Attach(ref ColorAttachments[Attachment], CachedImage.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, GalImage Image)
  68. {
  69. if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
  70. {
  71. EnsureFrameBuffer();
  72. if (CachedImage.HasDepth && CachedImage.HasStencil)
  73. {
  74. if (DepthAttachment != CachedImage.Handle ||
  75. StencilAttachment != CachedImage.Handle)
  76. {
  77. GL.FramebufferTexture(
  78. FramebufferTarget.DrawFramebuffer,
  79. FramebufferAttachment.DepthStencilAttachment,
  80. CachedImage.Handle,
  81. 0);
  82. DepthAttachment = CachedImage.Handle;
  83. StencilAttachment = CachedImage.Handle;
  84. }
  85. }
  86. else if (CachedImage.HasDepth)
  87. {
  88. Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
  89. Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
  90. }
  91. else if (CachedImage.HasStencil)
  92. {
  93. Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
  94. Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
  95. }
  96. else
  97. {
  98. throw new InvalidOperationException();
  99. }
  100. }
  101. else
  102. {
  103. UnbindZeta();
  104. }
  105. }
  106. private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
  107. {
  108. if (OldHandle != NewHandle)
  109. {
  110. GL.FramebufferTexture(
  111. FramebufferTarget.DrawFramebuffer,
  112. FbAttachment,
  113. NewHandle,
  114. 0);
  115. OldHandle = NewHandle;
  116. }
  117. }
  118. public void UnbindZeta()
  119. {
  120. EnsureFrameBuffer();
  121. if (DepthAttachment != 0 || StencilAttachment != 0)
  122. {
  123. GL.FramebufferTexture(
  124. FramebufferTarget.DrawFramebuffer,
  125. FramebufferAttachment.DepthStencilAttachment,
  126. 0,
  127. 0);
  128. DepthAttachment = 0;
  129. StencilAttachment = 0;
  130. }
  131. }
  132. public void Set(long Key)
  133. {
  134. Texture.TryGetImageHandler(Key, out ReadTex);
  135. }
  136. public void SetMap(int[] Map)
  137. {
  138. if (Map != null && Map.Length > 0)
  139. {
  140. DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
  141. for (int i = 0; i < Map.Length; i++)
  142. {
  143. Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
  144. }
  145. GL.DrawBuffers(Mode.Length, Mode);
  146. }
  147. else
  148. {
  149. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  150. }
  151. }
  152. public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
  153. {
  154. this.FlipX = FlipX;
  155. this.FlipY = FlipY;
  156. CropTop = Top;
  157. CropLeft = Left;
  158. CropRight = Right;
  159. CropBottom = Bottom;
  160. }
  161. public void SetWindowSize(int Width, int Height)
  162. {
  163. Window = new Rect(0, 0, Width, Height);
  164. }
  165. public void SetViewport(int X, int Y, int Width, int Height)
  166. {
  167. Viewport = new Rect(X, Y, Width, Height);
  168. SetViewport(Viewport);
  169. }
  170. private void SetViewport(Rect Viewport)
  171. {
  172. GL.Viewport(
  173. Viewport.X,
  174. Viewport.Y,
  175. Viewport.Width,
  176. Viewport.Height);
  177. }
  178. public void Render()
  179. {
  180. if (ReadTex == null)
  181. {
  182. return;
  183. }
  184. int SrcX0, SrcX1, SrcY0, SrcY1;
  185. if (CropLeft == 0 && CropRight == 0)
  186. {
  187. SrcX0 = 0;
  188. SrcX1 = ReadTex.Width;
  189. }
  190. else
  191. {
  192. SrcX0 = CropLeft;
  193. SrcX1 = CropRight;
  194. }
  195. if (CropTop == 0 && CropBottom == 0)
  196. {
  197. SrcY0 = 0;
  198. SrcY1 = ReadTex.Height;
  199. }
  200. else
  201. {
  202. SrcY0 = CropTop;
  203. SrcY1 = CropBottom;
  204. }
  205. float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
  206. float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
  207. int DstWidth = (int)(Window.Width * RatioX);
  208. int DstHeight = (int)(Window.Height * RatioY);
  209. int DstPaddingX = (Window.Width - DstWidth) / 2;
  210. int DstPaddingY = (Window.Height - DstHeight) / 2;
  211. int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
  212. int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
  213. int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
  214. int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
  215. GL.Viewport(0, 0, Window.Width, Window.Height);
  216. if (SrcFb == 0)
  217. {
  218. SrcFb = GL.GenFramebuffer();
  219. }
  220. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
  221. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
  222. GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
  223. GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
  224. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  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. EnsureFrameBuffer();
  232. }
  233. public void Copy(
  234. long SrcKey,
  235. long DstKey,
  236. int SrcX0,
  237. int SrcY0,
  238. int SrcX1,
  239. int SrcY1,
  240. int DstX0,
  241. int DstY0,
  242. int DstX1,
  243. int DstY1)
  244. {
  245. if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
  246. Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
  247. {
  248. if (SrcTex.HasColor != DstTex.HasColor ||
  249. SrcTex.HasDepth != DstTex.HasDepth ||
  250. SrcTex.HasStencil != DstTex.HasStencil)
  251. {
  252. throw new NotImplementedException();
  253. }
  254. if (SrcFb == 0)
  255. {
  256. SrcFb = GL.GenFramebuffer();
  257. }
  258. if (DstFb == 0)
  259. {
  260. DstFb = GL.GenFramebuffer();
  261. }
  262. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
  263. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
  264. FramebufferAttachment Attachment = GetAttachment(SrcTex);
  265. GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
  266. GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
  267. BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
  268. if (SrcTex.HasColor)
  269. {
  270. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  271. Filter = BlitFramebufferFilter.Linear;
  272. }
  273. ClearBufferMask Mask = GetClearMask(SrcTex);
  274. GL.Clear(Mask);
  275. GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
  276. EnsureFrameBuffer();
  277. }
  278. }
  279. public void Reinterpret(long Key, GalImage NewImage)
  280. {
  281. if (!Texture.TryGetImage(Key, out GalImage OldImage))
  282. {
  283. return;
  284. }
  285. if (NewImage.Format == OldImage.Format)
  286. {
  287. return;
  288. }
  289. byte[] Data = GetData(Key);
  290. GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
  291. Texture.Create(Key, Data, NewImage);
  292. GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
  293. }
  294. public byte[] GetData(long Key)
  295. {
  296. if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
  297. {
  298. return null;
  299. }
  300. if (SrcFb == 0)
  301. {
  302. SrcFb = GL.GenFramebuffer();
  303. }
  304. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
  305. FramebufferAttachment Attachment = GetAttachment(CachedImage);
  306. GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0);
  307. int Size = ImageUtils.GetSize(CachedImage.Image);
  308. byte[] Data = new byte[Size];
  309. int Width = CachedImage.Width;
  310. int Height = CachedImage.Height;
  311. (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
  312. GL.ReadPixels(0, 0, Width, Height, Format, Type, Data);
  313. return Data;
  314. }
  315. private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)
  316. {
  317. if (CachedImage.HasColor)
  318. {
  319. return FramebufferAttachment.ColorAttachment0;
  320. }
  321. else if (CachedImage.HasDepth && CachedImage.HasStencil)
  322. {
  323. return FramebufferAttachment.DepthStencilAttachment;
  324. }
  325. else if (CachedImage.HasDepth)
  326. {
  327. return FramebufferAttachment.DepthAttachment;
  328. }
  329. else if (CachedImage.HasStencil)
  330. {
  331. return FramebufferAttachment.StencilAttachment;
  332. }
  333. else
  334. {
  335. throw new InvalidOperationException();
  336. }
  337. }
  338. private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
  339. {
  340. return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
  341. (CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
  342. (CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
  343. }
  344. private void EnsureFrameBuffer()
  345. {
  346. if (DummyFrameBuffer == 0)
  347. {
  348. DummyFrameBuffer = GL.GenFramebuffer();
  349. }
  350. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
  351. }
  352. }
  353. }