Skip to content

Commit

Permalink
Prevent textures being created over the maximum texture dimension, fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CasualPokePlayer committed Jun 1, 2024
1 parent d91242d commit dcfe553
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 25 deletions.
32 changes: 16 additions & 16 deletions src/BizHawk.Bizware.Graphics.Controls/Controls/OpenGLControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ namespace BizHawk.Bizware.Graphics.Controls
{
internal sealed class OpenGLControl : GraphicsControl
{
public SDL2OpenGLContext Context { get; private set; }
private readonly Action _initGLState;
private SDL2OpenGLContext _context;

public OpenGLControl()
public OpenGLControl(Action initGLState)
{
_initGLState = initGLState;

// according to OpenTK, these are the styles we want to set
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.UserPaint, true);
Expand Down Expand Up @@ -41,14 +44,15 @@ protected override CreateParams CreateParams
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
Context = new(Handle, 3, 2, true);
_context = new(Handle, 3, 2, true);
_initGLState();
}

protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
Context.Dispose();
Context = null;
_context.Dispose();
_context = null;
}

private void MakeContextCurrent()
Expand All @@ -58,13 +62,13 @@ private void MakeContextCurrent()
throw new ObjectDisposedException(nameof(OpenGLControl));
}

if (Context is null)
if (_context is null)
{
CreateControl();
}
else
{
Context.MakeContextCurrent();
_context.MakeContextCurrent();
}
}

Expand All @@ -76,23 +80,19 @@ public override void AllowTearing(bool state)
public override void SetVsync(bool state)
{
MakeContextCurrent();
Context.SetVsync(state);
_context.SetVsync(state);
}

public override void Begin()
{
MakeContextCurrent();
}
=> MakeContextCurrent();

public override void End()
{
SDL2OpenGLContext.MakeNoneCurrent();
}
=> SDL2OpenGLContext.MakeNoneCurrent();

