Pipeline.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using Ryujinx.Graphics.GAL.Blend;
  5. using Ryujinx.Graphics.GAL.Color;
  6. using Ryujinx.Graphics.GAL.DepthStencil;
  7. using Ryujinx.Graphics.GAL.InputAssembler;
  8. using Ryujinx.Graphics.Shader;
  9. using System;
  10. namespace Ryujinx.Graphics.OpenGL
  11. {
  12. class Pipeline : IPipeline
  13. {
  14. private Program _program;
  15. private VertexArray _vertexArray;
  16. private Framebuffer _framebuffer;
  17. private IntPtr _indexBaseOffset;
  18. private DrawElementsType _elementsType;
  19. private PrimitiveType _primitiveType;
  20. private int _stencilFrontMask;
  21. private bool _depthMask;
  22. private bool _depthTest;
  23. private bool _hasDepthBuffer;
  24. private TextureView _unit0Texture;
  25. private ClipOrigin _clipOrigin;
  26. private ClipDepthMode _clipDepthMode;
  27. private uint[] _componentMasks;
  28. internal Pipeline()
  29. {
  30. _clipOrigin = ClipOrigin.LowerLeft;
  31. _clipDepthMode = ClipDepthMode.NegativeOneToOne;
  32. }
  33. public void BindBlendState(int index, BlendDescriptor blend)
  34. {
  35. if (!blend.Enable)
  36. {
  37. GL.Disable(IndexedEnableCap.Blend, index);
  38. return;
  39. }
  40. GL.BlendEquationSeparate(
  41. index,
  42. blend.ColorOp.Convert(),
  43. blend.AlphaOp.Convert());
  44. GL.BlendFuncSeparate(
  45. index,
  46. (BlendingFactorSrc) blend.ColorSrcFactor.Convert(),
  47. (BlendingFactorDest)blend.ColorDstFactor.Convert(),
  48. (BlendingFactorSrc) blend.AlphaSrcFactor.Convert(),
  49. (BlendingFactorDest)blend.AlphaDstFactor.Convert());
  50. GL.Enable(IndexedEnableCap.Blend, index);
  51. }
  52. public void BindImage(int index, ShaderStage stage, ITexture texture)
  53. {
  54. int unit = _program.GetImageUnit(stage, index);
  55. if (unit != -1 && texture != null)
  56. {
  57. TextureView view = (TextureView)texture;
  58. FormatInfo formatInfo = FormatTable.GetFormatInfo(view.Format);
  59. SizedInternalFormat format = (SizedInternalFormat)formatInfo.PixelInternalFormat;
  60. GL.BindImageTexture(
  61. unit,
  62. view.Handle,
  63. 0,
  64. true,
  65. 0,
  66. TextureAccess.ReadWrite,
  67. format);
  68. }
  69. }
  70. public void BindIndexBuffer(BufferRange buffer, IndexType type)
  71. {
  72. _elementsType = type.Convert();
  73. _indexBaseOffset = (IntPtr)buffer.Offset;
  74. EnsureVertexArray();
  75. _vertexArray.SetIndexBuffer((Buffer)buffer.Buffer);
  76. }
  77. public void BindProgram(IProgram program)
  78. {
  79. _program = (Program)program;
  80. _program.Bind();
  81. }
  82. public void BindSampler(int index, ShaderStage stage, ISampler sampler)
  83. {
  84. int unit = _program.GetTextureUnit(stage, index);
  85. if (unit != -1 && sampler != null)
  86. {
  87. ((Sampler)sampler).Bind(unit);
  88. }
  89. else if (unit == -1)
  90. {
  91. Logger.PrintError(LogClass.Gpu, $"Invalid binding point: {stage} {index}.");
  92. }
  93. }
  94. public void BindTexture(int index, ShaderStage stage, ITexture texture)
  95. {
  96. int unit = _program.GetTextureUnit(stage, index);
  97. if (unit != -1 && texture != null)
  98. {
  99. if (unit == 0)
  100. {
  101. _unit0Texture = ((TextureView)texture);
  102. }
  103. else
  104. {
  105. ((TextureView)texture).Bind(unit);
  106. }
  107. }
  108. else if (unit == -1)
  109. {
  110. Logger.PrintError(LogClass.Gpu, $"Invalid binding point: {stage} {index}.");
  111. }
  112. }
  113. public void BindStorageBuffer(int index, ShaderStage stage, BufferRange buffer)
  114. {
  115. BindBuffer(index, stage, buffer, isStorage: true);
  116. }
  117. public void BindUniformBuffer(int index, ShaderStage stage, BufferRange buffer)
  118. {
  119. BindBuffer(index, stage, buffer, isStorage: false);
  120. }
  121. private void BindBuffer(int index, ShaderStage stage, BufferRange buffer, bool isStorage)
  122. {
  123. int bindingPoint = isStorage
  124. ? _program.GetStorageBufferBindingPoint(stage, index)
  125. : _program.GetUniformBufferBindingPoint(stage, index);
  126. if (bindingPoint == -1)
  127. {
  128. Logger.PrintError(LogClass.Gpu, $"Invalid binding point: {stage} {index}.");
  129. return;
  130. }
  131. BufferRangeTarget target = isStorage
  132. ? BufferRangeTarget.ShaderStorageBuffer
  133. : BufferRangeTarget.UniformBuffer;
  134. if (buffer.Buffer == null)
  135. {
  136. GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
  137. return;
  138. }
  139. int bufferHandle = ((Buffer)buffer.Buffer).Handle;
  140. IntPtr bufferOffset = (IntPtr)buffer.Offset;
  141. GL.BindBufferRange(
  142. target,
  143. bindingPoint,
  144. bufferHandle,
  145. bufferOffset,
  146. buffer.Size);
  147. }
  148. public void BindVertexAttribs(VertexAttribDescriptor[] vertexAttribs)
  149. {
  150. EnsureVertexArray();
  151. _vertexArray.SetVertexAttributes(vertexAttribs);
  152. }
  153. public void BindVertexBuffers(VertexBufferDescriptor[] vertexBuffers)
  154. {
  155. EnsureVertexArray();
  156. _vertexArray.SetVertexBuffers(vertexBuffers);
  157. }
  158. public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
  159. {
  160. GL.ColorMask(
  161. index,
  162. (componentMask & 1) != 0,
  163. (componentMask & 2) != 0,
  164. (componentMask & 4) != 0,
  165. (componentMask & 8) != 0);
  166. float[] colors = new float[] { color.Red, color.Green, color.Blue, color.Alpha };
  167. GL.ClearBuffer(ClearBuffer.Color, index, colors);
  168. RestoreComponentMask(index);
  169. }
  170. public void ClearRenderTargetColor(int index, uint componentMask, ColorSI color)
  171. {
  172. GL.ColorMask(
  173. index,
  174. (componentMask & 1u) != 0,
  175. (componentMask & 2u) != 0,
  176. (componentMask & 4u) != 0,
  177. (componentMask & 8u) != 0);
  178. int[] colors = new int[] { color.Red, color.Green, color.Blue, color.Alpha };
  179. GL.ClearBuffer(ClearBuffer.Color, index, colors);
  180. RestoreComponentMask(index);
  181. }
  182. public void ClearRenderTargetColor(int index, uint componentMask, ColorUI color)
  183. {
  184. GL.ColorMask(
  185. index,
  186. (componentMask & 1u) != 0,
  187. (componentMask & 2u) != 0,
  188. (componentMask & 4u) != 0,
  189. (componentMask & 8u) != 0);
  190. uint[] colors = new uint[] { color.Red, color.Green, color.Blue, color.Alpha };
  191. GL.ClearBuffer(ClearBuffer.Color, index, colors);
  192. RestoreComponentMask(index);
  193. }
  194. public void ClearRenderTargetDepthStencil(
  195. float depthValue,
  196. bool depthMask,
  197. int stencilValue,
  198. int stencilMask)
  199. {
  200. bool stencilMaskChanged =
  201. stencilMask != 0 &&
  202. stencilMask != _stencilFrontMask;
  203. bool depthMaskChanged = depthMask && depthMask != _depthMask;
  204. if (stencilMaskChanged)
  205. {
  206. GL.StencilMaskSeparate(StencilFace.Front, stencilMask);
  207. }
  208. if (depthMaskChanged)
  209. {
  210. GL.DepthMask(depthMask);
  211. }
  212. if (depthMask && stencilMask != 0)
  213. {
  214. GL.ClearBuffer(ClearBufferCombined.DepthStencil, 0, depthValue, stencilValue);
  215. }
  216. else if (depthMask)
  217. {
  218. GL.ClearBuffer(ClearBuffer.Depth, 0, ref depthValue);
  219. }
  220. else if (stencilMask != 0)
  221. {
  222. GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencilValue);
  223. }
  224. if (stencilMaskChanged)
  225. {
  226. GL.StencilMaskSeparate(StencilFace.Front, _stencilFrontMask);
  227. }
  228. if (depthMaskChanged)
  229. {
  230. GL.DepthMask(_depthMask);
  231. }
  232. }
  233. public void Dispatch(int groupsX, int groupsY, int groupsZ)
  234. {
  235. if (!_program.IsLinked)
  236. {
  237. Logger.PrintError(LogClass.Gpu, "Dispatch error, shader not linked.");
  238. return;
  239. }
  240. PrepareForDispatch();
  241. GL.DispatchCompute(groupsX, groupsY, groupsZ);
  242. }
  243. public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
  244. {
  245. if (!_program.IsLinked)
  246. {
  247. Logger.PrintError(LogClass.Gpu, "Draw error, shader not linked.");
  248. return;
  249. }
  250. PrepareForDraw();
  251. if (_primitiveType == PrimitiveType.Quads)
  252. {
  253. DrawQuadsImpl(vertexCount, instanceCount, firstVertex, firstInstance);
  254. }
  255. else if (_primitiveType == PrimitiveType.QuadStrip)
  256. {
  257. DrawQuadStripImpl(vertexCount, instanceCount, firstVertex, firstInstance);
  258. }
  259. else
  260. {
  261. DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
  262. }
  263. }
  264. private void DrawQuadsImpl(
  265. int vertexCount,
  266. int instanceCount,
  267. int firstVertex,
  268. int firstInstance)
  269. {
  270. // TODO: Instanced rendering.
  271. int quadsCount = vertexCount / 4;
  272. int[] firsts = new int[quadsCount];
  273. int[] counts = new int[quadsCount];
  274. for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
  275. {
  276. firsts[quadIndex] = firstVertex + quadIndex * 4;
  277. counts[quadIndex] = 4;
  278. }
  279. GL.MultiDrawArrays(
  280. PrimitiveType.TriangleFan,
  281. firsts,
  282. counts,
  283. quadsCount);
  284. }
  285. private void DrawQuadStripImpl(
  286. int vertexCount,
  287. int instanceCount,
  288. int firstVertex,
  289. int firstInstance)
  290. {
  291. // TODO: Instanced rendering.
  292. int quadsCount = (vertexCount - 2) / 2;
  293. int[] firsts = new int[quadsCount];
  294. int[] counts = new int[quadsCount];
  295. firsts[0] = firstVertex;
  296. counts[0] = 4;
  297. for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++)
  298. {
  299. firsts[quadIndex] = firstVertex + quadIndex * 2;
  300. counts[quadIndex] = 4;
  301. }
  302. GL.MultiDrawArrays(
  303. PrimitiveType.TriangleFan,
  304. firsts,
  305. counts,
  306. quadsCount);
  307. }
  308. private void DrawImpl(
  309. int vertexCount,
  310. int instanceCount,
  311. int firstVertex,
  312. int firstInstance)
  313. {
  314. if (firstInstance == 0 && instanceCount == 1)
  315. {
  316. GL.DrawArrays(_primitiveType, firstVertex, vertexCount);
  317. }
  318. else if (firstInstance == 0)
  319. {
  320. GL.DrawArraysInstanced(_primitiveType, firstVertex, vertexCount, instanceCount);
  321. }
  322. else
  323. {
  324. GL.DrawArraysInstancedBaseInstance(
  325. _primitiveType,
  326. firstVertex,
  327. vertexCount,
  328. instanceCount,
  329. firstInstance);
  330. }
  331. }
  332. public void DrawIndexed(
  333. int indexCount,
  334. int instanceCount,
  335. int firstIndex,
  336. int firstVertex,
  337. int firstInstance)
  338. {
  339. if (!_program.IsLinked)
  340. {
  341. Logger.PrintError(LogClass.Gpu, "Draw error, shader not linked.");
  342. return;
  343. }
  344. PrepareForDraw();
  345. int indexElemSize = 1;
  346. switch (_elementsType)
  347. {
  348. case DrawElementsType.UnsignedShort: indexElemSize = 2; break;
  349. case DrawElementsType.UnsignedInt: indexElemSize = 4; break;
  350. }
  351. IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize;
  352. if (_primitiveType == PrimitiveType.Quads)
  353. {
  354. DrawQuadsIndexedImpl(
  355. indexCount,
  356. instanceCount,
  357. indexBaseOffset,
  358. indexElemSize,
  359. firstVertex,
  360. firstInstance);
  361. }
  362. else if (_primitiveType == PrimitiveType.QuadStrip)
  363. {
  364. DrawQuadStripIndexedImpl(
  365. indexCount,
  366. instanceCount,
  367. indexBaseOffset,
  368. indexElemSize,
  369. firstVertex,
  370. firstInstance);
  371. }
  372. else
  373. {
  374. DrawIndexedImpl(
  375. indexCount,
  376. instanceCount,
  377. indexBaseOffset,
  378. firstVertex,
  379. firstInstance);
  380. }
  381. }
  382. private void DrawQuadsIndexedImpl(
  383. int indexCount,
  384. int instanceCount,
  385. IntPtr indexBaseOffset,
  386. int indexElemSize,
  387. int firstVertex,
  388. int firstInstance)
  389. {
  390. // TODO: Instanced rendering.
  391. int quadsCount = indexCount / 4;
  392. IntPtr[] indices = new IntPtr[quadsCount];
  393. int[] counts = new int[quadsCount];
  394. int[] baseVertices = new int[quadsCount];
  395. for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
  396. {
  397. indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize;
  398. counts[quadIndex] = 4;
  399. baseVertices[quadIndex] = firstVertex;
  400. }
  401. GL.MultiDrawElementsBaseVertex(
  402. PrimitiveType.TriangleFan,
  403. counts,
  404. _elementsType,
  405. indices,
  406. quadsCount,
  407. baseVertices);
  408. }
  409. private void DrawQuadStripIndexedImpl(
  410. int indexCount,
  411. int instanceCount,
  412. IntPtr indexBaseOffset,
  413. int indexElemSize,
  414. int firstVertex,
  415. int firstInstance)
  416. {
  417. // TODO: Instanced rendering.
  418. int quadsCount = (indexCount - 2) / 2;
  419. IntPtr[] indices = new IntPtr[quadsCount];
  420. int[] counts = new int[quadsCount];
  421. int[] baseVertices = new int[quadsCount];
  422. indices[0] = indexBaseOffset;
  423. counts[0] = 4;
  424. baseVertices[0] = firstVertex;
  425. for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++)
  426. {
  427. indices[quadIndex] = indexBaseOffset + quadIndex * 2 * indexElemSize;
  428. counts[quadIndex] = 4;
  429. baseVertices[quadIndex] = firstVertex;
  430. }
  431. GL.MultiDrawElementsBaseVertex(
  432. PrimitiveType.TriangleFan,
  433. counts,
  434. _elementsType,
  435. indices,
  436. quadsCount,
  437. baseVertices);
  438. }
  439. private void DrawIndexedImpl(
  440. int indexCount,
  441. int instanceCount,
  442. IntPtr indexBaseOffset,
  443. int firstVertex,
  444. int firstInstance)
  445. {
  446. if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1)
  447. {
  448. GL.DrawElements(_primitiveType, indexCount, _elementsType, indexBaseOffset);
  449. }
  450. else if (firstInstance == 0 && instanceCount == 1)
  451. {
  452. GL.DrawElementsBaseVertex(
  453. _primitiveType,
  454. indexCount,
  455. _elementsType,
  456. indexBaseOffset,
  457. firstVertex);
  458. }
  459. else if (firstInstance == 0 && firstVertex == 0)
  460. {
  461. GL.DrawElementsInstanced(
  462. _primitiveType,
  463. indexCount,
  464. _elementsType,
  465. indexBaseOffset,
  466. instanceCount);
  467. }
  468. else if (firstInstance == 0)
  469. {
  470. GL.DrawElementsInstancedBaseVertex(
  471. _primitiveType,
  472. indexCount,
  473. _elementsType,
  474. indexBaseOffset,
  475. instanceCount,
  476. firstVertex);
  477. }
  478. else if (firstVertex == 0)
  479. {
  480. GL.DrawElementsInstancedBaseInstance(
  481. _primitiveType,
  482. indexCount,
  483. _elementsType,
  484. indexBaseOffset,
  485. instanceCount,
  486. firstInstance);
  487. }
  488. else
  489. {
  490. GL.DrawElementsInstancedBaseVertexBaseInstance(
  491. _primitiveType,
  492. indexCount,
  493. _elementsType,
  494. indexBaseOffset,
  495. instanceCount,
  496. firstVertex,
  497. firstInstance);
  498. }
  499. }
  500. public void DrawIndirect(BufferRange buffer, ulong offset, int drawCount, int stride)
  501. {
  502. }
  503. public void DrawIndexedIndirect(BufferRange buffer, ulong offset, int drawCount, int stride)
  504. {
  505. }
  506. public void SetBlendColor(ColorF color)
  507. {
  508. GL.BlendColor(color.Red, color.Green, color.Blue, color.Alpha);
  509. }
  510. public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
  511. {
  512. if ((enables & PolygonModeMask.Point) != 0)
  513. {
  514. GL.Enable(EnableCap.PolygonOffsetPoint);
  515. }
  516. else
  517. {
  518. GL.Disable(EnableCap.PolygonOffsetPoint);
  519. }
  520. if ((enables & PolygonModeMask.Line) != 0)
  521. {
  522. GL.Enable(EnableCap.PolygonOffsetLine);
  523. }
  524. else
  525. {
  526. GL.Disable(EnableCap.PolygonOffsetLine);
  527. }
  528. if ((enables & PolygonModeMask.Fill) != 0)
  529. {
  530. GL.Enable(EnableCap.PolygonOffsetFill);
  531. }
  532. else
  533. {
  534. GL.Disable(EnableCap.PolygonOffsetFill);
  535. }
  536. if (enables == 0)
  537. {
  538. return;
  539. }
  540. GL.PolygonOffset(factor, units);
  541. // GL.PolygonOffsetClamp(factor, units, clamp);
  542. }
  543. public void SetDepthMode(DepthMode mode)
  544. {
  545. ClipDepthMode depthMode = mode.Convert();
  546. if (_clipDepthMode != depthMode)
  547. {
  548. _clipDepthMode = depthMode;
  549. GL.ClipControl(_clipOrigin, depthMode);
  550. }
  551. }
  552. public void SetDepthTest(DepthTestDescriptor depthTest)
  553. {
  554. GL.DepthFunc((DepthFunction)depthTest.Func.Convert());
  555. _depthMask = depthTest.WriteEnable;
  556. _depthTest = depthTest.TestEnable;
  557. UpdateDepthTest();
  558. }
  559. public void SetFaceCulling(bool enable, Face face)
  560. {
  561. if (!enable)
  562. {
  563. GL.Disable(EnableCap.CullFace);
  564. return;
  565. }
  566. GL.CullFace(face.Convert());
  567. GL.Enable(EnableCap.CullFace);
  568. }
  569. public void SetFrontFace(FrontFace frontFace)
  570. {
  571. GL.FrontFace(frontFace.Convert());
  572. }
  573. public void SetPrimitiveRestart(bool enable, int index)
  574. {
  575. if (!enable)
  576. {
  577. GL.Disable(EnableCap.PrimitiveRestart);
  578. return;
  579. }
  580. GL.PrimitiveRestartIndex(index);
  581. GL.Enable(EnableCap.PrimitiveRestart);
  582. }
  583. public void SetPrimitiveTopology(PrimitiveTopology topology)
  584. {
  585. _primitiveType = topology.Convert();
  586. }
  587. public void SetRenderTargetColorMasks(uint[] componentMasks)
  588. {
  589. _componentMasks = (uint[])componentMasks.Clone();
  590. for (int index = 0; index < componentMasks.Length; index++)
  591. {
  592. RestoreComponentMask(index);
  593. }
  594. }
  595. public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
  596. {
  597. EnsureFramebuffer();
  598. for (int index = 0; index < colors.Length; index++)
  599. {
  600. TextureView color = (TextureView)colors[index];
  601. _framebuffer.AttachColor(index, color);
  602. }
  603. TextureView depthStencilView = (TextureView)depthStencil;
  604. _framebuffer.AttachDepthStencil(depthStencilView);
  605. _framebuffer.SetDrawBuffers(colors.Length);
  606. _hasDepthBuffer = depthStencil != null && depthStencilView.Format != Format.S8Uint;
  607. UpdateDepthTest();
  608. }
  609. public void SetStencilTest(StencilTestDescriptor stencilTest)
  610. {
  611. if (!stencilTest.TestEnable)
  612. {
  613. GL.Disable(EnableCap.StencilTest);
  614. return;
  615. }
  616. GL.StencilOpSeparate(
  617. StencilFace.Front,
  618. stencilTest.FrontSFail.Convert(),
  619. stencilTest.FrontDpFail.Convert(),
  620. stencilTest.FrontDpPass.Convert());
  621. GL.StencilFuncSeparate(
  622. StencilFace.Front,
  623. (StencilFunction)stencilTest.FrontFunc.Convert(),
  624. stencilTest.FrontFuncRef,
  625. stencilTest.FrontFuncMask);
  626. GL.StencilMaskSeparate(StencilFace.Front, stencilTest.FrontMask);
  627. GL.StencilOpSeparate(
  628. StencilFace.Back,
  629. stencilTest.BackSFail.Convert(),
  630. stencilTest.BackDpFail.Convert(),
  631. stencilTest.BackDpPass.Convert());
  632. GL.StencilFuncSeparate(
  633. StencilFace.Back,
  634. (StencilFunction)stencilTest.BackFunc.Convert(),
  635. stencilTest.BackFuncRef,
  636. stencilTest.BackFuncMask);
  637. GL.StencilMaskSeparate(StencilFace.Back, stencilTest.BackMask);
  638. GL.Enable(EnableCap.StencilTest);
  639. _stencilFrontMask = stencilTest.FrontMask;
  640. }
  641. public void SetViewports(int first, Viewport[] viewports)
  642. {
  643. bool flipY = false;
  644. float[] viewportArray = new float[viewports.Length * 4];
  645. double[] depthRangeArray = new double[viewports.Length * 2];
  646. for (int index = 0; index < viewports.Length; index++)
  647. {
  648. int viewportElemIndex = index * 4;
  649. Viewport viewport = viewports[index];
  650. viewportArray[viewportElemIndex + 0] = viewport.Region.X;
  651. viewportArray[viewportElemIndex + 1] = viewport.Region.Y;
  652. // OpenGL does not support per-viewport flipping, so
  653. // instead we decide that based on the viewport 0 value.
  654. // It will apply to all viewports.
  655. if (index == 0)
  656. {
  657. flipY = viewport.Region.Height < 0;
  658. }
  659. if (viewport.SwizzleY == ViewportSwizzle.NegativeY)
  660. {
  661. flipY = !flipY;
  662. }
  663. viewportArray[viewportElemIndex + 2] = MathF.Abs(viewport.Region.Width);
  664. viewportArray[viewportElemIndex + 3] = MathF.Abs(viewport.Region.Height);
  665. depthRangeArray[index * 2 + 0] = viewport.DepthNear;
  666. depthRangeArray[index * 2 + 1] = viewport.DepthFar;
  667. }
  668. GL.ViewportArray(first, viewports.Length, viewportArray);
  669. GL.DepthRangeArray(first, viewports.Length, depthRangeArray);
  670. SetOrigin(flipY ? ClipOrigin.UpperLeft : ClipOrigin.LowerLeft);
  671. }
  672. public void TextureBarrier()
  673. {
  674. GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
  675. }
  676. public void TextureBarrierTiled()
  677. {
  678. GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
  679. }
  680. private void SetOrigin(ClipOrigin origin)
  681. {
  682. if (_clipOrigin != origin)
  683. {
  684. _clipOrigin = origin;
  685. GL.ClipControl(origin, _clipDepthMode);
  686. }
  687. }
  688. private void EnsureVertexArray()
  689. {
  690. if (_vertexArray == null)
  691. {
  692. _vertexArray = new VertexArray();
  693. _vertexArray.Bind();
  694. }
  695. }
  696. private void EnsureFramebuffer()
  697. {
  698. if (_framebuffer == null)
  699. {
  700. _framebuffer = new Framebuffer();
  701. _framebuffer.Bind();
  702. GL.Enable(EnableCap.FramebufferSrgb);
  703. }
  704. }
  705. private void UpdateDepthTest()
  706. {
  707. // Enabling depth operations is only valid when we have
  708. // a depth buffer, otherwise it's not allowed.
  709. if (_hasDepthBuffer)
  710. {
  711. if (_depthTest)
  712. {
  713. GL.Enable(EnableCap.DepthTest);
  714. }
  715. else
  716. {
  717. GL.Disable(EnableCap.DepthTest);
  718. }
  719. GL.DepthMask(_depthMask);
  720. }
  721. else
  722. {
  723. GL.Disable(EnableCap.DepthTest);
  724. GL.DepthMask(false);
  725. }
  726. }
  727. private void PrepareForDispatch()
  728. {
  729. if (_unit0Texture != null)
  730. {
  731. _unit0Texture.Bind(0);
  732. }
  733. }
  734. private void PrepareForDraw()
  735. {
  736. _vertexArray.Validate();
  737. if (_unit0Texture != null)
  738. {
  739. _unit0Texture.Bind(0);
  740. }
  741. }
  742. private void RestoreComponentMask(int index)
  743. {
  744. if (_componentMasks != null)
  745. {
  746. GL.ColorMask(
  747. index,
  748. (_componentMasks[index] & 1u) != 0,
  749. (_componentMasks[index] & 2u) != 0,
  750. (_componentMasks[index] & 4u) != 0,
  751. (_componentMasks[index] & 8u) != 0);
  752. }
  753. }
  754. }
  755. }