| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- using OpenTK.Graphics.OpenGL;
- using Ryujinx.Graphics.Texture;
- using System;
- namespace Ryujinx.Graphics.Gal.OpenGL
- {
- class OglTexture : IGalTexture
- {
- private const long MaxTextureCacheSize = 768 * 1024 * 1024;
- private OglCachedResource<ImageHandler> _textureCache;
- public EventHandler<int> TextureDeleted { get; set; }
- public OglTexture()
- {
- _textureCache = new OglCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
- }
- public void LockCache()
- {
- _textureCache.Lock();
- }
- public void UnlockCache()
- {
- _textureCache.Unlock();
- }
- private void DeleteTexture(ImageHandler cachedImage)
- {
- TextureDeleted?.Invoke(this, cachedImage.Handle);
- GL.DeleteTexture(cachedImage.Handle);
- }
- public void Create(long key, int size, GalImage image)
- {
- int handle = GL.GenTexture();
- TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
- GL.BindTexture(target, handle);
- const int level = 0; //TODO: Support mipmap textures.
- const int border = 0;
- _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size);
- if (ImageUtils.IsCompressed(image.Format))
- {
- throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
- }
- (PixelInternalFormat internalFmt,
- PixelFormat format,
- PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
- switch (target)
- {
- case TextureTarget.Texture1D:
- GL.TexImage1D(
- target,
- level,
- internalFmt,
- image.Width,
- border,
- format,
- type,
- IntPtr.Zero);
- break;
- case TextureTarget.Texture2D:
- GL.TexImage2D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- border,
- format,
- type,
- IntPtr.Zero);
- break;
- case TextureTarget.Texture3D:
- GL.TexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.Depth,
- border,
- format,
- type,
- IntPtr.Zero);
- break;
- // Cube map arrays are just 2D texture arrays with 6 entries
- // per cube map so we can handle them in the same way
- case TextureTarget.TextureCubeMapArray:
- case TextureTarget.Texture2DArray:
- GL.TexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.LayerCount,
- border,
- format,
- type,
- IntPtr.Zero);
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {target}");
- }
- }
- public void Create(long key, byte[] data, GalImage image)
- {
- int handle = GL.GenTexture();
- TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
- GL.BindTexture(target, handle);
- const int level = 0; //TODO: Support mipmap textures.
- const int border = 0;
- _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)data.Length);
- if (ImageUtils.IsCompressed(image.Format) && !IsAstc(image.Format))
- {
- InternalFormat internalFmt = OglEnumConverter.GetCompressedImageFormat(image.Format);
- switch (target)
- {
- case TextureTarget.Texture1D:
- GL.CompressedTexImage1D(
- target,
- level,
- internalFmt,
- image.Width,
- border,
- data.Length,
- data);
- break;
- case TextureTarget.Texture2D:
- GL.CompressedTexImage2D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- border,
- data.Length,
- data);
- break;
- case TextureTarget.Texture3D:
- GL.CompressedTexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.Depth,
- border,
- data.Length,
- data);
- break;
- // Cube map arrays are just 2D texture arrays with 6 entries
- // per cube map so we can handle them in the same way
- case TextureTarget.TextureCubeMapArray:
- case TextureTarget.Texture2DArray:
- GL.CompressedTexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.LayerCount,
- border,
- data.Length,
- data);
- break;
- case TextureTarget.TextureCubeMap:
- Span<byte> array = new Span<byte>(data);
- int faceSize = ImageUtils.GetSize(image) / 6;
- for (int Face = 0; Face < 6; Face++)
- {
- GL.CompressedTexImage2D(
- TextureTarget.TextureCubeMapPositiveX + Face,
- level,
- internalFmt,
- image.Width,
- image.Height,
- border,
- faceSize,
- array.Slice(Face * faceSize, faceSize).ToArray());
- }
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {target}");
- }
- }
- else
- {
- // TODO: Use KHR_texture_compression_astc_hdr when available
- if (IsAstc(image.Format))
- {
- int textureBlockWidth = ImageUtils.GetBlockWidth(image.Format);
- int textureBlockHeight = ImageUtils.GetBlockHeight(image.Format);
- int textureBlockDepth = ImageUtils.GetBlockDepth(image.Format);
- data = AstcDecoder.DecodeToRgba8888(
- data,
- textureBlockWidth,
- textureBlockHeight,
- textureBlockDepth,
- image.Width,
- image.Height,
- image.Depth);
- image.Format = GalImageFormat.Rgba8 | (image.Format & GalImageFormat.TypeMask);
- }
- (PixelInternalFormat internalFmt,
- PixelFormat format,
- PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
- switch (target)
- {
- case TextureTarget.Texture1D:
- GL.TexImage1D(
- target,
- level,
- internalFmt,
- image.Width,
- border,
- format,
- type,
- data);
- break;
- case TextureTarget.Texture2D:
- GL.TexImage2D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- border,
- format,
- type,
- data);
- break;
- case TextureTarget.Texture3D:
- GL.TexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.Depth,
- border,
- format,
- type,
- data);
- break;
- // Cube map arrays are just 2D texture arrays with 6 entries
- // per cube map so we can handle them in the same way
- case TextureTarget.TextureCubeMapArray:
- case TextureTarget.Texture2DArray:
- GL.TexImage3D(
- target,
- level,
- internalFmt,
- image.Width,
- image.Height,
- image.LayerCount,
- border,
- format,
- type,
- data);
- break;
- case TextureTarget.TextureCubeMap:
- Span<byte> array = new Span<byte>(data);
- int faceSize = ImageUtils.GetSize(image) / 6;
- for (int face = 0; face < 6; face++)
- {
- GL.TexImage2D(
- TextureTarget.TextureCubeMapPositiveX + face,
- level,
- internalFmt,
- image.Width,
- image.Height,
- border,
- format,
- type,
- array.Slice(face * faceSize, faceSize).ToArray());
- }
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {target}");
- }
- }
- }
- private static bool IsAstc(GalImageFormat format)
- {
- format &= GalImageFormat.FormatMask;
- return format > GalImageFormat.Astc2DStart && format < GalImageFormat.Astc2DEnd;
- }
- public bool TryGetImage(long key, out GalImage image)
- {
- if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
- {
- image = cachedImage.Image;
- return true;
- }
- image = default(GalImage);
- return false;
- }
- public bool TryGetImageHandler(long key, out ImageHandler cachedImage)
- {
- if (_textureCache.TryGetValue(key, out cachedImage))
- {
- return true;
- }
- cachedImage = null;
- return false;
- }
- public void Bind(long key, int index, GalImage image)
- {
- if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
- {
- GL.ActiveTexture(TextureUnit.Texture0 + index);
- TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
- GL.BindTexture(target, cachedImage.Handle);
- int[] swizzleRgba = new int[]
- {
- (int)OglEnumConverter.GetTextureSwizzle(image.XSource),
- (int)OglEnumConverter.GetTextureSwizzle(image.YSource),
- (int)OglEnumConverter.GetTextureSwizzle(image.ZSource),
- (int)OglEnumConverter.GetTextureSwizzle(image.WSource)
- };
- GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
- }
- }
- public void SetSampler(GalImage image, GalTextureSampler sampler)
- {
- int wrapS = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressU);
- int wrapT = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressV);
- int wrapR = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressP);
- int minFilter = (int)OglEnumConverter.GetTextureMinFilter(sampler.MinFilter, sampler.MipFilter);
- int magFilter = (int)OglEnumConverter.GetTextureMagFilter(sampler.MagFilter);
- TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
- GL.TexParameter(target, TextureParameterName.TextureWrapS, wrapS);
- GL.TexParameter(target, TextureParameterName.TextureWrapT, wrapT);
- GL.TexParameter(target, TextureParameterName.TextureWrapR, wrapR);
- GL.TexParameter(target, TextureParameterName.TextureMinFilter, minFilter);
- GL.TexParameter(target, TextureParameterName.TextureMagFilter, magFilter);
- float[] color = new float[]
- {
- sampler.BorderColor.Red,
- sampler.BorderColor.Green,
- sampler.BorderColor.Blue,
- sampler.BorderColor.Alpha
- };
- GL.TexParameter(target, TextureParameterName.TextureBorderColor, color);
- if (sampler.DepthCompare)
- {
- GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
- GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)OglEnumConverter.GetDepthCompareFunc(sampler.DepthCompareFunc));
- }
- else
- {
- GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.None);
- GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)All.Never);
- }
- }
- }
- }
|