public override void SwapBuffers()
{
MakeContextCurrent();
Context.SwapBuffers();
_context.SwapBuffers();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static GraphicsControl CreateGraphicsControl(IGL gl)
{
GraphicsControl ret = gl switch
{
IGL_OpenGL => new OpenGLControl(),
IGL_OpenGL openGL => new OpenGLControl(openGL.InitGLState),
IGL_D3D11 d3d11 => new D3D11Control(d3d11.CreateSwapChain),
IGL_GDIPlus gdiPlus => new GDIPlusControl(gdiPlus.CreateControlRenderTarget),
_ => throw new InvalidOperationException()
Expand Down
13 changes: 11 additions & 2 deletions src/BizHawk.Bizware.Graphics/D3D11/D3D11Resources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ internal sealed class D3D11Resources : IDisposable
public ID3D11RasterizerState RasterizerState;

public FeatureLevel DeviceFeatureLevel;
public int MaxTextureDimension;
public bool PresentAllowTearing;

public D3D11RenderTarget CurRenderTarget;
public D3D11Pipeline CurPipeline;

public readonly HashSet<D3D11Texture2D> Textures = new();
public readonly HashSet<D3D11Pipeline> Pipelines = new();
public readonly HashSet<D3D11Texture2D> Textures = [ ];
public readonly HashSet<D3D11Pipeline> Pipelines = [ ];

public void CreateResources()
{
Expand Down Expand Up @@ -99,6 +100,14 @@ public void CreateResources()

DeviceFeatureLevel = Device.FeatureLevel;

MaxTextureDimension = DeviceFeatureLevel switch
{
FeatureLevel.Level_9_1 or FeatureLevel.Level_9_2 => 2048,
FeatureLevel.Level_9_3 => 4096,
FeatureLevel.Level_10_0 or FeatureLevel.Level_10_1 => 8192,
_ => ID3D11Resource.MaximumTexture2DSize,
};

var rd = new RasterizerDescription
{
CullMode = CullMode.None,
Expand Down
2 changes: 2 additions & 0 deletions src/BizHawk.Bizware.Graphics/D3D11/IGL_D3D11.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ public void Dispose()
_resources.Dispose();
}

public int MaxTextureDimension => _resources.MaxTextureDimension;

public void ClearColor(Color color)
=> Context.ClearRenderTargetView(CurRenderTarget?.RTV ?? _controlSwapChain.RTV, new(color.R, color.B, color.G, color.A));

Expand Down
3 changes: 3 additions & 0 deletions src/BizHawk.Bizware.Graphics/GDIPlus/IGL_GDIPlus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public void Dispose()
{
}

// maximum bitmap size doesn't seem to be well defined... we'll just use D3D11's maximum size
public int MaxTextureDimension => 16384;

internal SDGraphics GetCurrentGraphics()
=> CurRenderTarget?.TextureGraphics ?? _controlRenderTarget.BufferedGraphics.Graphics;

Expand Down
6 changes: 6 additions & 0 deletions src/BizHawk.Bizware.Graphics/Interfaces/IGL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ public interface IGL : IDisposable
/// </summary>
EDispMethod DispMethodEnum { get; }

/// <summary>
/// Returns the maximum size any dimension of a texture may have
/// This should be set on init, and therefore shouldn't need a graphics context active...
/// </summary>
int MaxTextureDimension { get; }

/// <summary>
/// Creates a texture with the specified dimensions
/// The texture will use a clamping address mode and nearest neighbor filtering by default
Expand Down
16 changes: 16 additions & 0 deletions src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ public IGL_OpenGL()
public void Dispose()
=> GL.Dispose();

/// <summary>
/// Should be called once the GL context is created
/// </summary>
public void InitGLState()
{
GL.GetInteger(GetPName.MaxTextureSize, out var maxTextureDimension);
if (maxTextureDimension == 0)
{
throw new($"Failed to get max texture size, GL error: {GL.GetError()}");
}

MaxTextureDimension = maxTextureDimension;
}

public int MaxTextureDimension { get; private set; }

public void ClearColor(Color color)
{
GL.ClearColor(color);
Expand Down
10 changes: 9 additions & 1 deletion src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
if (size.Width < 1) size.Width = 1;
if (size.Height < 1) size.Height = 1;

// if either of the dimensions exceed the maximum size of a texture, we need to constrain them
size.Width = Math.Min(size.Width, _gl.MaxTextureDimension);
size.Height = Math.Min(size.Height, _gl.MaxTextureDimension);

var fPadding = new FinalPresentation(size);
chain.AddFilter(fPadding, "padding");
fPadding.Config_PadOnly = true;
Expand Down Expand Up @@ -771,10 +775,14 @@ private FilterProgram UpdateSourceInternal(JobInfo job)
vw += padding.Horizontal;
vh += padding.Vertical;

//in case the user requested so much padding that the dimensions are now negative, just turn it to something small.
// in case the user requested so much padding that the dimensions are now negative, just turn it to something small.
if (vw < 1) vw = 1;
if (vh < 1) vh = 1;

// if either of the dimensions exceed the maximum size of a texture, we need to constrain them
vw = Math.Min(vw, _gl.MaxTextureDimension);
vh = Math.Min(vh, _gl.MaxTextureDimension);

BitmapBuffer bb = null;
ITexture2D videoTexture = null;
if (!simulate)
Expand Down
19 changes: 16 additions & 3 deletions src/BizHawk.Client.Common/DisplayManager/Filters/Gui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,22 @@ public override void Initialize()

public override void SetInputFormat(string channel, SurfaceState state)
{
var outputSize = state.SurfaceFormat.Size;
outputSize.Width *= Scale;
outputSize.Height *= Scale;
var inputSize = state.SurfaceFormat.Size;
var outputSize = new Size(inputSize.Width * Scale, inputSize.Height * Scale);
var maxTexDimension = FilterProgram.GL.MaxTextureDimension;
while (outputSize.Width > maxTexDimension || outputSize.Height > maxTexDimension)
{
outputSize.Width -= inputSize.Width;
outputSize.Height -= inputSize.Height;
Scale--;
}

// this hopefully never happens
if (outputSize.Width == 0 || outputSize.Height == 0)
{
throw new InvalidOperationException("Prescale input was too large for a texture");
}

var ss = new SurfaceState(new(outputSize), SurfaceDisposition.RenderTarget);
DeclareOutput(ss, channel);
}
Expand Down
5 changes: 3 additions & 2 deletions src/BizHawk.Client.EmuHawk/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,9 @@ IGL CheckRenderer(IGL gl)
// need to have a context active for checking renderer, will be disposed afterwards
using (new SDL2OpenGLContext(3, 2, true))
{
using var testIgl = new IGL_OpenGL();
_ = CheckRenderer(testIgl);
using var testOpenGL = new IGL_OpenGL();
testOpenGL.InitGLState();
_ = CheckRenderer(testOpenGL);
}

// don't return the same IGL, we don't want the test context to be part of this IGL
Expand Down

0 comments on commit dcfe553

Please sign in to comment.