/ src / Ryujinx.Graphics.OpenGL / Image / TextureView.cs
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  }