OGLFrameBuffer.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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)
  31. {
  32. this.Width = Width;
  33. this.Height = Height;
  34. Handle = GL.GenFramebuffer();
  35. RbHandle = GL.GenRenderbuffer();
  36. TexHandle = GL.GenTexture();
  37. }
  38. }
  39. private struct ShaderProgram
  40. {
  41. public int Handle;
  42. public int VpHandle;
  43. public int FpHandle;
  44. }
  45. private Dictionary<long, FrameBuffer> Fbs;
  46. private ShaderProgram Shader;
  47. private Rect Viewport;
  48. private Rect Window;
  49. private bool IsInitialized;
  50. private int RawFbTexWidth;
  51. private int RawFbTexHeight;
  52. private int RawFbTexHandle;
  53. private int CurrFbHandle;
  54. private int CurrTexHandle;
  55. private int VaoHandle;
  56. private int VboHandle;
  57. public OGLFrameBuffer()
  58. {
  59. Fbs = new Dictionary<long, FrameBuffer>();
  60. Shader = new ShaderProgram();
  61. }
  62. public void Create(long Key, int Width, int Height)
  63. {
  64. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  65. {
  66. if (Fb.Width != Width ||
  67. Fb.Height != Height)
  68. {
  69. SetupTexture(Fb.TexHandle, Width, Height);
  70. Fb.Width = Width;
  71. Fb.Height = Height;
  72. }
  73. return;
  74. }
  75. Fb = new FrameBuffer(Width, Height);
  76. SetupTexture(Fb.TexHandle, Width, Height);
  77. GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
  78. GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
  79. GL.RenderbufferStorage(
  80. RenderbufferTarget.Renderbuffer,
  81. RenderbufferStorage.Depth24Stencil8,
  82. Width,
  83. Height);
  84. GL.FramebufferRenderbuffer(
  85. FramebufferTarget.Framebuffer,
  86. FramebufferAttachment.DepthStencilAttachment,
  87. RenderbufferTarget.Renderbuffer,
  88. Fb.RbHandle);
  89. GL.FramebufferTexture(
  90. FramebufferTarget.Framebuffer,
  91. FramebufferAttachment.ColorAttachment0,
  92. Fb.TexHandle,
  93. 0);
  94. GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
  95. Fbs.Add(Key, Fb);
  96. }
  97. public void Bind(long Key)
  98. {
  99. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  100. {
  101. GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
  102. CurrFbHandle = Fb.Handle;
  103. }
  104. }
  105. public void BindTexture(long Key, int Index)
  106. {
  107. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  108. {
  109. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  110. GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
  111. }
  112. }
  113. public void Set(long Key)
  114. {
  115. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  116. {
  117. CurrTexHandle = Fb.TexHandle;
  118. }
  119. }
  120. public void Set(byte[] Data, int Width, int Height)
  121. {
  122. if (RawFbTexHandle == 0)
  123. {
  124. RawFbTexHandle = GL.GenTexture();
  125. }
  126. if (RawFbTexWidth != Width ||
  127. RawFbTexHeight != Height)
  128. {
  129. SetupTexture(RawFbTexHandle, Width, Height);
  130. RawFbTexWidth = Width;
  131. RawFbTexHeight = Height;
  132. }
  133. GL.ActiveTexture(TextureUnit.Texture0);
  134. GL.BindTexture(TextureTarget.Texture2D, RawFbTexHandle);
  135. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  136. GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
  137. CurrTexHandle = RawFbTexHandle;
  138. }
  139. public void SetTransform(float SX, float SY, float Rotate, float TX, float TY)
  140. {
  141. EnsureInitialized();
  142. Matrix2 Transform;
  143. Transform = Matrix2.CreateScale(SX, SY);
  144. Transform *= Matrix2.CreateRotation(Rotate);
  145. Vector2 Offs = new Vector2(TX, TY);
  146. int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
  147. GL.UseProgram(Shader.Handle);
  148. int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
  149. GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
  150. int OffsetUniformLocation = GL.GetUniformLocation(Shader.Handle, "offset");
  151. GL.Uniform2(OffsetUniformLocation, ref Offs);
  152. GL.UseProgram(CurrentProgram);
  153. }
  154. public void SetWindowSize(int Width, int Height)
  155. {
  156. int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
  157. GL.UseProgram(Shader.Handle);
  158. int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
  159. GL.Uniform2(WindowSizeUniformLocation, new Vector2(Width, Height));
  160. GL.UseProgram(CurrentProgram);
  161. Window = new Rect(0, 0, Width, Height);
  162. }
  163. public void SetViewport(int X, int Y, int Width, int Height)
  164. {
  165. Viewport = new Rect(X, Y, Width, Height);
  166. SetViewport(Viewport);
  167. }
  168. private void SetViewport(Rect Viewport)
  169. {
  170. GL.Viewport(
  171. Viewport.X,
  172. Viewport.Y,
  173. Viewport.Width,
  174. Viewport.Height);
  175. }
  176. public void Render()
  177. {
  178. if (CurrTexHandle != 0)
  179. {
  180. EnsureInitialized();
  181. //bool CullFaceEnable = GL.IsEnabled(EnableCap.CullFace);
  182. bool DepthTestEnable = GL.IsEnabled(EnableCap.DepthTest);
  183. bool StencilTestEnable = GL.IsEnabled(EnableCap.StencilTest);
  184. bool AlphaBlendEnable = GL.IsEnabled(EnableCap.Blend);
  185. //GL.Disable(EnableCap.CullFace);
  186. GL.Disable(EnableCap.DepthTest);
  187. GL.Disable(EnableCap.StencilTest);
  188. GL.Disable(EnableCap.Blend);
  189. GL.ActiveTexture(TextureUnit.Texture0);
  190. GL.BindTexture(TextureTarget.Texture2D, CurrTexHandle);
  191. int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
  192. GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
  193. SetViewport(Window);
  194. GL.Clear(
  195. ClearBufferMask.ColorBufferBit |
  196. ClearBufferMask.DepthBufferBit);
  197. GL.BindVertexArray(VaoHandle);
  198. GL.UseProgram(Shader.Handle);
  199. GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
  200. //Restore the original state.
  201. GL.BindFramebuffer(FramebufferTarget.Framebuffer, CurrFbHandle);
  202. GL.UseProgram(CurrentProgram);
  203. //if (CullFaceEnable)
  204. //{
  205. // GL.Enable(EnableCap.CullFace);
  206. //}
  207. if (DepthTestEnable)
  208. {
  209. GL.Enable(EnableCap.DepthTest);
  210. }
  211. if (StencilTestEnable)
  212. {
  213. GL.Enable(EnableCap.StencilTest);
  214. }
  215. if (AlphaBlendEnable)
  216. {
  217. GL.Enable(EnableCap.Blend);
  218. }
  219. SetViewport(Viewport);
  220. }
  221. }
  222. public void Copy(
  223. long SrcKey,
  224. long DstKey,
  225. int SrcX0,
  226. int SrcY0,
  227. int SrcX1,
  228. int SrcY1,
  229. int DstX0,
  230. int DstY0,
  231. int DstX1,
  232. int DstY1)
  233. {
  234. if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) &&
  235. Fbs.TryGetValue(DstKey, out FrameBuffer DstFb))
  236. {
  237. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle);
  238. GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle);
  239. GL.Clear(ClearBufferMask.ColorBufferBit);
  240. GL.BlitFramebuffer(
  241. SrcX0, SrcY0, SrcX1, SrcY1,
  242. DstX0, DstY0, DstX1, DstY1,
  243. ClearBufferMask.ColorBufferBit,
  244. BlitFramebufferFilter.Linear);
  245. }
  246. }
  247. public void GetBufferData(long Key, Action<byte[]> Callback)
  248. {
  249. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  250. {
  251. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
  252. byte[] Data = new byte[Fb.Width * Fb.Height * 4];
  253. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  254. GL.ReadPixels(
  255. 0,
  256. 0,
  257. Fb.Width,
  258. Fb.Height,
  259. Format,
  260. Type,
  261. Data);
  262. Callback(Data);
  263. GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrFbHandle);
  264. }
  265. }
  266. public void SetBufferData(
  267. long Key,
  268. int Width,
  269. int Height,
  270. GalTextureFormat Format,
  271. byte[] Buffer)
  272. {
  273. if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
  274. {
  275. GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
  276. const int Level = 0;
  277. const int Border = 0;
  278. const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
  279. (PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format);
  280. GL.TexImage2D(
  281. TextureTarget.Texture2D,
  282. Level,
  283. InternalFmt,
  284. Width,
  285. Height,
  286. Border,
  287. GlFormat,
  288. Type,
  289. Buffer);
  290. }
  291. }
  292. private void EnsureInitialized()
  293. {
  294. if (!IsInitialized)
  295. {
  296. IsInitialized = true;
  297. SetupShader();
  298. SetupVertex();
  299. }
  300. }
  301. private void SetupShader()
  302. {
  303. Shader.VpHandle = GL.CreateShader(ShaderType.VertexShader);
  304. Shader.FpHandle = GL.CreateShader(ShaderType.FragmentShader);
  305. string VpSource = EmbeddedResource.GetString("GlFbVtxShader");
  306. string FpSource = EmbeddedResource.GetString("GlFbFragShader");
  307. GL.ShaderSource(Shader.VpHandle, VpSource);
  308. GL.ShaderSource(Shader.FpHandle, FpSource);
  309. GL.CompileShader(Shader.VpHandle);
  310. GL.CompileShader(Shader.FpHandle);
  311. Shader.Handle = GL.CreateProgram();
  312. GL.AttachShader(Shader.Handle, Shader.VpHandle);
  313. GL.AttachShader(Shader.Handle, Shader.FpHandle);
  314. GL.LinkProgram(Shader.Handle);
  315. GL.UseProgram(Shader.Handle);
  316. Matrix2 Transform = Matrix2.Identity;
  317. int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex");
  318. GL.Uniform1(TexUniformLocation, 0);
  319. int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
  320. GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
  321. int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
  322. GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
  323. }
  324. private void SetupVertex()
  325. {
  326. VaoHandle = GL.GenVertexArray();
  327. VboHandle = GL.GenBuffer();
  328. float[] Buffer = new float[]
  329. {
  330. -1, 1, 0, 0,
  331. 1, 1, 1, 0,
  332. -1, -1, 0, 1,
  333. 1, -1, 1, 1
  334. };
  335. IntPtr Length = new IntPtr(Buffer.Length * 4);
  336. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  337. GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
  338. GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
  339. GL.BindVertexArray(VaoHandle);
  340. GL.EnableVertexAttribArray(0);
  341. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  342. GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
  343. GL.EnableVertexAttribArray(1);
  344. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  345. GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
  346. }
  347. private void SetupTexture(int Handle, int Width, int Height)
  348. {
  349. GL.BindTexture(TextureTarget.Texture2D, Handle);
  350. const int MinFilter = (int)TextureMinFilter.Linear;
  351. const int MagFilter = (int)TextureMagFilter.Linear;
  352. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
  353. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
  354. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
  355. const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
  356. const int Level = 0;
  357. const int Border = 0;
  358. GL.TexImage2D(
  359. TextureTarget.Texture2D,
  360. Level,
  361. InternalFmt,
  362. Width,
  363. Height,
  364. Border,
  365. Format,
  366. Type,
  367. IntPtr.Zero);
  368. }
  369. }
  370. }