FrameBuffer.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. using OpenTK;
  2. using OpenTK.Graphics.OpenGL;
  3. using System;
  4. namespace Ryujinx.Graphics.Gal.OpenGL
  5. {
  6. unsafe class FrameBuffer
  7. {
  8. public int WindowWidth { get; set; }
  9. public int WindowHeight { get; set; }
  10. private int VtxShaderHandle;
  11. private int FragShaderHandle;
  12. private int PrgShaderHandle;
  13. private int TexHandle;
  14. private int TexWidth;
  15. private int TexHeight;
  16. private int VaoHandle;
  17. private int VboHandle;
  18. private int[] Pixels;
  19. private byte* FbPtr;
  20. private object FbPtrLock;
  21. public FrameBuffer(int Width, int Height)
  22. {
  23. if (Width < 0)
  24. {
  25. throw new ArgumentOutOfRangeException(nameof(Width));
  26. }
  27. if (Height < 0)
  28. {
  29. throw new ArgumentOutOfRangeException(nameof(Height));
  30. }
  31. FbPtrLock = new object();
  32. TexWidth = Width;
  33. TexHeight = Height;
  34. WindowWidth = Width;
  35. WindowHeight = Height;
  36. SetupShaders();
  37. SetupTexture();
  38. SetupVertex();
  39. }
  40. private void SetupShaders()
  41. {
  42. VtxShaderHandle = GL.CreateShader(ShaderType.VertexShader);
  43. FragShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
  44. string VtxShaderSource = EmbeddedResource.GetString("GlFbVtxShader");
  45. string FragShaderSource = EmbeddedResource.GetString("GlFbFragShader");
  46. GL.ShaderSource(VtxShaderHandle, VtxShaderSource);
  47. GL.ShaderSource(FragShaderHandle, FragShaderSource);
  48. GL.CompileShader(VtxShaderHandle);
  49. GL.CompileShader(FragShaderHandle);
  50. PrgShaderHandle = GL.CreateProgram();
  51. GL.AttachShader(PrgShaderHandle, VtxShaderHandle);
  52. GL.AttachShader(PrgShaderHandle, FragShaderHandle);
  53. GL.LinkProgram(PrgShaderHandle);
  54. GL.UseProgram(PrgShaderHandle);
  55. int TexUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "tex");
  56. GL.Uniform1(TexUniformLocation, 0);
  57. int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
  58. GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
  59. }
  60. private void SetupTexture()
  61. {
  62. Pixels = new int[TexWidth * TexHeight];
  63. if (TexHandle == 0)
  64. {
  65. TexHandle = GL.GenTexture();
  66. }
  67. GL.BindTexture(TextureTarget.Texture2D, TexHandle);
  68. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
  69. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
  70. GL.TexImage2D(TextureTarget.Texture2D,
  71. 0,
  72. PixelInternalFormat.Rgba,
  73. TexWidth,
  74. TexHeight,
  75. 0,
  76. PixelFormat.Rgba,
  77. PixelType.UnsignedByte,
  78. IntPtr.Zero);
  79. }
  80. private void SetupVertex()
  81. {
  82. VaoHandle = GL.GenVertexArray();
  83. VboHandle = GL.GenBuffer();
  84. float[] Buffer = new float[]
  85. {
  86. -1, 1, 0, 0,
  87. 1, 1, 1, 0,
  88. -1, -1, 0, 1,
  89. 1, -1, 1, 1
  90. };
  91. IntPtr Length = new IntPtr(Buffer.Length * 4);
  92. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  93. GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
  94. GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
  95. GL.BindVertexArray(VaoHandle);
  96. GL.EnableVertexAttribArray(0);
  97. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  98. GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
  99. GL.EnableVertexAttribArray(1);
  100. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  101. GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
  102. GL.BindVertexArray(0);
  103. }
  104. public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform, Vector2 Offs)
  105. {
  106. if (Fb == null)
  107. {
  108. throw new ArgumentNullException(nameof(Fb));
  109. }
  110. if (Width < 0)
  111. {
  112. throw new ArgumentOutOfRangeException(nameof(Width));
  113. }
  114. if (Height < 0)
  115. {
  116. throw new ArgumentOutOfRangeException(nameof(Height));
  117. }
  118. lock (FbPtrLock)
  119. {
  120. FbPtr = Fb;
  121. }
  122. if (Width != TexWidth ||
  123. Height != TexHeight)
  124. {
  125. TexWidth = Width;
  126. TexHeight = Height;
  127. SetupTexture();
  128. }
  129. GL.UseProgram(PrgShaderHandle);
  130. int TransformUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "transform");
  131. GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
  132. int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
  133. GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
  134. int OffsetUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "offset");
  135. GL.Uniform2(OffsetUniformLocation, Offs);
  136. }
  137. public void Reset()
  138. {
  139. lock (FbPtrLock)
  140. {
  141. FbPtr = null;
  142. }
  143. }
  144. public void Render()
  145. {
  146. lock (FbPtrLock)
  147. {
  148. if (FbPtr == null)
  149. {
  150. return;
  151. }
  152. for (int Y = 0; Y < TexHeight; Y++)
  153. for (int X = 0; X < TexWidth; X++)
  154. {
  155. Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
  156. }
  157. }
  158. GL.BindTexture(TextureTarget.Texture2D, TexHandle);
  159. GL.TexSubImage2D(TextureTarget.Texture2D,
  160. 0,
  161. 0,
  162. 0,
  163. TexWidth,
  164. TexHeight,
  165. PixelFormat.Rgba,
  166. PixelType.UnsignedByte,
  167. Pixels);
  168. GL.ActiveTexture(TextureUnit.Texture0);
  169. GL.BindVertexArray(VaoHandle);
  170. GL.UseProgram(PrgShaderHandle);
  171. GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
  172. }
  173. private int GetSwizzleOffset(int X, int Y)
  174. {
  175. int Pos;
  176. Pos = (Y & 0x7f) >> 4;
  177. Pos += (X >> 4) << 3;
  178. Pos += (Y >> 7) * ((TexWidth >> 4) << 3);
  179. Pos *= 1024;
  180. Pos += ((Y & 0xf) >> 3) << 9;
  181. Pos += ((X & 0xf) >> 3) << 8;
  182. Pos += ((Y & 0x7) >> 1) << 6;
  183. Pos += ((X & 0x7) >> 2) << 5;
  184. Pos += ((Y & 0x1) >> 0) << 4;
  185. Pos += ((X & 0x3) >> 0) << 2;
  186. return Pos;
  187. }
  188. }
  189. }