FrameBuffer.cs 6.6 KB

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