| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787 |
- using OpenTK.Graphics.OpenGL;
- using Ryujinx.Common;
- using Ryujinx.Common.Memory;
- using Ryujinx.Graphics.GAL;
- using System;
- namespace Ryujinx.Graphics.OpenGL.Image
- {
- class TextureView : TextureBase, ITexture, ITextureInfo
- {
- private readonly OpenGLRenderer _renderer;
- private readonly TextureStorage _parent;
- public ITextureInfo Storage => _parent;
- public int FirstLayer { get; private set; }
- public int FirstLevel { get; private set; }
- public TextureView(
- OpenGLRenderer renderer,
- TextureStorage parent,
- TextureCreateInfo info,
- int firstLayer,
- int firstLevel) : base(info, parent.ScaleFactor)
- {
- _renderer = renderer;
- _parent = parent;
- FirstLayer = firstLayer;
- FirstLevel = firstLevel;
- CreateView();
- }
- private void CreateView()
- {
- TextureTarget target = Target.Convert();
- FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
- PixelInternalFormat pixelInternalFormat;
- if (format.IsCompressed)
- {
- pixelInternalFormat = (PixelInternalFormat)format.PixelFormat;
- }
- else
- {
- pixelInternalFormat = format.PixelInternalFormat;
- }
- int levels = Info.GetLevelsClamped();
- GL.TextureView(
- Handle,
- target,
- _parent.Handle,
- pixelInternalFormat,
- FirstLevel,
- levels,
- FirstLayer,
- Info.GetLayers());
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(target, Handle);
- int[] swizzleRgba = new int[]
- {
- (int)Info.SwizzleR.Convert(),
- (int)Info.SwizzleG.Convert(),
- (int)Info.SwizzleB.Convert(),
- (int)Info.SwizzleA.Convert()
- };
- if (Info.Format == Format.A1B5G5R5Unorm)
- {
- int temp = swizzleRgba[0];
- int temp2 = swizzleRgba[1];
- swizzleRgba[0] = swizzleRgba[3];
- swizzleRgba[1] = swizzleRgba[2];
- swizzleRgba[2] = temp2;
- swizzleRgba[3] = temp;
- }
- else if (Info.Format.IsBgr())
- {
- // Swap B <-> R for BGRA formats, as OpenGL has no support for them
- // and we need to manually swap the components on read/write on the GPU.
- int temp = swizzleRgba[0];
- swizzleRgba[0] = swizzleRgba[2];
- swizzleRgba[2] = temp;
- }
- GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
- int maxLevel = levels - 1;
- if (maxLevel < 0)
- {
- maxLevel = 0;
- }
- GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
- GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)Info.DepthStencilMode.Convert());
- }
- public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
- {
- firstLayer += FirstLayer;
- firstLevel += FirstLevel;
- return _parent.CreateView(info, firstLayer, firstLevel);
- }
- public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
- {
- TextureView destinationView = (TextureView)destination;
- if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
- {
- int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
- _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, layers);
- }
- else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
- {
- int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
- _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers);
- }
- else
- {
- _renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
- }
- }
- public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
- {
- TextureView destinationView = (TextureView)destination;
- if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
- {
- _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer,1);
- }
- else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
- {
- _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, srcLayer, dstLayer, 1);
- }
- else
- {
- _renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
- }
- }
- public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
- {
- _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter);
- }
- public unsafe ReadOnlySpan<byte> GetData()
- {
- int size = 0;
- int levels = Info.GetLevelsClamped();
- for (int level = 0; level < levels; level++)
- {
- size += Info.GetMipSize(level);
- }
- ReadOnlySpan<byte> data;
- if (HwCapabilities.UsePersistentBufferForFlush)
- {
- data = _renderer.PersistentBuffers.Default.GetTextureData(this, size);
- }
- else
- {
- IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
- WriteTo(target);
- data = new ReadOnlySpan<byte>(target.ToPointer(), size);
- }
- if (Format == Format.S8UintD24Unorm)
- {
- data = FormatConverter.ConvertD24S8ToS8D24(data);
- }
- return data;
- }
- public unsafe ReadOnlySpan<byte> GetData(int layer, int level)
- {
- int size = Info.GetMipSize(level);
- if (HwCapabilities.UsePersistentBufferForFlush)
- {
- return _renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level);
- }
- else
- {
- IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
- int offset = WriteTo2D(target, layer, level);
- return new ReadOnlySpan<byte>(target.ToPointer(), size).Slice(offset);
- }
- }
- public void WriteToPbo(int offset, bool forceBgra)
- {
- WriteTo(IntPtr.Zero + offset, forceBgra);
- }
- public int WriteToPbo2D(int offset, int layer, int level)
- {
- return WriteTo2D(IntPtr.Zero + offset, layer, level);
- }
- private int WriteTo2D(IntPtr data, int layer, int level)
- {
- TextureTarget target = Target.Convert();
- Bind(target, 0);
- FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
- PixelFormat pixelFormat = format.PixelFormat;
- PixelType pixelType = format.PixelType;
- if (target == TextureTarget.TextureCubeMap || target == TextureTarget.TextureCubeMapArray)
- {
- target = TextureTarget.TextureCubeMapPositiveX + (layer % 6);
- }
- int mipSize = Info.GetMipSize2D(level);
- if (format.IsCompressed)
- {
- GL.GetCompressedTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, mipSize, data);
- }
- else if (format.PixelFormat != PixelFormat.DepthStencil)
- {
- GL.GetTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, pixelFormat, pixelType, mipSize, data);
- }
- else
- {
- GL.GetTexImage(target, level, pixelFormat, pixelType, data);
- // The GL function returns all layers. Must return the offset of the layer we're interested in.
- return target switch
- {
- TextureTarget.TextureCubeMapArray => (layer / 6) * mipSize,
- TextureTarget.Texture1DArray => layer * mipSize,
- TextureTarget.Texture2DArray => layer * mipSize,
- _ => 0
- };
- }
- return 0;
- }
- private void WriteTo(IntPtr data, bool forceBgra = false)
- {
- TextureTarget target = Target.Convert();
- Bind(target, 0);
- FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
- PixelFormat pixelFormat = format.PixelFormat;
- PixelType pixelType = format.PixelType;
- if (forceBgra)
- {
- if (pixelType == PixelType.UnsignedShort565)
- {
- pixelType = PixelType.UnsignedShort565Reversed;
- }
- else if (pixelType == PixelType.UnsignedShort565Reversed)
- {
- pixelType = PixelType.UnsignedShort565;
- }
- else
- {
- pixelFormat = PixelFormat.Bgra;
- }
- }
- int faces = 1;
- if (target == TextureTarget.TextureCubeMap)
- {
- target = TextureTarget.TextureCubeMapPositiveX;
- faces = 6;
- }
- int levels = Info.GetLevelsClamped();
- for (int level = 0; level < levels; level++)
- {
- for (int face = 0; face < faces; face++)
- {
- int faceOffset = face * Info.GetMipSize2D(level);
- if (format.IsCompressed)
- {
- GL.GetCompressedTexImage(target + face, level, data + faceOffset);
- }
- else
- {
- GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
- }
- }
- data += Info.GetMipSize(level);
- }
- }
- public void SetData(SpanOrArray<byte> data)
- {
- var dataSpan = data.AsSpan();
- if (Format == Format.S8UintD24Unorm)
- {
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
- unsafe
- {
- fixed (byte* ptr = dataSpan)
- {
- ReadFrom((IntPtr)ptr, dataSpan.Length);
- }
- }
- }
- public void SetData(SpanOrArray<byte> data, int layer, int level)
- {
- var dataSpan = data.AsSpan();
- if (Format == Format.S8UintD24Unorm)
- {
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
- unsafe
- {
- fixed (byte* ptr = dataSpan)
- {
- int width = Math.Max(Info.Width >> level, 1);
- int height = Math.Max(Info.Height >> level, 1);
- ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
- }
- }
- }
- public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
- {
- var dataSpan = data.AsSpan();
- if (Format == Format.S8UintD24Unorm)
- {
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
- int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
- int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
- unsafe
- {
- fixed (byte* ptr = dataSpan)
- {
- ReadFrom2D(
- (IntPtr)ptr,
- layer,
- level,
- region.X,
- region.Y,
- region.Width,
- region.Height,
- BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
- }
- }
- }
- public void ReadFromPbo(int offset, int size)
- {
- ReadFrom(IntPtr.Zero + offset, size);
- }
- public void ReadFromPbo2D(int offset, int layer, int level, int width, int height)
- {
- ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height);
- }
- private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height)
- {
- int mipSize = Info.GetMipSize2D(level);
- ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
- }
- private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
- {
- TextureTarget target = Target.Convert();
- Bind(target, 0);
- FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
- switch (Target)
- {
- case Target.Texture1D:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage1D(
- target,
- level,
- x,
- width,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage1D(
- target,
- level,
- x,
- width,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Texture1DArray:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage2D(
- target,
- level,
- x,
- layer,
- width,
- 1,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage2D(
- target,
- level,
- x,
- layer,
- width,
- 1,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Texture2D:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage2D(
- target,
- level,
- x,
- y,
- width,
- height,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage2D(
- target,
- level,
- x,
- y,
- width,
- height,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Texture2DArray:
- case Target.Texture3D:
- case Target.CubemapArray:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage3D(
- target,
- level,
- x,
- y,
- layer,
- width,
- height,
- 1,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage3D(
- target,
- level,
- x,
- y,
- layer,
- width,
- height,
- 1,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Cubemap:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage2D(
- TextureTarget.TextureCubeMapPositiveX + layer,
- level,
- x,
- y,
- width,
- height,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage2D(
- TextureTarget.TextureCubeMapPositiveX + layer,
- level,
- x,
- y,
- width,
- height,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- }
- }
- private void ReadFrom(IntPtr data, int size)
- {
- TextureTarget target = Target.Convert();
- int baseLevel = 0;
- // glTexSubImage on cubemap views is broken on Intel, we have to use the storage instead.
- if (Target == Target.Cubemap && HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows)
- {
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(target, Storage.Handle);
- baseLevel = FirstLevel;
- }
- else
- {
- Bind(target, 0);
- }
- FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
- int width = Info.Width;
- int height = Info.Height;
- int depth = Info.Depth;
- int levels = Info.GetLevelsClamped();
- int offset = 0;
- for (int level = 0; level < levels; level++)
- {
- int mipSize = Info.GetMipSize(level);
- int endOffset = offset + mipSize;
- if ((uint)endOffset > (uint)size)
- {
- return;
- }
- switch (Target)
- {
- case Target.Texture1D:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage1D(
- target,
- level,
- 0,
- width,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage1D(
- target,
- level,
- 0,
- width,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Texture1DArray:
- case Target.Texture2D:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage2D(
- target,
- level,
- 0,
- 0,
- width,
- height,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage2D(
- target,
- level,
- 0,
- 0,
- width,
- height,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Texture2DArray:
- case Target.Texture3D:
- case Target.CubemapArray:
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage3D(
- target,
- level,
- 0,
- 0,
- 0,
- width,
- height,
- depth,
- format.PixelFormat,
- mipSize,
- data);
- }
- else
- {
- GL.TexSubImage3D(
- target,
- level,
- 0,
- 0,
- 0,
- width,
- height,
- depth,
- format.PixelFormat,
- format.PixelType,
- data);
- }
- break;
- case Target.Cubemap:
- int faceOffset = 0;
- for (int face = 0; face < 6; face++, faceOffset += mipSize / 6)
- {
- if (format.IsCompressed)
- {
- GL.CompressedTexSubImage2D(
- TextureTarget.TextureCubeMapPositiveX + face,
- baseLevel + level,
- 0,
- 0,
- width,
- height,
- format.PixelFormat,
- mipSize / 6,
- data + faceOffset);
- }
- else
- {
- GL.TexSubImage2D(
- TextureTarget.TextureCubeMapPositiveX + face,
- baseLevel + level,
- 0,
- 0,
- width,
- height,
- format.PixelFormat,
- format.PixelType,
- data + faceOffset);
- }
- }
- break;
- }
- data += mipSize;
- offset += mipSize;
- width = Math.Max(1, width >> 1);
- height = Math.Max(1, height >> 1);
- if (Target == Target.Texture3D)
- {
- depth = Math.Max(1, depth >> 1);
- }
- }
- }
- public void SetStorage(BufferRange buffer)
- {
- throw new NotSupportedException();
- }
- private void DisposeHandles()
- {
- if (Handle != 0)
- {
- GL.DeleteTexture(Handle);
- Handle = 0;
- }
- }
- /// <summary>
- /// Release the view without necessarily disposing the parent if we are the default view.
- /// This allows it to be added to the resource pool and reused later.
- /// </summary>
- public void Release()
- {
- bool hadHandle = Handle != 0;
- if (_parent.DefaultView != this)
- {
- DisposeHandles();
- }
- if (hadHandle)
- {
- _parent.DecrementViewsCount();
- }
- }
- public void Dispose()
- {
- if (_parent.DefaultView == this)
- {
- // Remove the default view (us), so that the texture cannot be released to the cache.
- _parent.DeleteDefault();
- }
- Release();
- }
- }
- }
|