Pipeline.cs
1 using OpenTK.Graphics.OpenGL; 2 using Ryujinx.Common.Logging; 3 using Ryujinx.Graphics.GAL; 4 using Ryujinx.Graphics.OpenGL.Image; 5 using Ryujinx.Graphics.OpenGL.Queries; 6 using Ryujinx.Graphics.Shader; 7 using System; 8 9 namespace Ryujinx.Graphics.OpenGL 10 { 11 class Pipeline : IPipeline, IDisposable 12 { 13 private const int SavedImages = 2; 14 15 private readonly DrawTextureEmulation _drawTexture; 16 17 internal ulong DrawCount { get; private set; } 18 19 private Program _program; 20 21 private bool _rasterizerDiscard; 22 23 private VertexArray _vertexArray; 24 private Framebuffer _framebuffer; 25 26 private IntPtr _indexBaseOffset; 27 28 private DrawElementsType _elementsType; 29 30 private PrimitiveType _primitiveType; 31 32 private int _stencilFrontMask; 33 private bool _depthMask; 34 private bool _depthTestEnable; 35 private bool _stencilTestEnable; 36 private bool _cullEnable; 37 38 private float[] _viewportArray = Array.Empty<float>(); 39 private double[] _depthRangeArray = Array.Empty<double>(); 40 41 private int _boundDrawFramebuffer; 42 private int _boundReadFramebuffer; 43 44 private CounterQueueEvent _activeConditionalRender; 45 46 private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount]; 47 48 private readonly TextureBase[] _images; 49 private TextureBase _unit0Texture; 50 private Sampler _unit0Sampler; 51 52 private FrontFaceDirection _frontFace; 53 private ClipOrigin _clipOrigin; 54 private ClipDepthMode _clipDepthMode; 55 56 private uint _fragmentOutputMap; 57 private uint _componentMasks; 58 private uint _currentComponentMasks; 59 private bool _advancedBlendEnable; 60 61 private uint _scissorEnables; 62 63 private bool _tfEnabled; 64 private TransformFeedbackPrimitiveType _tfTopology; 65 66 private readonly BufferHandle[] _tfbs; 67 private readonly BufferRange[] _tfbTargets; 68 69 private ColorF _blendConstant; 70 71 internal Pipeline() 72 { 73 _drawTexture = new DrawTextureEmulation(); 74 _rasterizerDiscard = false; 75 _clipOrigin = ClipOrigin.LowerLeft; 76 _clipDepthMode = ClipDepthMode.NegativeOneToOne; 77 78 _fragmentOutputMap = uint.MaxValue; 79 _componentMasks = uint.MaxValue; 80 81 _images = new TextureBase[SavedImages]; 82 83 _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers]; 84 _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers]; 85 } 86 87 public void Barrier() 88 { 89 GL.MemoryBarrier(MemoryBarrierFlags.AllBarrierBits); 90 } 91 92 public void BeginTransformFeedback(PrimitiveTopology topology) 93 { 94 GL.BeginTransformFeedback(_tfTopology = topology.ConvertToTfType()); 95 _tfEnabled = true; 96 } 97 98 public void ClearBuffer(BufferHandle destination, int offset, int size, uint value) 99 { 100 Buffer.Clear(destination, offset, size, value); 101 } 102 103 public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color) 104 { 105 EnsureFramebuffer(); 106 107 GL.ColorMask( 108 index, 109 (componentMask & 1) != 0, 110 (componentMask & 2) != 0, 111 (componentMask & 4) != 0, 112 (componentMask & 8) != 0); 113 114 float[] colors = new float[] { color.Red, color.Green, color.Blue, color.Alpha }; 115 116 if (layer != 0 || layerCount != _framebuffer.GetColorLayerCount(index)) 117 { 118 for (int l = layer; l < layer + layerCount; l++) 119 { 120 _framebuffer.AttachColorLayerForClear(index, l); 121 122 GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Color, index, colors); 123 } 124 125 _framebuffer.DetachColorLayerForClear(index); 126 } 127 else 128 { 129 GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Color, index, colors); 130 } 131 132 RestoreComponentMask(index); 133 } 134 135 public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask) 136 { 137 EnsureFramebuffer(); 138 139 bool stencilMaskChanged = 140 stencilMask != 0 && 141 stencilMask != _stencilFrontMask; 142 143 bool depthMaskChanged = depthMask && depthMask != _depthMask; 144 145 if (stencilMaskChanged) 146 { 147 GL.StencilMaskSeparate(StencilFace.Front, stencilMask); 148 } 149 150 if (depthMaskChanged) 151 { 152 GL.DepthMask(depthMask); 153 } 154 155 if (layer != 0 || layerCount != _framebuffer.GetDepthStencilLayerCount()) 156 { 157 for (int l = layer; l < layer + layerCount; l++) 158 { 159 _framebuffer.AttachDepthStencilLayerForClear(l); 160 161 ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask); 162 } 163 164 _framebuffer.DetachDepthStencilLayerForClear(); 165 } 166 else 167 { 168 ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask); 169 } 170 171 if (stencilMaskChanged) 172 { 173 GL.StencilMaskSeparate(StencilFace.Front, _stencilFrontMask); 174 } 175 176 if (depthMaskChanged) 177 { 178 GL.DepthMask(_depthMask); 179 } 180 } 181 182 private static void ClearDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask) 183 { 184 if (depthMask && stencilMask != 0) 185 { 186 GL.ClearBuffer(ClearBufferCombined.DepthStencil, 0, depthValue, stencilValue); 187 } 188 else if (depthMask) 189 { 190 GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Depth, 0, ref depthValue); 191 } 192 else if (stencilMask != 0) 193 { 194 GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Stencil, 0, ref stencilValue); 195 } 196 } 197 198 public void CommandBufferBarrier() 199 { 200 GL.MemoryBarrier(MemoryBarrierFlags.CommandBarrierBit); 201 } 202 203 public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size) 204 { 205 Buffer.Copy(source, destination, srcOffset, dstOffset, size); 206 } 207 208 public void DispatchCompute(int groupsX, int groupsY, int groupsZ) 209 { 210 if (!_program.IsLinked) 211 { 212 Logger.Debug?.Print(LogClass.Gpu, "Dispatch error, shader not linked."); 213 return; 214 } 215 216 PrepareForDispatch(); 217 218 GL.DispatchCompute(groupsX, groupsY, groupsZ); 219 } 220 221 public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) 222 { 223 if (!_program.IsLinked) 224 { 225 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 226 return; 227 } 228 229 PreDraw(vertexCount); 230 231 if (_primitiveType == PrimitiveType.Quads && !HwCapabilities.SupportsQuads) 232 { 233 DrawQuadsImpl(vertexCount, instanceCount, firstVertex, firstInstance); 234 } 235 else if (_primitiveType == PrimitiveType.QuadStrip && !HwCapabilities.SupportsQuads) 236 { 237 DrawQuadStripImpl(vertexCount, instanceCount, firstVertex, firstInstance); 238 } 239 else 240 { 241 DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance); 242 } 243 244 PostDraw(); 245 } 246 247 private static void DrawQuadsImpl( 248 int vertexCount, 249 int instanceCount, 250 int firstVertex, 251 int firstInstance) 252 { 253 // TODO: Instanced rendering. 254 int quadsCount = vertexCount / 4; 255 256 int[] firsts = new int[quadsCount]; 257 int[] counts = new int[quadsCount]; 258 259 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 260 { 261 firsts[quadIndex] = firstVertex + quadIndex * 4; 262 counts[quadIndex] = 4; 263 } 264 265 GL.MultiDrawArrays( 266 PrimitiveType.TriangleFan, 267 firsts, 268 counts, 269 quadsCount); 270 } 271 272 private static void DrawQuadStripImpl( 273 int vertexCount, 274 int instanceCount, 275 int firstVertex, 276 int firstInstance) 277 { 278 int quadsCount = (vertexCount - 2) / 2; 279 280 if (firstInstance != 0 || instanceCount != 1) 281 { 282 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 283 { 284 GL.DrawArraysInstancedBaseInstance(PrimitiveType.TriangleFan, firstVertex + quadIndex * 2, 4, instanceCount, firstInstance); 285 } 286 } 287 else 288 { 289 int[] firsts = new int[quadsCount]; 290 int[] counts = new int[quadsCount]; 291 292 firsts[0] = firstVertex; 293 counts[0] = 4; 294 295 for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) 296 { 297 firsts[quadIndex] = firstVertex + quadIndex * 2; 298 counts[quadIndex] = 4; 299 } 300 301 GL.MultiDrawArrays( 302 PrimitiveType.TriangleFan, 303 firsts, 304 counts, 305 quadsCount); 306 } 307 } 308 309 private void DrawImpl( 310 int vertexCount, 311 int instanceCount, 312 int firstVertex, 313 int firstInstance) 314 { 315 if (firstInstance == 0 && instanceCount == 1) 316 { 317 GL.DrawArrays(_primitiveType, firstVertex, vertexCount); 318 } 319 else if (firstInstance == 0) 320 { 321 GL.DrawArraysInstanced(_primitiveType, firstVertex, vertexCount, instanceCount); 322 } 323 else 324 { 325 GL.DrawArraysInstancedBaseInstance( 326 _primitiveType, 327 firstVertex, 328 vertexCount, 329 instanceCount, 330 firstInstance); 331 } 332 } 333 334 public void DrawIndexed( 335 int indexCount, 336 int instanceCount, 337 int firstIndex, 338 int firstVertex, 339 int firstInstance) 340 { 341 if (!_program.IsLinked) 342 { 343 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 344 return; 345 } 346 347 PreDrawVbUnbounded(); 348 349 int indexElemSize = 1; 350 351 switch (_elementsType) 352 { 353 case DrawElementsType.UnsignedShort: 354 indexElemSize = 2; 355 break; 356 case DrawElementsType.UnsignedInt: 357 indexElemSize = 4; 358 break; 359 } 360 361 IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize; 362 363 if (_primitiveType == PrimitiveType.Quads && !HwCapabilities.SupportsQuads) 364 { 365 DrawQuadsIndexedImpl( 366 indexCount, 367 instanceCount, 368 indexBaseOffset, 369 indexElemSize, 370 firstVertex, 371 firstInstance); 372 } 373 else if (_primitiveType == PrimitiveType.QuadStrip && !HwCapabilities.SupportsQuads) 374 { 375 DrawQuadStripIndexedImpl( 376 indexCount, 377 instanceCount, 378 indexBaseOffset, 379 indexElemSize, 380 firstVertex, 381 firstInstance); 382 } 383 else 384 { 385 DrawIndexedImpl( 386 indexCount, 387 instanceCount, 388 indexBaseOffset, 389 firstVertex, 390 firstInstance); 391 } 392 393 PostDraw(); 394 } 395 396 private void DrawQuadsIndexedImpl( 397 int indexCount, 398 int instanceCount, 399 IntPtr indexBaseOffset, 400 int indexElemSize, 401 int firstVertex, 402 int firstInstance) 403 { 404 int quadsCount = indexCount / 4; 405 406 if (firstInstance != 0 || instanceCount != 1) 407 { 408 if (firstVertex != 0 && firstInstance != 0) 409 { 410 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 411 { 412 GL.DrawElementsInstancedBaseVertexBaseInstance( 413 PrimitiveType.TriangleFan, 414 4, 415 _elementsType, 416 indexBaseOffset + quadIndex * 4 * indexElemSize, 417 instanceCount, 418 firstVertex, 419 firstInstance); 420 } 421 } 422 else if (firstInstance != 0) 423 { 424 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 425 { 426 GL.DrawElementsInstancedBaseInstance( 427 PrimitiveType.TriangleFan, 428 4, 429 _elementsType, 430 indexBaseOffset + quadIndex * 4 * indexElemSize, 431 instanceCount, 432 firstInstance); 433 } 434 } 435 else 436 { 437 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 438 { 439 GL.DrawElementsInstanced( 440 PrimitiveType.TriangleFan, 441 4, 442 _elementsType, 443 indexBaseOffset + quadIndex * 4 * indexElemSize, 444 instanceCount); 445 } 446 } 447 } 448 else 449 { 450 IntPtr[] indices = new IntPtr[quadsCount]; 451 452 int[] counts = new int[quadsCount]; 453 454 int[] baseVertices = new int[quadsCount]; 455 456 for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) 457 { 458 indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize; 459 460 counts[quadIndex] = 4; 461 462 baseVertices[quadIndex] = firstVertex; 463 } 464 465 GL.MultiDrawElementsBaseVertex( 466 PrimitiveType.TriangleFan, 467 counts, 468 _elementsType, 469 indices, 470 quadsCount, 471 baseVertices); 472 } 473 } 474 475 private void DrawQuadStripIndexedImpl( 476 int indexCount, 477 int instanceCount, 478 IntPtr indexBaseOffset, 479 int indexElemSize, 480 int firstVertex, 481 int firstInstance) 482 { 483 // TODO: Instanced rendering. 484 int quadsCount = (indexCount - 2) / 2; 485 486 IntPtr[] indices = new IntPtr[quadsCount]; 487 488 int[] counts = new int[quadsCount]; 489 490 int[] baseVertices = new int[quadsCount]; 491 492 indices[0] = indexBaseOffset; 493 494 counts[0] = 4; 495 496 baseVertices[0] = firstVertex; 497 498 for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) 499 { 500 indices[quadIndex] = indexBaseOffset + quadIndex * 2 * indexElemSize; 501 502 counts[quadIndex] = 4; 503 504 baseVertices[quadIndex] = firstVertex; 505 } 506 507 GL.MultiDrawElementsBaseVertex( 508 PrimitiveType.TriangleFan, 509 counts, 510 _elementsType, 511 indices, 512 quadsCount, 513 baseVertices); 514 } 515 516 private void DrawIndexedImpl( 517 int indexCount, 518 int instanceCount, 519 IntPtr indexBaseOffset, 520 int firstVertex, 521 int firstInstance) 522 { 523 if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1) 524 { 525 GL.DrawElements(_primitiveType, indexCount, _elementsType, indexBaseOffset); 526 } 527 else if (firstInstance == 0 && instanceCount == 1) 528 { 529 GL.DrawElementsBaseVertex( 530 _primitiveType, 531 indexCount, 532 _elementsType, 533 indexBaseOffset, 534 firstVertex); 535 } 536 else if (firstInstance == 0 && firstVertex == 0) 537 { 538 GL.DrawElementsInstanced( 539 _primitiveType, 540 indexCount, 541 _elementsType, 542 indexBaseOffset, 543 instanceCount); 544 } 545 else if (firstInstance == 0) 546 { 547 GL.DrawElementsInstancedBaseVertex( 548 _primitiveType, 549 indexCount, 550 _elementsType, 551 indexBaseOffset, 552 instanceCount, 553 firstVertex); 554 } 555 else if (firstVertex == 0) 556 { 557 GL.DrawElementsInstancedBaseInstance( 558 _primitiveType, 559 indexCount, 560 _elementsType, 561 indexBaseOffset, 562 instanceCount, 563 firstInstance); 564 } 565 else 566 { 567 GL.DrawElementsInstancedBaseVertexBaseInstance( 568 _primitiveType, 569 indexCount, 570 _elementsType, 571 indexBaseOffset, 572 instanceCount, 573 firstVertex, 574 firstInstance); 575 } 576 } 577 578 public void DrawIndexedIndirect(BufferRange indirectBuffer) 579 { 580 if (!_program.IsLinked) 581 { 582 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 583 return; 584 } 585 586 PreDrawVbUnbounded(); 587 588 _vertexArray.SetRangeOfIndexBuffer(); 589 590 GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32()); 591 592 GL.DrawElementsIndirect(_primitiveType, _elementsType, (IntPtr)indirectBuffer.Offset); 593 594 _vertexArray.RestoreIndexBuffer(); 595 596 PostDraw(); 597 } 598 599 public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) 600 { 601 if (!_program.IsLinked) 602 { 603 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 604 return; 605 } 606 607 PreDrawVbUnbounded(); 608 609 _vertexArray.SetRangeOfIndexBuffer(); 610 611 GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32()); 612 GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32()); 613 614 GL.MultiDrawElementsIndirectCount( 615 _primitiveType, 616 (All)_elementsType, 617 (IntPtr)indirectBuffer.Offset, 618 (IntPtr)parameterBuffer.Offset, 619 maxDrawCount, 620 stride); 621 622 _vertexArray.RestoreIndexBuffer(); 623 624 PostDraw(); 625 } 626 627 public void DrawIndirect(BufferRange indirectBuffer) 628 { 629 if (!_program.IsLinked) 630 { 631 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 632 return; 633 } 634 635 PreDrawVbUnbounded(); 636 637 GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32()); 638 639 GL.DrawArraysIndirect(_primitiveType, (IntPtr)indirectBuffer.Offset); 640 641 PostDraw(); 642 } 643 644 public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) 645 { 646 if (!_program.IsLinked) 647 { 648 Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked."); 649 return; 650 } 651 652 PreDrawVbUnbounded(); 653 654 GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32()); 655 GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32()); 656 657 GL.MultiDrawArraysIndirectCount( 658 _primitiveType, 659 (IntPtr)indirectBuffer.Offset, 660 (IntPtr)parameterBuffer.Offset, 661 maxDrawCount, 662 stride); 663 664 PostDraw(); 665 } 666 667 public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion) 668 { 669 if (texture is TextureView view && sampler is Sampler samp) 670 { 671 if (HwCapabilities.SupportsDrawTexture) 672 { 673 GL.NV.DrawTexture( 674 view.Handle, 675 samp.Handle, 676 dstRegion.X1, 677 dstRegion.Y1, 678 dstRegion.X2, 679 dstRegion.Y2, 680 0, 681 srcRegion.X1 / view.Width, 682 srcRegion.Y1 / view.Height, 683 srcRegion.X2 / view.Width, 684 srcRegion.Y2 / view.Height); 685 } 686 else 687 { 688 static void Disable(EnableCap cap, bool enabled) 689 { 690 if (enabled) 691 { 692 GL.Disable(cap); 693 } 694 } 695 696 static void Enable(EnableCap cap, bool enabled) 697 { 698 if (enabled) 699 { 700 GL.Enable(cap); 701 } 702 } 703 704 Disable(EnableCap.CullFace, _cullEnable); 705 Disable(EnableCap.StencilTest, _stencilTestEnable); 706 Disable(EnableCap.DepthTest, _depthTestEnable); 707 708 if (_depthMask) 709 { 710 GL.DepthMask(false); 711 } 712 713 if (_tfEnabled) 714 { 715 GL.EndTransformFeedback(); 716 } 717 718 GL.ClipControl(ClipOrigin.UpperLeft, ClipDepthMode.NegativeOneToOne); 719 720 _drawTexture.Draw( 721 view, 722 samp, 723 dstRegion.X1, 724 dstRegion.Y1, 725 dstRegion.X2, 726 dstRegion.Y2, 727 srcRegion.X1 / view.Width, 728 srcRegion.Y1 / view.Height, 729 srcRegion.X2 / view.Width, 730 srcRegion.Y2 / view.Height); 731 732 _program?.Bind(); 733 _unit0Sampler?.Bind(0); 734 735 RestoreViewport0(); 736 737 Enable(EnableCap.CullFace, _cullEnable); 738 Enable(EnableCap.StencilTest, _stencilTestEnable); 739 Enable(EnableCap.DepthTest, _depthTestEnable); 740 741 if (_depthMask) 742 { 743 GL.DepthMask(true); 744 } 745 746 if (_tfEnabled) 747 { 748 GL.BeginTransformFeedback(_tfTopology); 749 } 750 751 RestoreClipControl(); 752 } 753 } 754 } 755 756 public void EndTransformFeedback() 757 { 758 GL.EndTransformFeedback(); 759 _tfEnabled = false; 760 } 761 762 public void SetAlphaTest(bool enable, float reference, CompareOp op) 763 { 764 if (!enable) 765 { 766 GL.Disable(EnableCap.AlphaTest); 767 return; 768 } 769 770 GL.AlphaFunc((AlphaFunction)op.Convert(), reference); 771 GL.Enable(EnableCap.AlphaTest); 772 } 773 774 public void SetBlendState(AdvancedBlendDescriptor blend) 775 { 776 if (HwCapabilities.SupportsBlendEquationAdvanced) 777 { 778 GL.BlendEquation((BlendEquationMode)blend.Op.Convert()); 779 GL.NV.BlendParameter(NvBlendEquationAdvanced.BlendOverlapNv, (int)blend.Overlap.Convert()); 780 GL.NV.BlendParameter(NvBlendEquationAdvanced.BlendPremultipliedSrcNv, blend.SrcPreMultiplied ? 1 : 0); 781 GL.Enable(EnableCap.Blend); 782 _advancedBlendEnable = true; 783 } 784 } 785 786 public void SetBlendState(int index, BlendDescriptor blend) 787 { 788 if (_advancedBlendEnable) 789 { 790 GL.Disable(EnableCap.Blend); 791 _advancedBlendEnable = false; 792 } 793 794 if (!blend.Enable) 795 { 796 GL.Disable(IndexedEnableCap.Blend, index); 797 return; 798 } 799 800 GL.BlendEquationSeparate( 801 index, 802 blend.ColorOp.Convert(), 803 blend.AlphaOp.Convert()); 804 805 GL.BlendFuncSeparate( 806 index, 807 (BlendingFactorSrc)blend.ColorSrcFactor.Convert(), 808 (BlendingFactorDest)blend.ColorDstFactor.Convert(), 809 (BlendingFactorSrc)blend.AlphaSrcFactor.Convert(), 810 (BlendingFactorDest)blend.AlphaDstFactor.Convert()); 811 812 EnsureFramebuffer(); 813 814 _framebuffer.SetDualSourceBlend( 815 blend.ColorSrcFactor.IsDualSource() || 816 blend.ColorDstFactor.IsDualSource() || 817 blend.AlphaSrcFactor.IsDualSource() || 818 blend.AlphaDstFactor.IsDualSource()); 819 820 if (_blendConstant != blend.BlendConstant) 821 { 822 _blendConstant = blend.BlendConstant; 823 824 GL.BlendColor( 825 blend.BlendConstant.Red, 826 blend.BlendConstant.Green, 827 blend.BlendConstant.Blue, 828 blend.BlendConstant.Alpha); 829 } 830 831 GL.Enable(IndexedEnableCap.Blend, index); 832 } 833 834 public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) 835 { 836 if ((enables & PolygonModeMask.Point) != 0) 837 { 838 GL.Enable(EnableCap.PolygonOffsetPoint); 839 } 840 else 841 { 842 GL.Disable(EnableCap.PolygonOffsetPoint); 843 } 844 845 if ((enables & PolygonModeMask.Line) != 0) 846 { 847 GL.Enable(EnableCap.PolygonOffsetLine); 848 } 849 else 850 { 851 GL.Disable(EnableCap.PolygonOffsetLine); 852 } 853 854 if ((enables & PolygonModeMask.Fill) != 0) 855 { 856 GL.Enable(EnableCap.PolygonOffsetFill); 857 } 858 else 859 { 860 GL.Disable(EnableCap.PolygonOffsetFill); 861 } 862 863 if (enables == 0) 864 { 865 return; 866 } 867 868 if (HwCapabilities.SupportsPolygonOffsetClamp) 869 { 870 GL.PolygonOffsetClamp(factor, units, clamp); 871 } 872 else 873 { 874 GL.PolygonOffset(factor, units); 875 } 876 } 877 878 public void SetDepthClamp(bool clamp) 879 { 880 if (!clamp) 881 { 882 GL.Disable(EnableCap.DepthClamp); 883 return; 884 } 885 886 GL.Enable(EnableCap.DepthClamp); 887 } 888 889 public void SetDepthMode(DepthMode mode) 890 { 891 ClipDepthMode depthMode = mode.Convert(); 892 893 if (_clipDepthMode != depthMode) 894 { 895 _clipDepthMode = depthMode; 896 897 GL.ClipControl(_clipOrigin, depthMode); 898 } 899 } 900 901 public void SetDepthTest(DepthTestDescriptor depthTest) 902 { 903 if (depthTest.TestEnable) 904 { 905 GL.Enable(EnableCap.DepthTest); 906 GL.DepthFunc((DepthFunction)depthTest.Func.Convert()); 907 } 908 else 909 { 910 GL.Disable(EnableCap.DepthTest); 911 } 912 913 GL.DepthMask(depthTest.WriteEnable); 914 _depthMask = depthTest.WriteEnable; 915 _depthTestEnable = depthTest.TestEnable; 916 } 917 918 public void SetFaceCulling(bool enable, Face face) 919 { 920 _cullEnable = enable; 921 922 if (!enable) 923 { 924 GL.Disable(EnableCap.CullFace); 925 return; 926 } 927 928 GL.CullFace(face.Convert()); 929 930 GL.Enable(EnableCap.CullFace); 931 } 932 933 public void SetFrontFace(FrontFace frontFace) 934 { 935 SetFrontFace(_frontFace = frontFace.Convert()); 936 } 937 938 public void SetImage(ShaderStage stage, int binding, ITexture texture) 939 { 940 if ((uint)binding < SavedImages) 941 { 942 _images[binding] = texture as TextureBase; 943 } 944 945 if (texture == null) 946 { 947 GL.BindImageTexture(binding, 0, 0, true, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8); 948 return; 949 } 950 951 TextureBase texBase = (TextureBase)texture; 952 953 SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); 954 955 if (format != 0) 956 { 957 GL.BindImageTexture(binding, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format); 958 } 959 } 960 961 public void SetImageArray(ShaderStage stage, int binding, IImageArray array) 962 { 963 (array as ImageArray).Bind(binding); 964 } 965 966 public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array) 967 { 968 throw new NotSupportedException("OpenGL does not support descriptor sets."); 969 } 970 971 public void SetIndexBuffer(BufferRange buffer, IndexType type) 972 { 973 _elementsType = type.Convert(); 974 975 _indexBaseOffset = (IntPtr)buffer.Offset; 976 977 EnsureVertexArray(); 978 979 _vertexArray.SetIndexBuffer(buffer); 980 } 981 982 public void SetLogicOpState(bool enable, LogicalOp op) 983 { 984 if (enable) 985 { 986 GL.Enable(EnableCap.ColorLogicOp); 987 988 GL.LogicOp((LogicOp)op.Convert()); 989 } 990 else 991 { 992 GL.Disable(EnableCap.ColorLogicOp); 993 } 994 } 995 996 public void SetMultisampleState(MultisampleDescriptor multisample) 997 { 998 if (multisample.AlphaToCoverageEnable) 999 { 1000 GL.Enable(EnableCap.SampleAlphaToCoverage); 1001 1002 if (multisample.AlphaToOneEnable) 1003 { 1004 GL.Enable(EnableCap.SampleAlphaToOne); 1005 } 1006 else 1007 { 1008 GL.Disable(EnableCap.SampleAlphaToOne); 1009 } 1010 1011 if (HwCapabilities.SupportsAlphaToCoverageDitherControl) 1012 { 1013 GL.NV.AlphaToCoverageDitherControl(multisample.AlphaToCoverageDitherEnable 1014 ? NvAlphaToCoverageDitherControl.AlphaToCoverageDitherEnableNv 1015 : NvAlphaToCoverageDitherControl.AlphaToCoverageDitherDisableNv); 1016 } 1017 } 1018 else 1019 { 1020 GL.Disable(EnableCap.SampleAlphaToCoverage); 1021 } 1022 } 1023 1024 public void SetLineParameters(float width, bool smooth) 1025 { 1026 if (smooth) 1027 { 1028 GL.Enable(EnableCap.LineSmooth); 1029 } 1030 else 1031 { 1032 GL.Disable(EnableCap.LineSmooth); 1033 } 1034 1035 GL.LineWidth(width); 1036 } 1037 1038 public unsafe void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel) 1039 { 1040 GL.PatchParameter(PatchParameterInt.PatchVertices, vertices); 1041 1042 fixed (float* pOuterLevel = defaultOuterLevel) 1043 { 1044 GL.PatchParameter(PatchParameterFloat.PatchDefaultOuterLevel, pOuterLevel); 1045 } 1046 1047 fixed (float* pInnerLevel = defaultInnerLevel) 1048 { 1049 GL.PatchParameter(PatchParameterFloat.PatchDefaultInnerLevel, pInnerLevel); 1050 } 1051 } 1052 1053 public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin) 1054 { 1055 // GL_POINT_SPRITE was deprecated in core profile 3.2+ and causes GL_INVALID_ENUM when set. 1056 // As we don't know if the current context is core or compat, it's safer to keep this code. 1057 if (enablePointSprite) 1058 { 1059 GL.Enable(EnableCap.PointSprite); 1060 } 1061 else 1062 { 1063 GL.Disable(EnableCap.PointSprite); 1064 } 1065 1066 if (isProgramPointSize) 1067 { 1068 GL.Enable(EnableCap.ProgramPointSize); 1069 } 1070 else 1071 { 1072 GL.Disable(EnableCap.ProgramPointSize); 1073 } 1074 1075 GL.PointParameter(origin == Origin.LowerLeft 1076 ? PointSpriteCoordOriginParameter.LowerLeft 1077 : PointSpriteCoordOriginParameter.UpperLeft); 1078 1079 // Games seem to set point size to 0 which generates a GL_INVALID_VALUE 1080 // From the spec, GL_INVALID_VALUE is generated if size is less than or equal to 0. 1081 GL.PointSize(Math.Max(float.Epsilon, size)); 1082 } 1083 1084 public void SetPolygonMode(GAL.PolygonMode frontMode, GAL.PolygonMode backMode) 1085 { 1086 if (frontMode == backMode) 1087 { 1088 GL.PolygonMode(MaterialFace.FrontAndBack, frontMode.Convert()); 1089 } 1090 else 1091 { 1092 GL.PolygonMode(MaterialFace.Front, frontMode.Convert()); 1093 GL.PolygonMode(MaterialFace.Back, backMode.Convert()); 1094 } 1095 } 1096 1097 public void SetPrimitiveRestart(bool enable, int index) 1098 { 1099 if (!enable) 1100 { 1101 GL.Disable(EnableCap.PrimitiveRestart); 1102 return; 1103 } 1104 1105 GL.PrimitiveRestartIndex(index); 1106 1107 GL.Enable(EnableCap.PrimitiveRestart); 1108 } 1109 1110 public void SetPrimitiveTopology(PrimitiveTopology topology) 1111 { 1112 _primitiveType = topology.Convert(); 1113 } 1114 1115 public void SetProgram(IProgram program) 1116 { 1117 Program prg = (Program)program; 1118 1119 if (_tfEnabled) 1120 { 1121 GL.EndTransformFeedback(); 1122 prg.Bind(); 1123 GL.BeginTransformFeedback(_tfTopology); 1124 } 1125 else 1126 { 1127 prg.Bind(); 1128 } 1129 1130 if (_fragmentOutputMap != (uint)prg.FragmentOutputMap) 1131 { 1132 _fragmentOutputMap = (uint)prg.FragmentOutputMap; 1133 1134 for (int index = 0; index < Constants.MaxRenderTargets; index++) 1135 { 1136 RestoreComponentMask(index, force: false); 1137 } 1138 } 1139 1140 _program = prg; 1141 } 1142 1143 public void SetRasterizerDiscard(bool discard) 1144 { 1145 if (discard) 1146 { 1147 GL.Enable(EnableCap.RasterizerDiscard); 1148 } 1149 else 1150 { 1151 GL.Disable(EnableCap.RasterizerDiscard); 1152 } 1153 1154 _rasterizerDiscard = discard; 1155 } 1156 1157 public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks) 1158 { 1159 _componentMasks = 0; 1160 1161 for (int index = 0; index < componentMasks.Length; index++) 1162 { 1163 _componentMasks |= componentMasks[index] << (index * 4); 1164 1165 RestoreComponentMask(index, force: false); 1166 } 1167 } 1168 1169 public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) 1170 { 1171 EnsureFramebuffer(); 1172 1173 for (int index = 0; index < colors.Length; index++) 1174 { 1175 TextureView color = (TextureView)colors[index]; 1176 1177 _framebuffer.AttachColor(index, color); 1178 1179 if (color != null) 1180 { 1181 int isBgra = color.Format.IsBgr() ? 1 : 0; 1182 1183 if (_fpIsBgra[index].X != isBgra) 1184 { 1185 _fpIsBgra[index].X = isBgra; 1186 1187 RestoreComponentMask(index); 1188 } 1189 } 1190 } 1191 1192 TextureView depthStencilView = (TextureView)depthStencil; 1193 1194 _framebuffer.AttachDepthStencil(depthStencilView); 1195 _framebuffer.SetDrawBuffers(colors.Length); 1196 } 1197 1198 public void SetScissors(ReadOnlySpan<Rectangle<int>> regions) 1199 { 1200 int count = Math.Min(regions.Length, Constants.MaxViewports); 1201 1202 Span<int> v = stackalloc int[count * 4]; 1203 1204 for (int index = 0; index < count; index++) 1205 { 1206 int vIndex = index * 4; 1207 1208 var region = regions[index]; 1209 1210 bool enabled = (region.X | region.Y) != 0 || region.Width != 0xffff || region.Height != 0xffff; 1211 uint mask = 1u << index; 1212 1213 if (enabled) 1214 { 1215 v[vIndex] = region.X; 1216 v[vIndex + 1] = region.Y; 1217 v[vIndex + 2] = region.Width; 1218 v[vIndex + 3] = region.Height; 1219 1220 if ((_scissorEnables & mask) == 0) 1221 { 1222 _scissorEnables |= mask; 1223 GL.Enable(IndexedEnableCap.ScissorTest, index); 1224 } 1225 } 1226 else 1227 { 1228 if ((_scissorEnables & mask) != 0) 1229 { 1230 _scissorEnables &= ~mask; 1231 GL.Disable(IndexedEnableCap.ScissorTest, index); 1232 } 1233 } 1234 } 1235 1236 GL.ScissorArray(0, count, ref v[0]); 1237 } 1238 1239 public void SetStencilTest(StencilTestDescriptor stencilTest) 1240 { 1241 _stencilTestEnable = stencilTest.TestEnable; 1242 1243 if (!stencilTest.TestEnable) 1244 { 1245 GL.Disable(EnableCap.StencilTest); 1246 return; 1247 } 1248 1249 GL.StencilOpSeparate( 1250 StencilFace.Front, 1251 stencilTest.FrontSFail.Convert(), 1252 stencilTest.FrontDpFail.Convert(), 1253 stencilTest.FrontDpPass.Convert()); 1254 1255 GL.StencilFuncSeparate( 1256 StencilFace.Front, 1257 (StencilFunction)stencilTest.FrontFunc.Convert(), 1258 stencilTest.FrontFuncRef, 1259 stencilTest.FrontFuncMask); 1260 1261 GL.StencilMaskSeparate(StencilFace.Front, stencilTest.FrontMask); 1262 1263 GL.StencilOpSeparate( 1264 StencilFace.Back, 1265 stencilTest.BackSFail.Convert(), 1266 stencilTest.BackDpFail.Convert(), 1267 stencilTest.BackDpPass.Convert()); 1268 1269 GL.StencilFuncSeparate( 1270 StencilFace.Back, 1271 (StencilFunction)stencilTest.BackFunc.Convert(), 1272 stencilTest.BackFuncRef, 1273 stencilTest.BackFuncMask); 1274 1275 GL.StencilMaskSeparate(StencilFace.Back, stencilTest.BackMask); 1276 1277 GL.Enable(EnableCap.StencilTest); 1278 1279 _stencilFrontMask = stencilTest.FrontMask; 1280 } 1281 1282 public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers) 1283 { 1284 SetBuffers(buffers, isStorage: true); 1285 } 1286 1287 public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler) 1288 { 1289 if (texture != null) 1290 { 1291 if (binding == 0) 1292 { 1293 _unit0Texture = (TextureBase)texture; 1294 } 1295 else 1296 { 1297 ((TextureBase)texture).Bind(binding); 1298 } 1299 } 1300 else 1301 { 1302 TextureBase.ClearBinding(binding); 1303 } 1304 1305 Sampler glSampler = (Sampler)sampler; 1306 1307 glSampler?.Bind(binding); 1308 1309 if (binding == 0) 1310 { 1311 _unit0Sampler = glSampler; 1312 } 1313 } 1314 1315 public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array) 1316 { 1317 (array as TextureArray).Bind(binding); 1318 } 1319 1320 public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array) 1321 { 1322 throw new NotSupportedException("OpenGL does not support descriptor sets."); 1323 } 1324 1325 public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) 1326 { 1327 if (_tfEnabled) 1328 { 1329 GL.EndTransformFeedback(); 1330 } 1331 1332 int count = Math.Min(buffers.Length, Constants.MaxTransformFeedbackBuffers); 1333 1334 for (int i = 0; i < count; i++) 1335 { 1336 BufferRange buffer = buffers[i]; 1337 _tfbTargets[i] = buffer; 1338 1339 if (buffer.Handle == BufferHandle.Null) 1340 { 1341 GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, 0); 1342 continue; 1343 } 1344 1345 if (_tfbs[i] == BufferHandle.Null) 1346 { 1347 _tfbs[i] = Buffer.Create(); 1348 } 1349 1350 Buffer.Resize(_tfbs[i], buffer.Size); 1351 Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size); 1352 GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i].ToInt32()); 1353 } 1354 1355 if (_tfEnabled) 1356 { 1357 GL.BeginTransformFeedback(_tfTopology); 1358 } 1359 } 1360 1361 public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers) 1362 { 1363 SetBuffers(buffers, isStorage: false); 1364 } 1365 1366 public void SetUserClipDistance(int index, bool enableClip) 1367 { 1368 if (!enableClip) 1369 { 1370 GL.Disable(EnableCap.ClipDistance0 + index); 1371 return; 1372 } 1373 1374 GL.Enable(EnableCap.ClipDistance0 + index); 1375 } 1376 1377 public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs) 1378 { 1379 EnsureVertexArray(); 1380 1381 _vertexArray.SetVertexAttributes(vertexAttribs); 1382 } 1383 1384 public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers) 1385 { 1386 EnsureVertexArray(); 1387 1388 _vertexArray.SetVertexBuffers(vertexBuffers); 1389 } 1390 1391 public void SetViewports(ReadOnlySpan<Viewport> viewports) 1392 { 1393 Array.Resize(ref _viewportArray, viewports.Length * 4); 1394 Array.Resize(ref _depthRangeArray, viewports.Length * 2); 1395 1396 float[] viewportArray = _viewportArray; 1397 double[] depthRangeArray = _depthRangeArray; 1398 1399 for (int index = 0; index < viewports.Length; index++) 1400 { 1401 int viewportElemIndex = index * 4; 1402 1403 Viewport viewport = viewports[index]; 1404 1405 viewportArray[viewportElemIndex + 0] = viewport.Region.X; 1406 viewportArray[viewportElemIndex + 1] = viewport.Region.Y + (viewport.Region.Height < 0 ? viewport.Region.Height : 0); 1407 viewportArray[viewportElemIndex + 2] = viewport.Region.Width; 1408 viewportArray[viewportElemIndex + 3] = MathF.Abs(viewport.Region.Height); 1409 1410 if (HwCapabilities.SupportsViewportSwizzle) 1411 { 1412 GL.NV.ViewportSwizzle( 1413 index, 1414 viewport.SwizzleX.Convert(), 1415 viewport.SwizzleY.Convert(), 1416 viewport.SwizzleZ.Convert(), 1417 viewport.SwizzleW.Convert()); 1418 } 1419 1420 depthRangeArray[index * 2 + 0] = viewport.DepthNear; 1421 depthRangeArray[index * 2 + 1] = viewport.DepthFar; 1422 } 1423 1424 bool flipY = viewports.Length != 0 && viewports[0].Region.Height < 0; 1425 1426 SetOrigin(flipY ? ClipOrigin.UpperLeft : ClipOrigin.LowerLeft); 1427 1428 GL.ViewportArray(0, viewports.Length, viewportArray); 1429 GL.DepthRangeArray(0, viewports.Length, depthRangeArray); 1430 } 1431 1432 public void TextureBarrier() 1433 { 1434 GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit); 1435 } 1436 1437 public void TextureBarrierTiled() 1438 { 1439 GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit); 1440 } 1441 1442 private static void SetBuffers(ReadOnlySpan<BufferAssignment> buffers, bool isStorage) 1443 { 1444 BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer; 1445 1446 for (int index = 0; index < buffers.Length; index++) 1447 { 1448 BufferAssignment assignment = buffers[index]; 1449 BufferRange buffer = assignment.Range; 1450 1451 if (buffer.Handle == BufferHandle.Null) 1452 { 1453 GL.BindBufferRange(target, assignment.Binding, 0, IntPtr.Zero, 0); 1454 continue; 1455 } 1456 1457 GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size); 1458 } 1459 } 1460 1461 private void SetOrigin(ClipOrigin origin) 1462 { 1463 if (_clipOrigin != origin) 1464 { 1465 _clipOrigin = origin; 1466 1467 GL.ClipControl(origin, _clipDepthMode); 1468 1469 SetFrontFace(_frontFace); 1470 } 1471 } 1472 1473 private void SetFrontFace(FrontFaceDirection frontFace) 1474 { 1475 // Changing clip origin will also change the front face to compensate 1476 // for the flipped viewport, we flip it again here to compensate as 1477 // this effect is undesirable for us. 1478 if (_clipOrigin == ClipOrigin.UpperLeft) 1479 { 1480 frontFace = frontFace == FrontFaceDirection.Ccw ? FrontFaceDirection.Cw : FrontFaceDirection.Ccw; 1481 } 1482 1483 GL.FrontFace(frontFace); 1484 } 1485 1486 private void EnsureVertexArray() 1487 { 1488 if (_vertexArray == null) 1489 { 1490 _vertexArray = new VertexArray(); 1491 1492 _vertexArray.Bind(); 1493 } 1494 } 1495 1496 private void EnsureFramebuffer() 1497 { 1498 if (_framebuffer == null) 1499 { 1500 _framebuffer = new Framebuffer(); 1501 1502 int boundHandle = _framebuffer.Bind(); 1503 _boundDrawFramebuffer = _boundReadFramebuffer = boundHandle; 1504 1505 GL.Enable(EnableCap.FramebufferSrgb); 1506 } 1507 } 1508 1509 internal (int drawHandle, int readHandle) GetBoundFramebuffers() 1510 { 1511 if (BackgroundContextWorker.InBackground) 1512 { 1513 return (0, 0); 1514 } 1515 1516 return (_boundDrawFramebuffer, _boundReadFramebuffer); 1517 } 1518 1519 private void PrepareForDispatch() 1520 { 1521 _unit0Texture?.Bind(0); 1522 } 1523 1524 private void PreDraw(int vertexCount) 1525 { 1526 _vertexArray.PreDraw(vertexCount); 1527 PreDraw(); 1528 } 1529 1530 private void PreDrawVbUnbounded() 1531 { 1532 _vertexArray.PreDrawVbUnbounded(); 1533 PreDraw(); 1534 } 1535 1536 private void PreDraw() 1537 { 1538 DrawCount++; 1539 1540 _unit0Texture?.Bind(0); 1541 } 1542 1543 private void PostDraw() 1544 { 1545 if (_tfEnabled) 1546 { 1547 for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++) 1548 { 1549 if (_tfbTargets[i].Handle != BufferHandle.Null) 1550 { 1551 Buffer.Copy(_tfbs[i], _tfbTargets[i].Handle, 0, _tfbTargets[i].Offset, _tfbTargets[i].Size); 1552 } 1553 } 1554 } 1555 } 1556 1557 public void RestoreComponentMask(int index, bool force = true) 1558 { 1559 // If the bound render target is bgra, swap the red and blue masks. 1560 uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u; 1561 uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u; 1562 1563 int shift = index * 4; 1564 uint componentMask = _componentMasks & _fragmentOutputMap; 1565 uint checkMask = 0xfu << shift; 1566 uint componentMaskAtIndex = componentMask & checkMask; 1567 1568 if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask)) 1569 { 1570 return; 1571 } 1572 1573 componentMask >>= shift; 1574 componentMask &= 0xfu; 1575 1576 GL.ColorMask( 1577 index, 1578 (componentMask & redMask) != 0, 1579 (componentMask & 2u) != 0, 1580 (componentMask & blueMask) != 0, 1581 (componentMask & 8u) != 0); 1582 1583 _currentComponentMasks &= ~checkMask; 1584 _currentComponentMasks |= componentMaskAtIndex; 1585 } 1586 1587 public void RestoreClipControl() 1588 { 1589 GL.ClipControl(_clipOrigin, _clipDepthMode); 1590 } 1591 1592 public void RestoreScissor0Enable() 1593 { 1594 if ((_scissorEnables & 1u) != 0) 1595 { 1596 GL.Enable(IndexedEnableCap.ScissorTest, 0); 1597 } 1598 } 1599 1600 public void RestoreRasterizerDiscard() 1601 { 1602 if (_rasterizerDiscard) 1603 { 1604 GL.Enable(EnableCap.RasterizerDiscard); 1605 } 1606 } 1607 1608 public void RestoreViewport0() 1609 { 1610 if (_viewportArray.Length > 0) 1611 { 1612 GL.ViewportArray(0, 1, _viewportArray); 1613 } 1614 } 1615 1616 public void RestoreProgram() 1617 { 1618 _program?.Bind(); 1619 } 1620 1621 public void RestoreImages1And2() 1622 { 1623 for (int i = 0; i < SavedImages; i++) 1624 { 1625 TextureBase texBase = _images[i]; 1626 1627 if (texBase != null) 1628 { 1629 SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format); 1630 1631 if (format != 0) 1632 { 1633 GL.BindImageTexture(i, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format); 1634 continue; 1635 } 1636 } 1637 1638 GL.BindImageTexture(i, 0, 0, true, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8); 1639 } 1640 } 1641 1642 public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) 1643 { 1644 // Compare an event and a constant value. 1645 if (value is CounterQueueEvent evt) 1646 { 1647 // Easy host conditional rendering when the check matches what GL can do: 1648 // - Event is of type samples passed. 1649 // - Result is not a combination of multiple queries. 1650 // - Comparing against 0. 1651 // - Event has not already been flushed. 1652 1653 if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter) 1654 { 1655 if (!value.ReserveForHostAccess()) 1656 { 1657 // If the event has been flushed, then just use the values on the CPU. 1658 // The query object may already be repurposed for another draw (eg. begin + end). 1659 return false; 1660 } 1661 1662 GL.BeginConditionalRender(evt.Query, isEqual ? ConditionalRenderType.QueryNoWaitInverted : ConditionalRenderType.QueryNoWait); 1663 _activeConditionalRender = evt; 1664 1665 return true; 1666 } 1667 } 1668 1669 // The GPU will flush the queries to CPU and evaluate the condition there instead. 1670 1671 GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now. 1672 return false; 1673 } 1674 1675 public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual) 1676 { 1677 GL.Flush(); // The GPU thread will be stalled manually flushing the counter, so flush GL commands now. 1678 return false; // We don't currently have a way to compare two counters for conditional rendering. 1679 } 1680 1681 public void EndHostConditionalRendering() 1682 { 1683 GL.EndConditionalRender(); 1684 1685 _activeConditionalRender?.ReleaseHostAccess(); 1686 _activeConditionalRender = null; 1687 } 1688 1689 public void Dispose() 1690 { 1691 for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++) 1692 { 1693 if (_tfbs[i] != BufferHandle.Null) 1694 { 1695 Buffer.Delete(_tfbs[i]); 1696 _tfbs[i] = BufferHandle.Null; 1697 } 1698 } 1699 1700 _activeConditionalRender?.ReleaseHostAccess(); 1701 _framebuffer?.Dispose(); 1702 _vertexArray?.Dispose(); 1703 _drawTexture.Dispose(); 1704 } 1705 } 1706 }