OGLRasterizer.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. using OpenTK.Graphics.OpenGL;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.Graphics.Gal.OpenGL
  5. {
  6. public class OGLRasterizer : IGalRasterizer
  7. {
  8. private static Dictionary<GalVertexAttribSize, int> AttribElements =
  9. new Dictionary<GalVertexAttribSize, int>()
  10. {
  11. { GalVertexAttribSize._32_32_32_32, 4 },
  12. { GalVertexAttribSize._32_32_32, 3 },
  13. { GalVertexAttribSize._16_16_16_16, 4 },
  14. { GalVertexAttribSize._32_32, 2 },
  15. { GalVertexAttribSize._16_16_16, 3 },
  16. { GalVertexAttribSize._8_8_8_8, 4 },
  17. { GalVertexAttribSize._16_16, 2 },
  18. { GalVertexAttribSize._32, 1 },
  19. { GalVertexAttribSize._8_8_8, 3 },
  20. { GalVertexAttribSize._8_8, 2 },
  21. { GalVertexAttribSize._16, 1 },
  22. { GalVertexAttribSize._8, 1 },
  23. { GalVertexAttribSize._10_10_10_2, 4 },
  24. { GalVertexAttribSize._11_11_10, 3 }
  25. };
  26. private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> AttribTypes =
  27. new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
  28. {
  29. { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
  30. { GalVertexAttribSize._32_32_32, VertexAttribPointerType.Int },
  31. { GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.Short },
  32. { GalVertexAttribSize._32_32, VertexAttribPointerType.Int },
  33. { GalVertexAttribSize._16_16_16, VertexAttribPointerType.Short },
  34. { GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.Byte },
  35. { GalVertexAttribSize._16_16, VertexAttribPointerType.Short },
  36. { GalVertexAttribSize._32, VertexAttribPointerType.Int },
  37. { GalVertexAttribSize._8_8_8, VertexAttribPointerType.Byte },
  38. { GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
  39. { GalVertexAttribSize._16, VertexAttribPointerType.Short },
  40. { GalVertexAttribSize._8, VertexAttribPointerType.Byte },
  41. { GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int }, //?
  42. { GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
  43. };
  44. private int VaoHandle;
  45. private int[] VertexBuffers;
  46. private OGLCachedResource<int> VboCache;
  47. private OGLCachedResource<int> IboCache;
  48. private struct IbInfo
  49. {
  50. public int Count;
  51. public int ElemSizeLog2;
  52. public DrawElementsType Type;
  53. }
  54. private IbInfo IndexBuffer;
  55. public OGLRasterizer()
  56. {
  57. VertexBuffers = new int[32];
  58. VboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
  59. IboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
  60. IndexBuffer = new IbInfo();
  61. }
  62. public void LockCaches()
  63. {
  64. VboCache.Lock();
  65. IboCache.Lock();
  66. }
  67. public void UnlockCaches()
  68. {
  69. VboCache.Unlock();
  70. IboCache.Unlock();
  71. }
  72. public void ClearBuffers(GalClearBufferFlags Flags)
  73. {
  74. ClearBufferMask Mask = ClearBufferMask.ColorBufferBit;
  75. GL.ColorMask(
  76. Flags.HasFlag(GalClearBufferFlags.ColorRed),
  77. Flags.HasFlag(GalClearBufferFlags.ColorGreen),
  78. Flags.HasFlag(GalClearBufferFlags.ColorBlue),
  79. Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
  80. if (Flags.HasFlag(GalClearBufferFlags.Depth))
  81. {
  82. Mask |= ClearBufferMask.DepthBufferBit;
  83. }
  84. if (Flags.HasFlag(GalClearBufferFlags.Stencil))
  85. {
  86. Mask |= ClearBufferMask.StencilBufferBit;
  87. }
  88. GL.Clear(Mask);
  89. GL.ColorMask(true, true, true, true);
  90. }
  91. public bool IsVboCached(long Key, long DataSize)
  92. {
  93. return VboCache.TryGetSize(Key, out long Size) && Size == DataSize;
  94. }
  95. public bool IsIboCached(long Key, long DataSize)
  96. {
  97. return IboCache.TryGetSize(Key, out long Size) && Size == DataSize;
  98. }
  99. public void SetFrontFace(GalFrontFace FrontFace)
  100. {
  101. GL.FrontFace(OGLEnumConverter.GetFrontFace(FrontFace));
  102. }
  103. public void EnableCullFace()
  104. {
  105. GL.Enable(EnableCap.CullFace);
  106. }
  107. public void DisableCullFace()
  108. {
  109. GL.Disable(EnableCap.CullFace);
  110. }
  111. public void SetCullFace(GalCullFace CullFace)
  112. {
  113. GL.CullFace(OGLEnumConverter.GetCullFace(CullFace));
  114. }
  115. public void EnableDepthTest()
  116. {
  117. GL.Enable(EnableCap.DepthTest);
  118. }
  119. public void DisableDepthTest()
  120. {
  121. GL.Disable(EnableCap.DepthTest);
  122. }
  123. public void SetDepthFunction(GalComparisonOp Func)
  124. {
  125. GL.DepthFunc(OGLEnumConverter.GetDepthFunc(Func));
  126. }
  127. public void SetClearDepth(float Depth)
  128. {
  129. GL.ClearDepth(Depth);
  130. }
  131. public void EnableStencilTest()
  132. {
  133. GL.Enable(EnableCap.StencilTest);
  134. }
  135. public void DisableStencilTest()
  136. {
  137. GL.Disable(EnableCap.StencilTest);
  138. }
  139. public void SetStencilFunction(bool IsFrontFace, GalComparisonOp Func, int Ref, int Mask)
  140. {
  141. GL.StencilFuncSeparate(
  142. IsFrontFace ? StencilFace.Front : StencilFace.Back,
  143. OGLEnumConverter.GetStencilFunc(Func),
  144. Ref,
  145. Mask);
  146. }
  147. public void SetStencilOp(bool IsFrontFace, GalStencilOp Fail, GalStencilOp ZFail, GalStencilOp ZPass)
  148. {
  149. GL.StencilOpSeparate(
  150. IsFrontFace ? StencilFace.Front : StencilFace.Back,
  151. OGLEnumConverter.GetStencilOp(Fail),
  152. OGLEnumConverter.GetStencilOp(ZFail),
  153. OGLEnumConverter.GetStencilOp(ZPass));
  154. }
  155. public void SetStencilMask(bool IsFrontFace, int Mask)
  156. {
  157. GL.StencilMaskSeparate(IsFrontFace ? StencilFace.Front : StencilFace.Back, Mask);
  158. }
  159. public void SetClearStencil(int Stencil)
  160. {
  161. GL.ClearStencil(Stencil);
  162. }
  163. public void EnablePrimitiveRestart()
  164. {
  165. GL.Enable(EnableCap.PrimitiveRestart);
  166. }
  167. public void DisablePrimitiveRestart()
  168. {
  169. GL.Disable(EnableCap.PrimitiveRestart);
  170. }
  171. public void SetPrimitiveRestartIndex(uint Index)
  172. {
  173. GL.PrimitiveRestartIndex(Index);
  174. }
  175. public void CreateVbo(long Key, byte[] Buffer)
  176. {
  177. int Handle = GL.GenBuffer();
  178. VboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length);
  179. IntPtr Length = new IntPtr(Buffer.Length);
  180. GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
  181. GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
  182. }
  183. public void CreateIbo(long Key, byte[] Buffer)
  184. {
  185. int Handle = GL.GenBuffer();
  186. IboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length);
  187. IntPtr Length = new IntPtr(Buffer.Length);
  188. GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
  189. GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
  190. }
  191. public void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs)
  192. {
  193. if (!VboCache.TryGetValue(VboKey, out int VboHandle))
  194. {
  195. return;
  196. }
  197. if (VaoHandle == 0)
  198. {
  199. VaoHandle = GL.GenVertexArray();
  200. }
  201. GL.BindVertexArray(VaoHandle);
  202. foreach (GalVertexAttrib Attrib in Attribs)
  203. {
  204. GL.EnableVertexAttribArray(Attrib.Index);
  205. GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
  206. bool Unsigned =
  207. Attrib.Type == GalVertexAttribType.Unorm ||
  208. Attrib.Type == GalVertexAttribType.Uint ||
  209. Attrib.Type == GalVertexAttribType.Uscaled;
  210. bool Normalize =
  211. Attrib.Type == GalVertexAttribType.Snorm ||
  212. Attrib.Type == GalVertexAttribType.Unorm;
  213. VertexAttribPointerType Type = 0;
  214. if (Attrib.Type == GalVertexAttribType.Float)
  215. {
  216. Type = VertexAttribPointerType.Float;
  217. }
  218. else
  219. {
  220. Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
  221. }
  222. int Size = AttribElements[Attrib.Size];
  223. int Offset = Attrib.Offset;
  224. GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Stride, Offset);
  225. }
  226. }
  227. public void SetIndexArray(int Size, GalIndexFormat Format)
  228. {
  229. IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
  230. IndexBuffer.Count = Size >> (int)Format;
  231. IndexBuffer.ElemSizeLog2 = (int)Format;
  232. }
  233. public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
  234. {
  235. if (PrimCount == 0)
  236. {
  237. return;
  238. }
  239. GL.BindVertexArray(VaoHandle);
  240. GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
  241. }
  242. public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
  243. {
  244. if (!IboCache.TryGetValue(IboKey, out int IboHandle))
  245. {
  246. return;
  247. }
  248. PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType);
  249. GL.BindVertexArray(VaoHandle);
  250. GL.BindBuffer(BufferTarget.ElementArrayBuffer, IboHandle);
  251. First <<= IndexBuffer.ElemSizeLog2;
  252. if (VertexBase != 0)
  253. {
  254. IntPtr Indices = new IntPtr(First);
  255. GL.DrawElementsBaseVertex(Mode, IndexBuffer.Count, IndexBuffer.Type, Indices, VertexBase);
  256. }
  257. else
  258. {
  259. GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First);
  260. }
  261. }
  262. }
  263. }