OGLRenderTarget.cs 15 KB

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