TextureView.cs
1 using OpenTK.Graphics.OpenGL; 2 using Ryujinx.Common; 3 using Ryujinx.Common.Memory; 4 using Ryujinx.Graphics.GAL; 5 using System; 6 using System.Diagnostics; 7 8 namespace Ryujinx.Graphics.OpenGL.Image 9 { 10 class TextureView : TextureBase, ITexture, ITextureInfo 11 { 12 private readonly OpenGLRenderer _renderer; 13 14 private readonly TextureStorage _parent; 15 16 public ITextureInfo Storage => _parent; 17 18 public int FirstLayer { get; private set; } 19 public int FirstLevel { get; private set; } 20 21 public TextureView( 22 OpenGLRenderer renderer, 23 TextureStorage parent, 24 TextureCreateInfo info, 25 int firstLayer, 26 int firstLevel) : base(info) 27 { 28 _renderer = renderer; 29 _parent = parent; 30 31 FirstLayer = firstLayer; 32 FirstLevel = firstLevel; 33 34 CreateView(); 35 } 36 37 private void CreateView() 38 { 39 TextureTarget target = Target.Convert(); 40 41 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 42 43 PixelInternalFormat pixelInternalFormat; 44 45 if (format.IsCompressed) 46 { 47 pixelInternalFormat = (PixelInternalFormat)format.PixelFormat; 48 } 49 else 50 { 51 pixelInternalFormat = format.PixelInternalFormat; 52 } 53 54 int levels = Info.Levels; 55 56 GL.TextureView( 57 Handle, 58 target, 59 _parent.Handle, 60 pixelInternalFormat, 61 FirstLevel, 62 levels, 63 FirstLayer, 64 Info.GetLayers()); 65 66 GL.ActiveTexture(TextureUnit.Texture0); 67 68 GL.BindTexture(target, Handle); 69 70 int[] swizzleRgba = new int[] 71 { 72 (int)Info.SwizzleR.Convert(), 73 (int)Info.SwizzleG.Convert(), 74 (int)Info.SwizzleB.Convert(), 75 (int)Info.SwizzleA.Convert(), 76 }; 77 78 if (Info.Format == Format.A1B5G5R5Unorm) 79 { 80 int temp = swizzleRgba[0]; 81 int temp2 = swizzleRgba[1]; 82 swizzleRgba[0] = swizzleRgba[3]; 83 swizzleRgba[1] = swizzleRgba[2]; 84 swizzleRgba[2] = temp2; 85 swizzleRgba[3] = temp; 86 } 87 else if (Info.Format.IsBgr()) 88 { 89 // Swap B <-> R for BGRA formats, as OpenGL has no support for them 90 // and we need to manually swap the components on read/write on the GPU. 91 (swizzleRgba[2], swizzleRgba[0]) = (swizzleRgba[0], swizzleRgba[2]); 92 } 93 94 GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba); 95 96 int maxLevel = levels - 1; 97 98 if (maxLevel < 0) 99 { 100 maxLevel = 0; 101 } 102 103 GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel); 104 GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)Info.DepthStencilMode.Convert()); 105 } 106 107 public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel) 108 { 109 firstLayer += FirstLayer; 110 firstLevel += FirstLevel; 111 112 return _parent.CreateView(info, firstLayer, firstLevel); 113 } 114 115 public void CopyTo(ITexture destination, int firstLayer, int firstLevel) 116 { 117 TextureView destinationView = (TextureView)destination; 118 119 bool srcIsMultisample = Target.IsMultisample(); 120 bool dstIsMultisample = destinationView.Target.IsMultisample(); 121 122 if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil()) 123 { 124 int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); 125 CopyWithBlitForDepthMS(destinationView, 0, firstLayer, layers); 126 } 127 else if (!dstIsMultisample && srcIsMultisample) 128 { 129 int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); 130 _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, layers); 131 } 132 else if (dstIsMultisample && !srcIsMultisample) 133 { 134 int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); 135 _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers); 136 } 137 else if (destinationView.Info.BytesPerPixel != Info.BytesPerPixel) 138 { 139 int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); 140 int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel); 141 _renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, 0, firstLayer, 0, firstLevel, layers, levels); 142 } 143 else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil()) 144 { 145 int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); 146 int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel); 147 148 for (int level = 0; level < levels; level++) 149 { 150 int srcWidth = Math.Max(1, Width >> level); 151 int srcHeight = Math.Max(1, Height >> level); 152 153 int dstWidth = Math.Max(1, destinationView.Width >> (firstLevel + level)); 154 int dstHeight = Math.Max(1, destinationView.Height >> (firstLevel + level)); 155 156 int minWidth = Math.Min(srcWidth, dstWidth); 157 int minHeight = Math.Min(srcHeight, dstHeight); 158 159 for (int layer = 0; layer < layers; layer++) 160 { 161 _renderer.TextureCopy.PboCopy(this, destinationView, 0, firstLayer + layer, 0, firstLevel + level, minWidth, minHeight); 162 } 163 } 164 } 165 else 166 { 167 _renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel); 168 } 169 } 170 171 public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel) 172 { 173 TextureView destinationView = (TextureView)destination; 174 175 bool srcIsMultisample = Target.IsMultisample(); 176 bool dstIsMultisample = destinationView.Target.IsMultisample(); 177 178 if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil()) 179 { 180 CopyWithBlitForDepthMS(destinationView, srcLayer, dstLayer, 1); 181 } 182 else if (!dstIsMultisample && srcIsMultisample) 183 { 184 _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer, 1); 185 } 186 else if (dstIsMultisample && !srcIsMultisample) 187 { 188 _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, srcLayer, dstLayer, 1); 189 } 190 else if (destinationView.Info.BytesPerPixel != Info.BytesPerPixel) 191 { 192 _renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1); 193 } 194 else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil()) 195 { 196 int minWidth = Math.Min(Width, destinationView.Width); 197 int minHeight = Math.Min(Height, destinationView.Height); 198 199 _renderer.TextureCopy.PboCopy(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, minWidth, minHeight); 200 } 201 else 202 { 203 _renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1); 204 } 205 } 206 207 private void CopyWithBlitForDepthMS(TextureView destinationView, int srcLayer, int dstLayer, int layers) 208 { 209 // This is currently used for multisample <-> non-multisample copies. 210 // We can't do that with compute because it's not possible to write depth textures on compute. 211 // It can be done with draws, but we don't have support for saving and restoring the OpenGL state 212 // for a draw with different state right now. 213 // This approach uses blit, which causes a resolution loss since some samples will be lost 214 // in the process. 215 216 Extents2D srcRegion = new(0, 0, Width, Height); 217 Extents2D dstRegion = new(0, 0, destinationView.Width, destinationView.Height); 218 219 if (destinationView.Target.IsMultisample()) 220 { 221 TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast( 222 Info.Target, 223 Info.BlockWidth, 224 Info.BlockHeight, 225 Info.BytesPerPixel, 226 Format, 227 destinationView.Width, 228 destinationView.Height, 229 Info.Depth, 230 1, 231 1); 232 233 _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, dstRegion, false); 234 _renderer.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1); 235 } 236 else 237 { 238 Target target = Target switch 239 { 240 Target.Texture2DMultisample => Target.Texture2D, 241 Target.Texture2DMultisampleArray => Target.Texture2DArray, 242 _ => Target, 243 }; 244 245 TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast( 246 target, 247 Info.BlockWidth, 248 Info.BlockHeight, 249 Info.BytesPerPixel, 250 Format, 251 Width, 252 Height, 253 Info.Depth, 254 1, 255 1); 256 257 _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, false); 258 _renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1); 259 } 260 } 261 262 public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) 263 { 264 _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter); 265 } 266 267 public unsafe PinnedSpan<byte> GetData() 268 { 269 int size = 0; 270 int levels = Info.Levels; 271 272 for (int level = 0; level < levels; level++) 273 { 274 size += Info.GetMipSize(level); 275 } 276 277 ReadOnlySpan<byte> data; 278 279 if (HwCapabilities.UsePersistentBufferForFlush) 280 { 281 data = _renderer.PersistentBuffers.Default.GetTextureData(this, size); 282 } 283 else 284 { 285 IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size); 286 287 WriteTo(target); 288 289 data = new ReadOnlySpan<byte>(target.ToPointer(), size); 290 } 291 292 if (Format == Format.S8UintD24Unorm) 293 { 294 data = FormatConverter.ConvertD24S8ToS8D24(data); 295 } 296 297 return PinnedSpan<byte>.UnsafeFromSpan(data); 298 } 299 300 public unsafe PinnedSpan<byte> GetData(int layer, int level) 301 { 302 int size = Info.GetMipSize(level); 303 304 if (HwCapabilities.UsePersistentBufferForFlush) 305 { 306 return PinnedSpan<byte>.UnsafeFromSpan(_renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level)); 307 } 308 else 309 { 310 IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size); 311 312 int offset = WriteTo2D(target, layer, level); 313 314 return new PinnedSpan<byte>((byte*)target.ToPointer() + offset, size); 315 } 316 } 317 318 public void CopyTo(BufferRange range, int layer, int level, int stride) 319 { 320 if (stride != 0 && stride != BitUtils.AlignUp(Info.Width * Info.BytesPerPixel, 4)) 321 { 322 throw new NotSupportedException("Stride conversion for texture copy to buffer not supported."); 323 } 324 325 GL.BindBuffer(BufferTarget.PixelPackBuffer, range.Handle.ToInt32()); 326 327 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 328 if (format.PixelFormat == PixelFormat.DepthStencil) 329 { 330 throw new InvalidOperationException("DepthStencil copy to buffer is not supported for layer/level > 0."); 331 } 332 333 int offset = WriteToPbo2D(range.Offset, layer, level); 334 335 Debug.Assert(offset == 0); 336 337 GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); 338 } 339 340 public void WriteToPbo(int offset, bool forceBgra) 341 { 342 WriteTo(IntPtr.Zero + offset, forceBgra); 343 } 344 345 public int WriteToPbo2D(int offset, int layer, int level) 346 { 347 return WriteTo2D(IntPtr.Zero + offset, layer, level); 348 } 349 350 private int WriteTo2D(IntPtr data, int layer, int level) 351 { 352 TextureTarget target = Target.Convert(); 353 354 Bind(target, 0); 355 356 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 357 358 PixelFormat pixelFormat = format.PixelFormat; 359 PixelType pixelType = format.PixelType; 360 361 if (target == TextureTarget.TextureCubeMap || target == TextureTarget.TextureCubeMapArray) 362 { 363 target = TextureTarget.TextureCubeMapPositiveX + (layer % 6); 364 } 365 366 int mipSize = Info.GetMipSize2D(level); 367 368 if (format.IsCompressed) 369 { 370 GL.GetCompressedTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, mipSize, data); 371 } 372 else if (format.PixelFormat != PixelFormat.DepthStencil) 373 { 374 GL.GetTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, pixelFormat, pixelType, mipSize, data); 375 } 376 else 377 { 378 GL.GetTexImage(target, level, pixelFormat, pixelType, data); 379 380 // The GL function returns all layers. Must return the offset of the layer we're interested in. 381 return target switch 382 { 383 TextureTarget.TextureCubeMapArray => (layer / 6) * mipSize, 384 TextureTarget.Texture1DArray => layer * mipSize, 385 TextureTarget.Texture2DArray => layer * mipSize, 386 _ => 0, 387 }; 388 } 389 390 return 0; 391 } 392 393 private void WriteTo(IntPtr data, bool forceBgra = false) 394 { 395 TextureTarget target = Target.Convert(); 396 397 Bind(target, 0); 398 399 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 400 401 PixelFormat pixelFormat = format.PixelFormat; 402 PixelType pixelType = format.PixelType; 403 404 if (forceBgra) 405 { 406 if (pixelType == PixelType.UnsignedShort565) 407 { 408 pixelType = PixelType.UnsignedShort565Reversed; 409 } 410 else if (pixelType == PixelType.UnsignedShort565Reversed) 411 { 412 pixelType = PixelType.UnsignedShort565; 413 } 414 else 415 { 416 pixelFormat = PixelFormat.Bgra; 417 } 418 } 419 420 int faces = 1; 421 422 if (target == TextureTarget.TextureCubeMap) 423 { 424 target = TextureTarget.TextureCubeMapPositiveX; 425 426 faces = 6; 427 } 428 429 int levels = Info.Levels; 430 431 for (int level = 0; level < levels; level++) 432 { 433 for (int face = 0; face < faces; face++) 434 { 435 int faceOffset = face * Info.GetMipSize2D(level); 436 437 if (format.IsCompressed) 438 { 439 GL.GetCompressedTexImage(target + face, level, data + faceOffset); 440 } 441 else 442 { 443 GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset); 444 } 445 } 446 447 data += Info.GetMipSize(level); 448 } 449 } 450 451 public void SetData(MemoryOwner<byte> data) 452 { 453 using (data = EnsureDataFormat(data)) 454 { 455 unsafe 456 { 457 var dataSpan = data.Span; 458 fixed (byte* ptr = dataSpan) 459 { 460 ReadFrom((IntPtr)ptr, dataSpan.Length); 461 } 462 } 463 } 464 } 465 466 public void SetData(MemoryOwner<byte> data, int layer, int level) 467 { 468 using (data = EnsureDataFormat(data)) 469 { 470 unsafe 471 { 472 fixed (byte* ptr = data.Span) 473 { 474 int width = Math.Max(Info.Width >> level, 1); 475 int height = Math.Max(Info.Height >> level, 1); 476 477 ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height); 478 } 479 } 480 } 481 } 482 483 public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) 484 { 485 using (data = EnsureDataFormat(data)) 486 { 487 int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth); 488 int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight); 489 490 unsafe 491 { 492 fixed (byte* ptr = data.Span) 493 { 494 ReadFrom2D( 495 (IntPtr)ptr, 496 layer, 497 level, 498 region.X, 499 region.Y, 500 region.Width, 501 region.Height, 502 BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks); 503 } 504 } 505 } 506 } 507 508 public void ReadFromPbo(int offset, int size) 509 { 510 ReadFrom(IntPtr.Zero + offset, size); 511 } 512 513 public void ReadFromPbo2D(int offset, int layer, int level, int width, int height) 514 { 515 ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height); 516 } 517 518 private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height) 519 { 520 int mipSize = Info.GetMipSize2D(level); 521 522 ReadFrom2D(data, layer, level, x, y, width, height, mipSize); 523 } 524 525 private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data) 526 { 527 if (Format == Format.S8UintD24Unorm) 528 { 529 using (data) 530 { 531 return FormatConverter.ConvertS8D24ToD24S8(data.Span); 532 } 533 } 534 535 return data; 536 } 537 538 private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize) 539 { 540 TextureTarget target = Target.Convert(); 541 542 Bind(target, 0); 543 544 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 545 546 switch (Target) 547 { 548 case Target.Texture1D: 549 if (format.IsCompressed) 550 { 551 GL.CompressedTexSubImage1D( 552 target, 553 level, 554 x, 555 width, 556 format.PixelFormat, 557 mipSize, 558 data); 559 } 560 else 561 { 562 GL.TexSubImage1D( 563 target, 564 level, 565 x, 566 width, 567 format.PixelFormat, 568 format.PixelType, 569 data); 570 } 571 break; 572 573 case Target.Texture1DArray: 574 if (format.IsCompressed) 575 { 576 GL.CompressedTexSubImage2D( 577 target, 578 level, 579 x, 580 layer, 581 width, 582 1, 583 format.PixelFormat, 584 mipSize, 585 data); 586 } 587 else 588 { 589 GL.TexSubImage2D( 590 target, 591 level, 592 x, 593 layer, 594 width, 595 1, 596 format.PixelFormat, 597 format.PixelType, 598 data); 599 } 600 break; 601 602 case Target.Texture2D: 603 if (format.IsCompressed) 604 { 605 GL.CompressedTexSubImage2D( 606 target, 607 level, 608 x, 609 y, 610 width, 611 height, 612 format.PixelFormat, 613 mipSize, 614 data); 615 } 616 else 617 { 618 GL.TexSubImage2D( 619 target, 620 level, 621 x, 622 y, 623 width, 624 height, 625 format.PixelFormat, 626 format.PixelType, 627 data); 628 } 629 break; 630 631 case Target.Texture2DArray: 632 case Target.Texture3D: 633 case Target.CubemapArray: 634 if (format.IsCompressed) 635 { 636 GL.CompressedTexSubImage3D( 637 target, 638 level, 639 x, 640 y, 641 layer, 642 width, 643 height, 644 1, 645 format.PixelFormat, 646 mipSize, 647 data); 648 } 649 else 650 { 651 GL.TexSubImage3D( 652 target, 653 level, 654 x, 655 y, 656 layer, 657 width, 658 height, 659 1, 660 format.PixelFormat, 661 format.PixelType, 662 data); 663 } 664 break; 665 666 case Target.Cubemap: 667 if (format.IsCompressed) 668 { 669 GL.CompressedTexSubImage2D( 670 TextureTarget.TextureCubeMapPositiveX + layer, 671 level, 672 x, 673 y, 674 width, 675 height, 676 format.PixelFormat, 677 mipSize, 678 data); 679 } 680 else 681 { 682 GL.TexSubImage2D( 683 TextureTarget.TextureCubeMapPositiveX + layer, 684 level, 685 x, 686 y, 687 width, 688 height, 689 format.PixelFormat, 690 format.PixelType, 691 data); 692 } 693 break; 694 } 695 } 696 697 private void ReadFrom(IntPtr data, int size) 698 { 699 TextureTarget target = Target.Convert(); 700 int baseLevel = 0; 701 702 // glTexSubImage on cubemap views is broken on Intel, we have to use the storage instead. 703 if (Target == Target.Cubemap && HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows) 704 { 705 GL.ActiveTexture(TextureUnit.Texture0); 706 GL.BindTexture(target, Storage.Handle); 707 baseLevel = FirstLevel; 708 } 709 else 710 { 711 Bind(target, 0); 712 } 713 714 FormatInfo format = FormatTable.GetFormatInfo(Info.Format); 715 716 int width = Info.Width; 717 int height = Info.Height; 718 int depth = Info.Depth; 719 int levels = Info.Levels; 720 721 int offset = 0; 722 723 for (int level = 0; level < levels; level++) 724 { 725 int mipSize = Info.GetMipSize(level); 726 727 int endOffset = offset + mipSize; 728 729 if ((uint)endOffset > (uint)size) 730 { 731 return; 732 } 733 734 switch (Target) 735 { 736 case Target.Texture1D: 737 if (format.IsCompressed) 738 { 739 GL.CompressedTexSubImage1D( 740 target, 741 level, 742 0, 743 width, 744 format.PixelFormat, 745 mipSize, 746 data); 747 } 748 else 749 { 750 GL.TexSubImage1D( 751 target, 752 level, 753 0, 754 width, 755 format.PixelFormat, 756 format.PixelType, 757 data); 758 } 759 break; 760 761 case Target.Texture1DArray: 762 case Target.Texture2D: 763 if (format.IsCompressed) 764 { 765 GL.CompressedTexSubImage2D( 766 target, 767 level, 768 0, 769 0, 770 width, 771 height, 772 format.PixelFormat, 773 mipSize, 774 data); 775 } 776 else 777 { 778 GL.TexSubImage2D( 779 target, 780 level, 781 0, 782 0, 783 width, 784 height, 785 format.PixelFormat, 786 format.PixelType, 787 data); 788 } 789 break; 790 791 case Target.Texture2DArray: 792 case Target.Texture3D: 793 case Target.CubemapArray: 794 if (format.IsCompressed) 795 { 796 GL.CompressedTexSubImage3D( 797 target, 798 level, 799 0, 800 0, 801 0, 802 width, 803 height, 804 depth, 805 format.PixelFormat, 806 mipSize, 807 data); 808 } 809 else 810 { 811 GL.TexSubImage3D( 812 target, 813 level, 814 0, 815 0, 816 0, 817 width, 818 height, 819 depth, 820 format.PixelFormat, 821 format.PixelType, 822 data); 823 } 824 break; 825 826 case Target.Cubemap: 827 int faceOffset = 0; 828 829 for (int face = 0; face < 6; face++, faceOffset += mipSize / 6) 830 { 831 if (format.IsCompressed) 832 { 833 GL.CompressedTexSubImage2D( 834 TextureTarget.TextureCubeMapPositiveX + face, 835 baseLevel + level, 836 0, 837 0, 838 width, 839 height, 840 format.PixelFormat, 841 mipSize / 6, 842 data + faceOffset); 843 } 844 else 845 { 846 GL.TexSubImage2D( 847 TextureTarget.TextureCubeMapPositiveX + face, 848 baseLevel + level, 849 0, 850 0, 851 width, 852 height, 853 format.PixelFormat, 854 format.PixelType, 855 data + faceOffset); 856 } 857 } 858 break; 859 } 860 861 data += mipSize; 862 offset += mipSize; 863 864 width = Math.Max(1, width >> 1); 865 height = Math.Max(1, height >> 1); 866 867 if (Target == Target.Texture3D) 868 { 869 depth = Math.Max(1, depth >> 1); 870 } 871 } 872 } 873 874 public void SetStorage(BufferRange buffer) 875 { 876 throw new NotSupportedException(); 877 } 878 879 private void DisposeHandles() 880 { 881 if (Handle != 0) 882 { 883 GL.DeleteTexture(Handle); 884 885 Handle = 0; 886 } 887 } 888 889 /// <summary> 890 /// Release the view without necessarily disposing the parent if we are the default view. 891 /// This allows it to be added to the resource pool and reused later. 892 /// </summary> 893 public void Release() 894 { 895 bool hadHandle = Handle != 0; 896 897 if (_parent.DefaultView != this) 898 { 899 DisposeHandles(); 900 } 901 902 if (hadHandle) 903 { 904 _parent.DecrementViewsCount(); 905 } 906 } 907 908 public void Dispose() 909 { 910 if (_parent.DefaultView == this) 911 { 912 // Remove the default view (us), so that the texture cannot be released to the cache. 913 _parent.DeleteDefault(); 914 } 915 916 Release(); 917 } 918 } 919 }