From f78bcb80485419466fde56812425a53e22705765 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 3 Nov 2021 20:58:24 -0300 Subject: [PATCH] Clamp number of mipmap levels to avoid API errors due to invalid textures (#2808) --- Ryujinx.Graphics.GAL/TextureCreateInfo.cs | 20 +++++++++++++++++++ .../Image/TextureStorage.cs | 16 ++++++++------- Ryujinx.Graphics.OpenGL/Image/TextureView.cs | 16 ++++++++++----- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/Ryujinx.Graphics.GAL/TextureCreateInfo.cs b/Ryujinx.Graphics.GAL/TextureCreateInfo.cs index eedf58a0..3ccfb700 100644 --- a/Ryujinx.Graphics.GAL/TextureCreateInfo.cs +++ b/Ryujinx.Graphics.GAL/TextureCreateInfo.cs @@ -1,5 +1,6 @@ using Ryujinx.Common; using System; +using System.Numerics; namespace Ryujinx.Graphics.GAL { @@ -112,6 +113,25 @@ namespace Ryujinx.Graphics.GAL return 1; } + public readonly int GetLevelsClamped() + { + int maxSize = Width; + + if (Target != Target.Texture1D && + Target != Target.Texture1DArray) + { + maxSize = Math.Max(maxSize, Height); + } + + if (Target == Target.Texture3D) + { + maxSize = Math.Max(maxSize, Depth); + } + + int maxLevels = BitOperations.Log2((uint)maxSize) + 1; + return Math.Min(Levels, maxLevels); + } + private static int GetLevelSize(int size, int level) { return Math.Max(1, size >> level); diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs b/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs index ce4616e4..215446ec 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs @@ -50,12 +50,14 @@ namespace Ryujinx.Graphics.OpenGL.Image internalFormat = (SizedInternalFormat)format.PixelInternalFormat; } + int levels = Info.GetLevelsClamped(); + switch (Info.Target) { case Target.Texture1D: GL.TexStorage1D( TextureTarget1d.Texture1D, - Info.Levels, + levels, internalFormat, Info.Width); break; @@ -63,7 +65,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.Texture1DArray: GL.TexStorage2D( TextureTarget2d.Texture1DArray, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height); @@ -72,7 +74,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.Texture2D: GL.TexStorage2D( TextureTarget2d.Texture2D, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height); @@ -81,7 +83,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.Texture2DArray: GL.TexStorage3D( TextureTarget3d.Texture2DArray, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height, @@ -112,7 +114,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.Texture3D: GL.TexStorage3D( TextureTarget3d.Texture3D, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height, @@ -122,7 +124,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.Cubemap: GL.TexStorage2D( TextureTarget2d.TextureCubeMap, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height); @@ -131,7 +133,7 @@ namespace Ryujinx.Graphics.OpenGL.Image case Target.CubemapArray: GL.TexStorage3D( (TextureTarget3d)All.TextureCubeMapArray, - Info.Levels, + levels, internalFormat, Info.Width, Info.Height, diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs index a70ab595..137f7d6e 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs @@ -48,13 +48,15 @@ namespace Ryujinx.Graphics.OpenGL.Image pixelInternalFormat = format.PixelInternalFormat; } + int levels = Info.GetLevelsClamped(); + GL.TextureView( Handle, target, _parent.Handle, pixelInternalFormat, FirstLevel, - Info.Levels, + levels, FirstLayer, Info.GetLayers()); @@ -81,7 +83,7 @@ namespace Ryujinx.Graphics.OpenGL.Image GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba); - int maxLevel = Info.Levels - 1; + int maxLevel = levels - 1; if (maxLevel < 0) { @@ -122,8 +124,9 @@ namespace Ryujinx.Graphics.OpenGL.Image public unsafe ReadOnlySpan GetData() { int size = 0; + int levels = Info.GetLevelsClamped(); - for (int level = 0; level < Info.Levels; level++) + for (int level = 0; level < levels; level++) { size += Info.GetMipSize(level); } @@ -227,7 +230,9 @@ namespace Ryujinx.Graphics.OpenGL.Image faces = 6; } - for (int level = 0; level < Info.Levels; level++) + int levels = Info.GetLevelsClamped(); + + for (int level = 0; level < levels; level++) { for (int face = 0; face < faces; face++) { @@ -465,10 +470,11 @@ namespace Ryujinx.Graphics.OpenGL.Image int width = Info.Width; int height = Info.Height; int depth = Info.Depth; + int levels = Info.GetLevelsClamped(); int offset = 0; - for (int level = 0; level < Info.Levels; level++) + for (int level = 0; level < levels; level++) { int mipSize = Info.GetMipSize(level);