diff options
author | gdk <gab.dark.100@gmail.com> | 2019-10-13 03:02:07 -0300 |
---|---|---|
committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
commit | 1876b346fea647e8284a66bb6d62c38801035cff (patch) | |
tree | 6eeff094298cda84d1613dc5ec0691e51d7b35f1 /Ryujinx.Graphics.OpenGL/TextureView.cs | |
parent | f617fb542a0e3d36012d77a4b5acbde7b08902f2 (diff) |
Initial work
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/TextureView.cs')
-rw-r--r-- | Ryujinx.Graphics.OpenGL/TextureView.cs | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.OpenGL/TextureView.cs b/Ryujinx.Graphics.OpenGL/TextureView.cs new file mode 100644 index 00000000..8a2b50dc --- /dev/null +++ b/Ryujinx.Graphics.OpenGL/TextureView.cs @@ -0,0 +1,425 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.GAL.Texture; +using Ryujinx.Graphics.OpenGL.Formats; +using OpenTK.Graphics.OpenGL; +using System; + +namespace Ryujinx.Graphics.OpenGL +{ + class TextureView : ITexture + { + public int Handle { get; private set; } + + private Renderer _renderer; + + private TextureStorage _parent; + + private TextureView _emulatedViewParent; + + private TextureCreateInfo _info; + + private int _firstLayer; + private int _firstLevel; + + private bool _acquired; + private bool _pendingDelete; + + public int Width => _info.Width; + public int Height => _info.Height; + public int DepthOrLayers => _info.GetDepthOrLayers(); + public int Levels => _info.Levels; + + public Target Target => _info.Target; + public Format Format => _info.Format; + + public int BlockWidth => _info.BlockWidth; + public int BlockHeight => _info.BlockHeight; + + public bool IsCompressed => _info.IsCompressed; + + public TextureView( + Renderer renderer, + TextureStorage parent, + TextureCreateInfo info, + int firstLayer, + int firstLevel) + { + _renderer = renderer; + _parent = parent; + _info = info; + + _firstLayer = firstLayer; + _firstLevel = firstLevel; + + Handle = GL.GenTexture(); + + 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; + } + + GL.TextureView( + Handle, + target, + _parent.Handle, + pixelInternalFormat, + _firstLevel, + _info.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() + }; + + GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba); + + int maxLevel = _info.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) + { + if (_info.IsCompressed == info.IsCompressed) + { + firstLayer += _firstLayer; + firstLevel += _firstLevel; + + return _parent.CreateView(info, firstLayer, firstLevel); + } + else + { + // TODO: Improve + TextureView emulatedView = (TextureView)_renderer.CreateTexture(info); + + emulatedView._emulatedViewParent = this; + + emulatedView._firstLayer = firstLayer; + emulatedView._firstLevel = firstLevel; + + return emulatedView; + } + } + + public int GetStorageDebugId() + { + return _parent.GetHashCode(); + } + + public void CopyTo(ITexture destination) + { + TextureView destinationView = (TextureView)destination; + + TextureCopyUnscaled.Copy(this, destinationView, 0, 0); + + int width = Math.Min(Width, destinationView.Width); + int height = Math.Min(Height, destinationView.Height); + + int depth = Math.Min(_info.GetDepthOrLayers(), destinationView._info.GetDepthOrLayers()); + + int levels = Math.Min(_info.Levels, destinationView._info.Levels); + + if (destinationView._emulatedViewParent != null) + { + TextureCopyUnscaled.Copy( + this, + destinationView._emulatedViewParent, + destinationView._firstLayer, + destinationView._firstLevel); + } + } + + public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) + { + _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter); + } + + public byte[] GetData(int face) + { + TextureTarget target = Target.Convert(); + + Bind(target, 0); + + FormatInfo format = FormatTable.GetFormatInfo(_info.Format); + + int depth = _info.GetDepthOrLayers(); + + if (target == TextureTarget.TextureCubeMap) + { + target = TextureTarget.TextureCubeMapPositiveX + face; + } + + if (format.IsCompressed) + { + byte[] data = new byte[_info.Width * _info.Height * depth * 4]; + + GL.GetTexImage(target, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data); + + return data; + } + else + { + byte[] data = new byte[_info.GetMipSize(0)]; + + GL.GetTexImage(target, 0, format.PixelFormat, format.PixelType, data); + + return data; + } + } + + public void SetData(Span<byte> data) + { + unsafe + { + fixed (byte* ptr = data) + { + SetData((IntPtr)ptr, data.Length); + } + } + } + + private void SetData(IntPtr data, int size) + { + TextureTarget target = Target.Convert(); + + Bind(target, 0); + + FormatInfo format = FormatTable.GetFormatInfo(_info.Format); + + int width = _info.Width; + int height = _info.Height; + int depth = _info.Depth; + + int offset = 0; + + for (int level = 0; level < _info.Levels; level++) + { + int mipSize = _info.GetMipSize(level); + + int endOffset = offset + mipSize; + + if ((uint)endOffset > (uint)size) + { + return; + } + + switch (_info.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, + level, + 0, + 0, + width, + height, + format.PixelFormat, + mipSize / 6, + data + faceOffset); + } + else + { + GL.TexSubImage2D( + TextureTarget.TextureCubeMapPositiveX + face, + 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 Bind(int unit) + { + Bind(Target.Convert(), unit); + } + + private void Bind(TextureTarget target, int unit) + { + GL.ActiveTexture(TextureUnit.Texture0 + unit); + + GL.BindTexture(target, Handle); + } + + public void Acquire() + { + _acquired = true; + } + + public void Release() + { + _acquired = false; + + if (_pendingDelete) + { + _pendingDelete = false; + + Dispose(); + } + } + + public void Dispose() + { + if (_acquired) + { + _pendingDelete = true; + + return; + } + + if (Handle != 0) + { + GL.DeleteTexture(Handle); + + _parent.DecrementViewsCount(); + + Handle = 0; + } + } + } +} |