Clamp number of mipmap levels to avoid API errors due to invalid textures (#2808)

This commit is contained in:
gdkchan 2021-11-03 20:58:24 -03:00 committed by GitHub
parent f41687f4c1
commit f78bcb8048
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 12 deletions

View file

@ -1,5 +1,6 @@
using Ryujinx.Common; using Ryujinx.Common;
using System; using System;
using System.Numerics;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -112,6 +113,25 @@ namespace Ryujinx.Graphics.GAL
return 1; 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) private static int GetLevelSize(int size, int level)
{ {
return Math.Max(1, size >> level); return Math.Max(1, size >> level);

View file

@ -50,12 +50,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
internalFormat = (SizedInternalFormat)format.PixelInternalFormat; internalFormat = (SizedInternalFormat)format.PixelInternalFormat;
} }
int levels = Info.GetLevelsClamped();
switch (Info.Target) switch (Info.Target)
{ {
case Target.Texture1D: case Target.Texture1D:
GL.TexStorage1D( GL.TexStorage1D(
TextureTarget1d.Texture1D, TextureTarget1d.Texture1D,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width); Info.Width);
break; break;
@ -63,7 +65,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.Texture1DArray: case Target.Texture1DArray:
GL.TexStorage2D( GL.TexStorage2D(
TextureTarget2d.Texture1DArray, TextureTarget2d.Texture1DArray,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height); Info.Height);
@ -72,7 +74,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.Texture2D: case Target.Texture2D:
GL.TexStorage2D( GL.TexStorage2D(
TextureTarget2d.Texture2D, TextureTarget2d.Texture2D,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height); Info.Height);
@ -81,7 +83,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.Texture2DArray: case Target.Texture2DArray:
GL.TexStorage3D( GL.TexStorage3D(
TextureTarget3d.Texture2DArray, TextureTarget3d.Texture2DArray,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height, Info.Height,
@ -112,7 +114,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.Texture3D: case Target.Texture3D:
GL.TexStorage3D( GL.TexStorage3D(
TextureTarget3d.Texture3D, TextureTarget3d.Texture3D,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height, Info.Height,
@ -122,7 +124,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.Cubemap: case Target.Cubemap:
GL.TexStorage2D( GL.TexStorage2D(
TextureTarget2d.TextureCubeMap, TextureTarget2d.TextureCubeMap,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height); Info.Height);
@ -131,7 +133,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
case Target.CubemapArray: case Target.CubemapArray:
GL.TexStorage3D( GL.TexStorage3D(
(TextureTarget3d)All.TextureCubeMapArray, (TextureTarget3d)All.TextureCubeMapArray,
Info.Levels, levels,
internalFormat, internalFormat,
Info.Width, Info.Width,
Info.Height, Info.Height,

View file

@ -48,13 +48,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
pixelInternalFormat = format.PixelInternalFormat; pixelInternalFormat = format.PixelInternalFormat;
} }
int levels = Info.GetLevelsClamped();
GL.TextureView( GL.TextureView(
Handle, Handle,
target, target,
_parent.Handle, _parent.Handle,
pixelInternalFormat, pixelInternalFormat,
FirstLevel, FirstLevel,
Info.Levels, levels,
FirstLayer, FirstLayer,
Info.GetLayers()); Info.GetLayers());
@ -81,7 +83,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba); GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
int maxLevel = Info.Levels - 1; int maxLevel = levels - 1;
if (maxLevel < 0) if (maxLevel < 0)
{ {
@ -122,8 +124,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
public unsafe ReadOnlySpan<byte> GetData() public unsafe ReadOnlySpan<byte> GetData()
{ {
int size = 0; 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); size += Info.GetMipSize(level);
} }
@ -227,7 +230,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
faces = 6; 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++) for (int face = 0; face < faces; face++)
{ {
@ -465,10 +470,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
int width = Info.Width; int width = Info.Width;
int height = Info.Height; int height = Info.Height;
int depth = Info.Depth; int depth = Info.Depth;
int levels = Info.GetLevelsClamped();
int offset = 0; int offset = 0;
for (int level = 0; level < Info.Levels; level++) for (int level = 0; level < levels; level++)
{ {
int mipSize = Info.GetMipSize(level); int mipSize = Info.GetMipSize(level);