GraphicsPipeline.cs 25 KB

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