cleanup display manager code

This commit is contained in:
adelikat 2019-12-31 11:14:10 -06:00
parent 7a3606d684
commit 0f33e2b1e7
13 changed files with 374 additions and 307 deletions

View File

@ -16,10 +16,8 @@
//BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize //BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using BizHawk.Common.NumberExtensions;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {

View File

@ -159,7 +159,7 @@ namespace BizHawk.Client.EmuHawk
/// these variables will track the dimensions of the last frame's (or the next frame? this is confusing) emulator native output size /// these variables will track the dimensions of the last frame's (or the next frame? this is confusing) emulator native output size
/// THIS IS OLD JUNK. I should get rid of it, I think. complex results from the last filter ingestion should be saved instead. /// THIS IS OLD JUNK. I should get rid of it, I think. complex results from the last filter ingestion should be saved instead.
/// </summary> /// </summary>
int currEmuWidth, currEmuHeight; private int currEmuWidth, currEmuHeight;
/// <summary> /// <summary>
/// additional pixels added at the unscaled level for the use of lua drawing. essentially increases the input video provider dimensions /// additional pixels added at the unscaled level for the use of lua drawing. essentially increases the input video provider dimensions
@ -906,7 +906,6 @@ namespace BizHawk.Client.EmuHawk
} }
case FilterProgram.ProgramStepType.FinalTarget: case FilterProgram.ProgramStepType.FinalTarget:
{ {
var size = (Size)step.Args;
inFinalTarget = true; inFinalTarget = true;
rtCurr = null; rtCurr = null;
_currentFilterProgram.CurrRenderTarget = null; _currentFilterProgram.CurrRenderTarget = null;
@ -955,9 +954,9 @@ namespace BizHawk.Client.EmuHawk
private bool? LastVsyncSetting; private bool? LastVsyncSetting;
private GraphicsControl LastVsyncSettingGraphicsControl; private GraphicsControl LastVsyncSettingGraphicsControl;
private Dictionary<string, DisplaySurface> MapNameToLuaSurface = new Dictionary<string,DisplaySurface>(); private readonly Dictionary<string, DisplaySurface> MapNameToLuaSurface = new Dictionary<string,DisplaySurface>();
private Dictionary<DisplaySurface, string> MapLuaSurfaceToName = new Dictionary<DisplaySurface, string>(); private readonly Dictionary<DisplaySurface, string> MapLuaSurfaceToName = new Dictionary<DisplaySurface, string>();
private Dictionary<string, SwappableDisplaySurfaceSet> LuaSurfaceSets = new Dictionary<string, SwappableDisplaySurfaceSet>(); private readonly Dictionary<string, SwappableDisplaySurfaceSet> LuaSurfaceSets = new Dictionary<string, SwappableDisplaySurfaceSet>();
/// <summary> /// <summary>
/// Peeks a locked lua surface, or returns null if it isn't locked /// Peeks a locked lua surface, or returns null if it isn't locked
@ -993,13 +992,17 @@ namespace BizHawk.Client.EmuHawk
currNativeHeight += ClientExtraPadding.Vertical; currNativeHeight += ClientExtraPadding.Vertical;
int width,height; int width,height;
if(name == "emu") { if (name == "emu")
{
width = currEmuWidth; width = currEmuWidth;
height = currEmuHeight; height = currEmuHeight;
width += GameExtraPadding.Horizontal; width += GameExtraPadding.Horizontal;
height += GameExtraPadding.Vertical; height += GameExtraPadding.Vertical;
} }
else if(name == "native") { width = currNativeWidth; height = currNativeHeight; } else if (name == "native")
{
width = currNativeWidth; height = currNativeHeight;
}
else throw new InvalidOperationException($"Unknown lua surface name: {name}"); else throw new InvalidOperationException($"Unknown lua surface name: {name}");
DisplaySurface ret = sdss.AllocateSurface(width, height, clear); DisplaySurface ret = sdss.AllocateSurface(width, height, clear);

View File

@ -12,9 +12,9 @@ namespace BizHawk.Client.EmuHawk
/// </summary> /// </summary>
public unsafe class DisplaySurface : IDisposable public unsafe class DisplaySurface : IDisposable
{ {
private Bitmap bmp; private Bitmap _bmp;
private BitmapData bmpdata; private BitmapData _bmpData;
private int[] pixels; private readonly int[] _pixels;
public unsafe void Clear() public unsafe void Clear()
{ {
@ -25,7 +25,7 @@ namespace BizHawk.Client.EmuHawk
public Bitmap PeekBitmap() public Bitmap PeekBitmap()
{ {
ToBitmap(); ToBitmap();
return bmp; return _bmp;
} }
/// <summary> /// <summary>
@ -34,7 +34,7 @@ namespace BizHawk.Client.EmuHawk
public Graphics GetGraphics() public Graphics GetGraphics()
{ {
ToBitmap(); ToBitmap();
return Graphics.FromImage(bmp); return Graphics.FromImage(_bmp);
} }
public unsafe void ToBitmap(bool copy=true) public unsafe void ToBitmap(bool copy=true)
@ -42,79 +42,101 @@ namespace BizHawk.Client.EmuHawk
if (_isBitmap) return; if (_isBitmap) return;
_isBitmap = true; _isBitmap = true;
if (bmp == null) if (_bmp == null)
{ {
bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); _bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
} }
if (copy) if (copy)
{ {
bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); _bmpData = _bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
int w = Width; int w = Width;
int h = Height; int h = Height;
int stride = bmpdata.Stride / 4; int stride = _bmpData.Stride / 4;
int* bmpbuf = (int*)bmpdata.Scan0.ToPointer(); int* bmpBuf = (int*)_bmpData.Scan0.ToPointer();
for (int y = 0, i = 0; y < h; y++) for (int y = 0, i = 0; y < h; y++)
{
for (int x = 0; x < w; x++) for (int x = 0; x < w; x++)
bmpbuf[y * stride + x] = pixels[i++]; {
bmpBuf[y * stride + x] = _pixels[i++];
}
}
bmp.UnlockBits(bmpdata); _bmp.UnlockBits(_bmpData);
} }
} }
bool _isBitmap; private bool _isBitmap;
public unsafe void FromBitmap(bool copy = true) public unsafe void FromBitmap(bool copy = true)
{ {
if (!_isBitmap) return; if (!_isBitmap)
{
return;
}
_isBitmap = false; _isBitmap = false;
if (copy) if (copy)
{ {
bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); _bmpData = _bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int w = Width; int w = Width;
int h = Height; int h = Height;
int stride = bmpdata.Stride / 4; int stride = _bmpData.Stride / 4;
int* bmpbuf = (int*)bmpdata.Scan0.ToPointer(); int* bmpBuf = (int*)_bmpData.Scan0.ToPointer();
for (int y = 0, i = 0; y < h; y++) for (int y = 0, i = 0; y < h; y++)
{
for (int x = 0; x < w; x++) for (int x = 0; x < w; x++)
pixels[i++] = bmpbuf[y * stride + x]; {
_pixels[i++] = bmpBuf[y * stride + x];
}
}
bmp.UnlockBits(bmpdata); _bmp.UnlockBits(_bmpData);
} }
} }
public DisplaySurface(int width, int height) public DisplaySurface(int width, int height)
{ {
// can't create a bitmap with zero dimensions, so for now, just bump it up to one // can't create a bitmap with zero dimensions, so for now, just bump it up to one
if (width == 0) width = 1; if (width == 0)
if (height == 0) height = 1; {
width = 1;
}
if (height == 0)
{
height = 1;
}
Width = width; Width = width;
Height = height; Height = height;
pixels = new int[width * height]; _pixels = new int[width * height];
LockPixels(); LockPixels();
} }
public int* PixelPtr => (int*)ptr; public int* PixelPtr => (int*)_ptr;
public int Stride => Width * 4; public int Stride => Width * 4;
void* ptr; private void* _ptr;
GCHandle handle; private GCHandle _handle;
void LockPixels() private void LockPixels()
{ {
UnlockPixels(); UnlockPixels();
handle = GCHandle.Alloc(pixels, GCHandleType.Pinned); _handle = GCHandle.Alloc(_pixels, GCHandleType.Pinned);
ptr = handle.AddrOfPinnedObject().ToPointer(); _ptr = _handle.AddrOfPinnedObject().ToPointer();
} }
private void UnlockPixels() private void UnlockPixels()
{ {
if(handle.IsAllocated) handle.Free(); if (_handle.IsAllocated)
{
_handle.Free();
}
} }
public int Width { get; } public int Width { get; }
@ -122,8 +144,8 @@ namespace BizHawk.Client.EmuHawk
public void Dispose() public void Dispose()
{ {
bmp?.Dispose(); _bmp?.Dispose();
bmp = null; _bmp = null;
UnlockPixels(); UnlockPixels();
} }
} }

View File

@ -182,7 +182,7 @@ namespace BizHawk.Client.EmuHawk.FilterManager
iosi.SurfaceFormat = currState.SurfaceFormat; iosi.SurfaceFormat = currState.SurfaceFormat;
f.SetInputFormat(channel, currState); f.SetInputFormat(channel, currState);
if (f.IsNOP) if (f.IsNop)
{ {
continue; continue;
} }

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using BizHawk.Client.EmuHawk.FilterManager; using BizHawk.Client.EmuHawk.FilterManager;
@ -16,20 +15,18 @@ using OpenTK;
// 4. In SetInputFormat(), use DeclareOutput to set the output based on your desires, or the provided input format. // 4. In SetInputFormat(), use DeclareOutput to set the output based on your desires, or the provided input format.
// 5. In Run(), the render target is already set. If using a texture, use InputTexture // 5. In Run(), the render target is already set. If using a texture, use InputTexture
// 6. In Run(), if supplying an output texture, use YieldOutput // 6. In Run(), if supplying an output texture, use YieldOutput
namespace BizHawk.Client.EmuHawk.Filters namespace BizHawk.Client.EmuHawk.Filters
{ {
public class BaseFilter public class BaseFilter
{ {
// initialization stuff // initialization stuff
public void BeginInitialization(FilterProgram program) { IOSurfaceInfos.Clear(); FilterProgram = program; } public void BeginInitialization(FilterProgram program) { _ioSurfaceInfos.Clear(); FilterProgram = program; }
public virtual void Initialize() { } public virtual void Initialize() { }
public virtual Size PresizeInput(string channel, Size size) { return size; } public virtual Size PresizeInput(string channel, Size size) => size;
public virtual Size PresizeOutput(string channel, Size size) { return size; } public virtual Size PresizeOutput(string channel, Size size) => size;
public virtual void SetInputFormat(string channel, SurfaceState state) { } //TODO - why a different param order than DeclareOutput? public virtual void SetInputFormat(string channel, SurfaceState state) { } //TODO - why a different param order than DeclareOutput?
public Dictionary<string, object> Parameters = new Dictionary<string, object>(); public Dictionary<string, object> Parameters = new Dictionary<string, object>();
public bool IsNOP { get => _IsNop; protected set => _IsNop = value; } public bool IsNop { get; set; }
private Boolean _IsNop = false;
// runtime signals // runtime signals
public virtual Vector2 UntransformPoint(string channel, Vector2 point) public virtual Vector2 UntransformPoint(string channel, Vector2 point)
@ -63,24 +60,34 @@ namespace BizHawk.Client.EmuHawk.Filters
InputTexture = tex; InputTexture = tex;
} }
public virtual void Run() { } public virtual void Run() { }
public Texture2d GetOutput() { return OutputTexture; } public Texture2d GetOutput() => _outputTexture;
// filter actions // filter actions
protected void YieldOutput(Texture2d tex) protected void YieldOutput(Texture2d tex)
{ {
OutputTexture = tex; _outputTexture = tex;
} }
protected FilterProgram FilterProgram; protected FilterProgram FilterProgram;
protected Texture2d InputTexture; protected Texture2d InputTexture;
private Texture2d OutputTexture; private Texture2d _outputTexture;
// setup utilities // setup utilities
protected IOSurfaceInfo DeclareInput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default") { return DeclareIO(SurfaceDirection.Input, channel, disposition); } protected IOSurfaceInfo DeclareInput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default")
protected IOSurfaceInfo DeclareOutput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default") { return DeclareIO(SurfaceDirection.Output, channel, disposition); } {
//TODO - why a different param order than DeclareOutput? return DeclareIO(SurfaceDirection.Input, channel, disposition);
}
protected RenderTarget GetTempTarget(int width, int height) { return FilterProgram.GetTempTarget(width, height); } protected IOSurfaceInfo DeclareOutput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default")
{
return DeclareIO(SurfaceDirection.Output, channel, disposition);
}
// TODO - why a different param order than DeclareOutput?
protected RenderTarget GetTempTarget(int width, int height)
{
return FilterProgram.GetTempTarget(width, height);
}
protected IOSurfaceInfo DeclareOutput(SurfaceState state, string channel = "default") protected IOSurfaceInfo DeclareOutput(SurfaceState state, string channel = "default")
{ {
@ -89,36 +96,51 @@ namespace BizHawk.Client.EmuHawk.Filters
return iosi; return iosi;
} }
public IOSurfaceInfo FindInput(string channel = "default") { return FindIOSurfaceInfo(channel, SurfaceDirection.Input); } public IOSurfaceInfo FindInput(string channel = "default")
public IOSurfaceInfo FindOutput(string channel = "default") { return FindIOSurfaceInfo(channel, SurfaceDirection.Output); } {
return FindIOSurfaceInfo(channel, SurfaceDirection.Input);
}
public IOSurfaceInfo FindOutput(string channel = "default")
{
return FindIOSurfaceInfo(channel, SurfaceDirection.Output);
}
private IOSurfaceInfo DeclareIO(SurfaceDirection direction, string channel, SurfaceDisposition disposition) private IOSurfaceInfo DeclareIO(SurfaceDirection direction, string channel, SurfaceDisposition disposition)
{ {
var iosi = new IOSurfaceInfo(); var iosi = new IOSurfaceInfo
iosi.SurfaceDirection = direction; {
iosi.Channel = channel; SurfaceDirection = direction,
iosi.SurfaceDisposition = disposition; Channel = channel,
IOSurfaceInfos.Add(iosi); SurfaceDisposition = disposition
};
_ioSurfaceInfos.Add(iosi);
return iosi; return iosi;
} }
private readonly List<IOSurfaceInfo> IOSurfaceInfos = new List<IOSurfaceInfo>(); private readonly List<IOSurfaceInfo> _ioSurfaceInfos = new List<IOSurfaceInfo>();
private IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction) private IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction)
{ {
foreach (var iosi in IOSurfaceInfos) foreach (var iosi in _ioSurfaceInfos)
{
if (iosi.Channel == channel && iosi.SurfaceDirection == direction) if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
{
return iosi; return iosi;
}
}
return null; return null;
} }
public class IOSurfaceInfo public class IOSurfaceInfo
{ {
public SurfaceFormat SurfaceFormat; public SurfaceFormat SurfaceFormat { get; set; }
public SurfaceDirection SurfaceDirection; public SurfaceDirection SurfaceDirection { get; set; }
public SurfaceDisposition SurfaceDisposition; public SurfaceDisposition SurfaceDisposition { get; set; }
public string Channel; public string Channel { get; set; }
} }
public enum SurfaceDirection public enum SurfaceDirection

View File

@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk.Filters
/// applies letterboxing logic to figure out how to fit the source dimensions into the target dimensions. /// applies letterboxing logic to figure out how to fit the source dimensions into the target dimensions.
/// In the future this could also apply rules like integer-only scaling, etc. /// In the future this could also apply rules like integer-only scaling, etc.
/// </summary> /// </summary>
class LetterboxingLogic public class LetterboxingLogic
{ {
/// <summary> /// <summary>
/// the location within the destination region of the output content (scaled and translated) /// the location within the destination region of the output content (scaled and translated)
@ -42,9 +42,11 @@ namespace BizHawk.Client.EmuHawk.Filters
sourceWidth = (int)virtualWidth; sourceWidth = (int)virtualWidth;
sourceHeight = (int)virtualHeight; sourceHeight = (int)virtualHeight;
//this doesnt make sense // this doesn't make sense
if (!maintainAspect) if (!maintainAspect)
{
maintainInteger = false; maintainInteger = false;
}
float widthScale = (float)targetWidth / sourceWidth; float widthScale = (float)targetWidth / sourceWidth;
float heightScale = (float)targetHeight / sourceHeight; float heightScale = (float)targetHeight / sourceHeight;
@ -67,44 +69,46 @@ namespace BizHawk.Client.EmuHawk.Filters
Vector2 VS = new Vector2(virtualWidth, virtualHeight); Vector2 VS = new Vector2(virtualWidth, virtualHeight);
Vector2 BS = new Vector2(textureWidth, textureHeight); Vector2 BS = new Vector2(textureWidth, textureHeight);
Vector2 AR = Vector2.Divide(VS, BS); Vector2 AR = Vector2.Divide(VS, BS);
float target_par = (AR.X / AR.Y); float targetPar = (AR.X / AR.Y);
Vector2 PS = new Vector2(1, 1); //this would malfunction for AR <= 0.5 or AR >= 2.0 Vector2 PS = new Vector2(1, 1); //this would malfunction for AR <= 0.5 or AR >= 2.0
for(;;) for(;;)
{ {
// TODO - would be good not to run this per frame.... // TODO - would be good not to run this per frame....
Vector2[] trials = new[] { Vector2[] trials =
{
PS + new Vector2(1, 0), PS + new Vector2(1, 0),
PS + new Vector2(0, 1), PS + new Vector2(0, 1),
PS + new Vector2(1, 1) PS + new Vector2(1, 1)
}; };
bool[] trials_limited = new bool[3] { false,false,false};
bool[] trialsLimited = new bool[3] { false,false,false};
int bestIndex = -1; int bestIndex = -1;
float bestValue = 1000.0f; float bestValue = 1000.0f;
for (int t = 0; t < trials.Length; t++) for (int t = 0; t < trials.Length; t++)
{ {
Vector2 vTrial = trials[t]; Vector2 vTrial = trials[t];
trials_limited[t] = false; trialsLimited[t] = false;
//check whether this is going to exceed our allotted area //check whether this is going to exceed our allotted area
int test_vw = (int)(vTrial.X * textureWidth); int testVw = (int)(vTrial.X * textureWidth);
int test_vh = (int)(vTrial.Y * textureHeight); int testVh = (int)(vTrial.Y * textureHeight);
if (test_vw > targetWidth) trials_limited[t] = true; if (testVw > targetWidth) trialsLimited[t] = true;
if (test_vh > targetHeight) trials_limited[t] = true; if (testVh > targetHeight) trialsLimited[t] = true;
// I. // I.
float test_ar = vTrial.X / vTrial.Y; float testAr = vTrial.X / vTrial.Y;
// II. // II.
// Vector2 calc = Vector2.Multiply(trials[t], VS); // Vector2 calc = Vector2.Multiply(trials[t], VS);
// float test_ar = calc.X / calc.Y; // float test_ar = calc.X / calc.Y;
// not clear which approach is superior // not clear which approach is superior
float deviation_linear = Math.Abs(test_ar - target_par); float deviationLinear = Math.Abs(testAr - targetPar);
float deviation_geom = test_ar / target_par; float deviationGeom = testAr / targetPar;
if (deviation_geom < 1) deviation_geom = 1.0f / deviation_geom; if (deviationGeom < 1) deviationGeom = 1.0f / deviationGeom;
float value = deviation_linear; float value = deviationLinear;
if (value < bestValue) if (value < bestValue)
{ {
bestIndex = t; bestIndex = t;
@ -117,7 +121,7 @@ namespace BizHawk.Client.EmuHawk.Filters
break; break;
// if the winner ran off the edge, bail out // if the winner ran off the edge, bail out
if (trials_limited[bestIndex]) if (trialsLimited[bestIndex])
break; break;
PS = trials[bestIndex]; PS = trials[bestIndex];
@ -137,13 +141,18 @@ namespace BizHawk.Client.EmuHawk.Filters
vh = (int)(heightScale * sourceHeight); vh = (int)(heightScale * sourceHeight);
} }
//theres only one sensible way to letterbox in case we're shrinking a dimension: "pan & scan" to the center // there's only one sensible way to letterbox in case we're shrinking a dimension: "pan & scan" to the center
// this is unlikely to be what the user wants except in the one case of maybe shrinking off some overscan area // this is unlikely to be what the user wants except in the one case of maybe shrinking off some overscan area
// instead, since we're more about biz than gaming, lets shrink the view to fit in the small dimension // instead, since we're more about biz than gaming, lets shrink the view to fit in the small dimension
if (targetWidth < vw) if (targetWidth < vw)
{
vw = targetWidth; vw = targetWidth;
}
if (targetHeight < vh) if (targetHeight < vh)
{
vh = targetHeight; vh = targetHeight;
}
//determine letterboxing parameters //determine letterboxing parameters
vx = (targetWidth - vw) / 2; vx = (targetWidth - vw) / 2;
@ -151,13 +160,12 @@ namespace BizHawk.Client.EmuHawk.Filters
// zero 09-oct-2014 - changed this for TransformPoint. scenario: basic 1x (but system-specified AR) NES window. // zero 09-oct-2014 - changed this for TransformPoint. scenario: basic 1x (but system-specified AR) NES window.
// vw would be 293 but WidthScale would be 1.0. I think it should be something different. // vw would be 293 but WidthScale would be 1.0. I think it should be something different.
//FinalPresentation doesnt use the LL.WidthScale, so this is unlikely to be breaking anything old that depends on it // FinalPresentation doesn't use the LL.WidthScale, so this is unlikely to be breaking anything old that depends on it
// WidthScale = widthScale; // WidthScale = widthScale;
// HeightScale = heightScale; // HeightScale = heightScale;
WidthScale = (float)vw / oldSourceWidth; WidthScale = (float)vw / oldSourceWidth;
HeightScale = (float)vh / oldSourceHeight; HeightScale = (float)vh / oldSourceHeight;
} }
} }
public class FinalPresentation : BaseFilter public class FinalPresentation : BaseFilter
@ -168,23 +176,22 @@ namespace BizHawk.Client.EmuHawk.Filters
} }
public eFilterOption FilterOption = eFilterOption.None; public eFilterOption FilterOption = eFilterOption.None;
public RetroShaderChain BicubicFilter;
public FinalPresentation(Size size) public FinalPresentation(Size size)
{ {
this.OutputSize = size; this.OutputSize = size;
} }
Size OutputSize, InputSize; private Size OutputSize, InputSize;
public Size TextureSize, VirtualTextureSize; public Size TextureSize, VirtualTextureSize;
public int BackgroundColor; public int BackgroundColor;
public bool AutoPrescale; public bool AutoPrescale;
public IGuiRenderer GuiRenderer; public IGuiRenderer GuiRenderer;
public bool Flip; public bool Flip;
public IGL GL; public IGL GL;
bool nop; private bool nop;
LetterboxingLogic LL; private LetterboxingLogic LL;
Size ContentSize; private Size ContentSize;
public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly; public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly;
@ -278,10 +285,10 @@ namespace BizHawk.Client.EmuHawk.Filters
ContentSize = new Size(LL.vw,LL.vh); ContentSize = new Size(LL.vw,LL.vh);
if (InputSize == OutputSize) //any reason we need to check vx and vy? if (InputSize == OutputSize) //any reason we need to check vx and vy?
IsNOP = true; IsNop = true;
} }
public Size GetContentSize() { return ContentSize; } public Size GetContentSize() => ContentSize;
public override Vector2 UntransformPoint(string channel, Vector2 point) public override Vector2 UntransformPoint(string channel, Vector2 point)
{ {
@ -350,10 +357,10 @@ namespace BizHawk.Client.EmuHawk.Filters
public override void SetInputFormat(string channel, SurfaceState state) public override void SetInputFormat(string channel, SurfaceState state)
{ {
var OutputSize = state.SurfaceFormat.Size; var outputSize = state.SurfaceFormat.Size;
OutputSize.Width *= Scale; outputSize.Width *= Scale;
OutputSize.Height *= Scale; outputSize.Height *= Scale;
var ss = new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget); var ss = new SurfaceState(new SurfaceFormat(outputSize), SurfaceDisposition.RenderTarget);
DeclareOutput(ss, channel); DeclareOutput(ss, channel);
} }
@ -370,8 +377,8 @@ namespace BizHawk.Client.EmuHawk.Filters
public class AutoPrescaleFilter : BaseFilter public class AutoPrescaleFilter : BaseFilter
{ {
Size OutputSize, InputSize; private Size OutputSize, InputSize;
int XIS, YIS; private int XIS, YIS;
public override void Initialize() public override void Initialize()
{ {
@ -391,7 +398,7 @@ namespace BizHawk.Client.EmuHawk.Filters
if (XIS <= 1 && YIS <= 1) if (XIS <= 1 && YIS <= 1)
{ {
IsNOP = true; IsNop = true;
} }
else else
{ {
@ -411,14 +418,15 @@ namespace BizHawk.Client.EmuHawk.Filters
return base.PresizeOutput(channel, size); return base.PresizeOutput(channel, size);
} }
public override Size PresizeInput(string channel, Size insize) public override Size PresizeInput(string channel, Size inSize)
{ {
InputSize = insize; InputSize = inSize;
return insize; return inSize;
} }
public override void Run() public override void Run()
{ {
FilterProgram.GuiRenderer.Begin(OutputSize); //hope this didnt change FilterProgram.GuiRenderer.Begin(OutputSize); // hope this didn't change
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNoneCopy); FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNoneCopy);
FilterProgram.GuiRenderer.Modelview.Scale(XIS,YIS); FilterProgram.GuiRenderer.Modelview.Scale(XIS,YIS);
FilterProgram.GuiRenderer.Draw(InputTexture); FilterProgram.GuiRenderer.Draw(InputTexture);
@ -437,11 +445,11 @@ namespace BizHawk.Client.EmuHawk.Filters
DeclareOutput(state); DeclareOutput(state);
} }
Texture2d Texture; private Texture2d _texture;
public void SetTexture(Texture2d tex) public void SetTexture(Texture2d tex)
{ {
Texture = tex; _texture = tex;
} }
public override void Run() public override void Run()
@ -449,7 +457,7 @@ namespace BizHawk.Client.EmuHawk.Filters
var outSize = FindOutput().SurfaceFormat.Size; var outSize = FindOutput().SurfaceFormat.Size;
FilterProgram.GuiRenderer.Begin(outSize); FilterProgram.GuiRenderer.Begin(outSize);
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNormal); FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNormal);
FilterProgram.GuiRenderer.Draw(Texture); FilterProgram.GuiRenderer.Draw(_texture);
FilterProgram.GuiRenderer.End(); FilterProgram.GuiRenderer.End();
} }
} }

View File

@ -3,34 +3,25 @@
// https://github.com/libretro/common-shaders/ // https://github.com/libretro/common-shaders/
using System; using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Drawing; using System.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk;
using BizHawk.Client.EmuHawk.FilterManager; using BizHawk.Client.EmuHawk.FilterManager;
using BizHawk.Bizware.BizwareGL; using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace BizHawk.Client.EmuHawk.Filters namespace BizHawk.Client.EmuHawk.Filters
{ {
public class RetroShaderChain : IDisposable public class RetroShaderChain : IDisposable
{ {
static System.Text.RegularExpressions.Regex rxInclude = new Regex(@"^(\s)?\#include(\s)+(""|<)(.*)?(""|>)", RegexOptions.Multiline | RegexOptions.IgnoreCase); private static readonly Regex RxInclude = new Regex(@"^(\s)?\#include(\s)+(""|<)(.*)?(""|>)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
static string ResolveIncludes(string content, string baseDirectory) static string ResolveIncludes(string content, string baseDirectory)
{ {
for (; ; ) for (; ; )
{ {
var match = rxInclude.Match(content); var match = RxInclude.Match(content);
if(match.Value == "") break; if(match.Value == "") break;
string fname = match.Groups[4].Value; string fname = match.Groups[4].Value;
fname = Path.Combine(baseDirectory,fname); fname = Path.Combine(baseDirectory,fname);
@ -43,7 +34,7 @@ namespace BizHawk.Client.EmuHawk.Filters
public RetroShaderChain(IGL owner, RetroShaderPreset preset, string baseDirectory, bool debug = false) public RetroShaderChain(IGL owner, RetroShaderPreset preset, string baseDirectory, bool debug = false)
{ {
Owner = owner; Owner = owner;
this.Preset = preset; Preset = preset;
Passes = preset.Passes.ToArray(); Passes = preset.Passes.ToArray();
Errors = ""; Errors = "";
@ -82,9 +73,16 @@ namespace BizHawk.Client.EmuHawk.Filters
public void Dispose() public void Dispose()
{ {
if (_isDisposed) return; if (_isDisposed)
{
return;
}
foreach (var s in Shaders) foreach (var s in Shaders)
{
s.Dispose(); s.Dispose();
}
_isDisposed = true; _isDisposed = true;
} }
@ -107,13 +105,13 @@ namespace BizHawk.Client.EmuHawk.Filters
public RetroShaderPreset(Stream stream) public RetroShaderPreset(Stream stream)
{ {
var content = new StreamReader(stream).ReadToEnd(); var content = new StreamReader(stream).ReadToEnd();
Dictionary<string, string> dict = new Dictionary<string, string>(); var dict = new Dictionary<string, string>();
//parse the key-value-pair format of the file //parse the key-value-pair format of the file
content = content.Replace("\r", ""); content = content.Replace("\r", "");
foreach (var _line in content.Split('\n')) foreach (var splitLine in content.Split('\n'))
{ {
var line = _line.Trim(); var line = splitLine.Trim();
if (line.StartsWith("#")) continue; //lines that are solely comments if (line.StartsWith("#")) continue; //lines that are solely comments
if (line == "") continue; //empty line if (line == "") continue; //empty line
int eq = line.IndexOf('='); int eq = line.IndexOf('=');
@ -137,8 +135,7 @@ namespace BizHawk.Client.EmuHawk.Filters
int nShaders = FetchInt(dict, "shaders", 0); int nShaders = FetchInt(dict, "shaders", 0);
for (int i = 0; i < nShaders; i++) for (int i = 0; i < nShaders; i++)
{ {
ShaderPass sp = new ShaderPass(); var sp = new ShaderPass { Index = i };
sp.Index = i;
Passes.Add(sp); Passes.Add(sp);
sp.InputFilterLinear = FetchBool(dict, $"filter_linear{i}", false); //Should this value not be defined, the filtering option is implementation defined. sp.InputFilterLinear = FetchBool(dict, $"filter_linear{i}", false); //Should this value not be defined, the filtering option is implementation defined.
@ -159,24 +156,31 @@ namespace BizHawk.Client.EmuHawk.Filters
sp.Scale.Y = FetchFloat(dict, $"scale_y{i}", 1); sp.Scale.Y = FetchFloat(dict, $"scale_y{i}", 1);
float scale = FetchFloat(dict, $"scale{i}", -999); float scale = FetchFloat(dict, $"scale{i}", -999);
if (scale != -999) if (scale != -999)
{
sp.Scale.X = sp.Scale.Y = FetchFloat(dict, $"scale{i}", 1); sp.Scale.X = sp.Scale.Y = FetchFloat(dict, $"scale{i}", 1);
}
//TODO - LUTs //TODO - LUTs
} }
} }
public List<ShaderPass> Passes = new List<ShaderPass>(); public List<ShaderPass> Passes { get; set; } = new List<ShaderPass>();
/// <summary> /// <summary>
/// Indicates whether any of the passes contain GLSL filenames (these are invalid now) /// Indicates whether any of the passes contain GLSL filenames (these are invalid now)
/// </summary> /// </summary>
public bool ContainsGLSL public bool ContainsGlsl
{ {
get get
{ {
foreach (var pass in Passes) foreach (var pass in Passes)
if (Path.GetExtension(pass.ShaderPath).ToLowerInvariant() == ".glsl") {
if (Path.GetExtension(pass.ShaderPath)?.ToLowerInvariant() == ".glsl")
{
return true; return true;
}
}
return false; return false;
} }
} }
@ -198,64 +202,51 @@ namespace BizHawk.Client.EmuHawk.Filters
public Vector2 Scale; public Vector2 Scale;
} }
string FetchString(Dictionary<string, string> dict, string key, string @default) private string FetchString(IDictionary<string, string> dict, string key, string @default)
{ {
string str; return dict.TryGetValue(key, out var str) ? str : @default;
if (dict.TryGetValue(key, out str))
return str;
else return @default;
} }
int FetchInt(Dictionary<string, string> dict, string key, int @default) private int FetchInt(IDictionary<string, string> dict, string key, int @default)
{ {
string str; return dict.TryGetValue(key, out var str) ? int.Parse(str) : @default;
if (dict.TryGetValue(key, out str))
return int.Parse(str);
else return @default;
} }
float FetchFloat(Dictionary<string, string> dict, string key, float @default) private float FetchFloat(IDictionary<string, string> dict, string key, float @default)
{ {
string str; return dict.TryGetValue(key, out var str) ? float.Parse(str) : @default;
if (dict.TryGetValue(key, out str))
return float.Parse(str);
else return @default;
} }
bool FetchBool(Dictionary<string, string> dict, string key, bool @default) private bool FetchBool(IDictionary<string, string> dict, string key, bool @default)
{ {
string str; return dict.TryGetValue(key, out var str) ? ParseBool(str) : @default;
if (dict.TryGetValue(key, out str))
return ParseBool(str);
else return @default;
} }
private bool ParseBool(string value)
bool ParseBool(string value)
{ {
if (value == "1") return true; if (value == "1") return true;
if (value == "0") return false; if (value == "0") return false;
value = value.ToLower(); value = value.ToLower();
if (value == "true") return true; if (value == "true") return true;
if (value == "false") return false; if (value == "false") return false;
throw new InvalidOperationException("Unparseable bool in CGP file content"); throw new InvalidOperationException("Unparsable bool in CGP file content");
} }
} }
public class RetroShaderPass : BaseFilter public class RetroShaderPass : BaseFilter
{ {
RetroShaderChain RSC; private readonly RetroShaderChain _rsc;
RetroShaderPreset.ShaderPass SP; private readonly RetroShaderPreset.ShaderPass _sp;
int RSI; private readonly int _rsi;
Size OutputSize; private Size _outputSize;
public override string ToString() => $"{nameof(RetroShaderPass)}[#{RSI}]"; public override string ToString() => $"{nameof(RetroShaderPass)}[#{_rsi}]";
public RetroShaderPass(RetroShaderChain RSC, int index) public RetroShaderPass(RetroShaderChain rsc, int index)
{ {
this.RSC = RSC; _rsc = rsc;
this.RSI = index; _rsi = index;
this.SP = RSC.Passes[index]; _sp = _rsc.Passes[index];
} }
public override void Initialize() public override void Initialize()
@ -265,59 +256,66 @@ namespace BizHawk.Client.EmuHawk.Filters
public override void SetInputFormat(string channel, SurfaceState state) public override void SetInputFormat(string channel, SurfaceState state)
{ {
Size insize = state.SurfaceFormat.Size; Size inSize = state.SurfaceFormat.Size;
if (SP.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) OutputSize.Width = (int)SP.Scale.X; if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) _outputSize.Width = (int)_sp.Scale.X;
if (SP.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) OutputSize.Width = (int)SP.Scale.Y; if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) _outputSize.Width = (int)_sp.Scale.Y;
if (SP.ScaleTypeX == RetroShaderPreset.ScaleType.Source) OutputSize.Width = (int)(insize.Width * SP.Scale.X); if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Source) _outputSize.Width = (int)(inSize.Width * _sp.Scale.X);
if (SP.ScaleTypeY == RetroShaderPreset.ScaleType.Source) OutputSize.Height = (int)(insize.Height * SP.Scale.Y); if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Source) _outputSize.Height = (int)(inSize.Height * _sp.Scale.Y);
var outState = new SurfaceState(); DeclareOutput(new SurfaceState
outState.SurfaceFormat = new SurfaceFormat(OutputSize); {
outState.SurfaceDisposition = SurfaceDisposition.RenderTarget; SurfaceFormat = new SurfaceFormat(_outputSize),
DeclareOutput(outState); SurfaceDisposition = SurfaceDisposition.RenderTarget
});
} }
public override Size PresizeOutput(string channel, Size size) public override Size PresizeOutput(string channel, Size size)
{ {
OutputSize = size; _outputSize = size;
return size; return size;
} }
public override Size PresizeInput(string channel, Size insize) public override Size PresizeInput(string channel, Size inSize)
{ {
Size outsize = insize; Size outsize = inSize;
if (SP.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) outsize.Width = (int)SP.Scale.X; if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Absolute) outsize.Width = (int)_sp.Scale.X;
if (SP.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) outsize.Width = (int)SP.Scale.Y; if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Absolute) outsize.Width = (int)_sp.Scale.Y;
if (SP.ScaleTypeX == RetroShaderPreset.ScaleType.Source) outsize.Width = (int)(insize.Width * SP.Scale.X); if (_sp.ScaleTypeX == RetroShaderPreset.ScaleType.Source) outsize.Width = (int)(inSize.Width * _sp.Scale.X);
if (SP.ScaleTypeY == RetroShaderPreset.ScaleType.Source) outsize.Height = (int)(insize.Height * SP.Scale.Y); if (_sp.ScaleTypeY == RetroShaderPreset.ScaleType.Source) outsize.Height = (int)(inSize.Height * _sp.Scale.Y);
return outsize; return outsize;
} }
public override void Run() public override void Run()
{ {
var shader = RSC.Shaders[RSI]; var shader = _rsc.Shaders[_rsi];
shader.Bind(); shader.Bind();
// apply all parameters to this shader.. even if it was meant for other shaders. kind of lame. // apply all parameters to this shader.. even if it was meant for other shaders. kind of lame.
if(Parameters != null) if(Parameters != null)
{
foreach (var kvp in Parameters) foreach (var kvp in Parameters)
{ {
if (kvp.Value is float) if (kvp.Value is float value)
shader.Pipeline[kvp.Key].Set((float)kvp.Value); {
shader.Pipeline[kvp.Key].Set(value);
}
}
} }
var input = InputTexture; var input = InputTexture;
if (SP.InputFilterLinear) if (_sp.InputFilterLinear)
{
InputTexture.SetFilterLinear(); InputTexture.SetFilterLinear();
}
else else
{
InputTexture.SetFilterNearest(); InputTexture.SetFilterNearest();
RSC.Shaders[RSI].Run(input, input.Size, OutputSize, InputTexture.IsUpsideDown); }
_rsc.Shaders[_rsi].Run(input, input.Size, _outputSize, InputTexture.IsUpsideDown);
// maintain invariant.. i think. // maintain invariant.. i think.
InputTexture.SetFilterNearest(); InputTexture.SetFilterNearest();
} }
} }
} }

View File

@ -9,12 +9,12 @@ namespace BizHawk.Client.EmuHawk.Filters
{ {
public SourceImage(Size size) public SourceImage(Size size)
{ {
Size = size; _size = size;
} }
private readonly Size Size; private readonly Size _size;
public Texture2d Texture; public Texture2d Texture { get; set; }
public override void Run() public override void Run()
{ {
@ -23,7 +23,7 @@ namespace BizHawk.Client.EmuHawk.Filters
public override void Initialize() public override void Initialize()
{ {
DeclareOutput(new SurfaceState(new SurfaceFormat(Size), SurfaceDisposition.Texture)); DeclareOutput(new SurfaceState(new SurfaceFormat(_size), SurfaceDisposition.Texture));
} }
public override void SetInputFormat(string channel, SurfaceState format) public override void SetInputFormat(string channel, SurfaceState format)
@ -35,7 +35,7 @@ namespace BizHawk.Client.EmuHawk.Filters
/// <summary> /// <summary>
/// transforms an input texture to an output render target (by rendering it) /// transforms an input texture to an output render target (by rendering it)
/// </summary> /// </summary>
class Render : BaseFilter public class Render : BaseFilter
{ {
public override void Initialize() public override void Initialize()
{ {
@ -57,7 +57,7 @@ namespace BizHawk.Client.EmuHawk.Filters
} }
} }
class Resolve : BaseFilter public class Resolve : BaseFilter
{ {
public override void Initialize() public override void Initialize()
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Drawing;
using System.Collections.Generic; using System.Collections.Generic;
using BizHawk.Bizware.BizwareGL; using BizHawk.Bizware.BizwareGL;
@ -7,48 +8,53 @@ namespace BizHawk.Client.EmuHawk
{ {
/// <summary> /// <summary>
/// Recycles a pair of temporary render targets, as long as the dimensions match. /// Recycles a pair of temporary render targets, as long as the dimensions match.
/// When the dimensions dont match, a new one will be allocated /// When the dimensions don't match, a new one will be allocated
/// </summary> /// </summary>
public class RenderTargetFrugalizer : IDisposable public class RenderTargetFrugalizer : IDisposable
{ {
public RenderTargetFrugalizer(IGL gl) public RenderTargetFrugalizer(IGL gl)
{ {
GL = gl; _gl = gl;
ResetList(); ResetList();
} }
public void Dispose() public void Dispose()
{ {
foreach (var ct in CurrentRenderTargets) foreach (var ct in _currentRenderTargets)
if (ct != null) {
ct.Dispose(); ct?.Dispose();
}
ResetList(); ResetList();
} }
void ResetList() private void ResetList()
{ {
CurrentRenderTargets = new List<RenderTarget>(); _currentRenderTargets = new List<RenderTarget> { null, null };
CurrentRenderTargets.Add(null);
CurrentRenderTargets.Add(null);
} }
IGL GL; private readonly IGL _gl;
List<RenderTarget> CurrentRenderTargets; private List<RenderTarget> _currentRenderTargets;
public RenderTarget Get(Size dimensions)
{
return Get(dimensions.Width, dimensions.Height);
}
public RenderTarget Get(System.Drawing.Size dimensions) { return Get(dimensions.Width, dimensions.Height); }
public RenderTarget Get(int width, int height) public RenderTarget Get(int width, int height)
{ {
//get the current entry //get the current entry
RenderTarget CurrentRenderTarget = CurrentRenderTargets[0]; RenderTarget currentRenderTarget = _currentRenderTargets[0];
//check if its rotten and needs recreating //check if its rotten and needs recreating
if (CurrentRenderTarget == null || CurrentRenderTarget.Texture2d.IntWidth != width || CurrentRenderTarget.Texture2d.IntHeight != height) if (currentRenderTarget == null
|| currentRenderTarget.Texture2d.IntWidth != width
|| currentRenderTarget.Texture2d.IntHeight != height)
{ {
// needs recreating. be sure to kill the old one... // needs recreating. be sure to kill the old one...
if (CurrentRenderTarget != null) currentRenderTarget?.Dispose();
CurrentRenderTarget.Dispose();
// and make a new one // and make a new one
CurrentRenderTarget = GL.CreateRenderTarget(width, height); currentRenderTarget = _gl.CreateRenderTarget(width, height);
} }
else else
{ {
@ -56,10 +62,10 @@ namespace BizHawk.Client.EmuHawk
} }
// now shuffle the buffers // now shuffle the buffers
CurrentRenderTargets[0] = CurrentRenderTargets[1]; _currentRenderTargets[0] = _currentRenderTargets[1];
CurrentRenderTargets[1] = CurrentRenderTarget; _currentRenderTargets[1] = currentRenderTarget;
return CurrentRenderTarget; return currentRenderTarget;
} }
} }
} }

View File

@ -4,13 +4,13 @@ namespace BizHawk.Client.EmuHawk
{ {
/// <summary> /// <summary>
/// encapsulates thread-safe concept of pending/current display surfaces, reusing buffers where matching /// encapsulates thread-safe concept of pending/current display surfaces, reusing buffers where matching
/// sizes are available and keeping them cleaned up when they dont seem like theyll need to be used anymore /// sizes are available and keeping them cleaned up when they don't seem like they'll need to be used anymore
/// </summary> /// </summary>
public class SwappableDisplaySurfaceSet public class SwappableDisplaySurfaceSet
{ {
private DisplaySurface Pending, Current; private DisplaySurface _pending, _current;
private bool IsPending; private bool _isPending;
private readonly Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>(); private readonly Queue<DisplaySurface> _releasedSurfaces = new Queue<DisplaySurface>();
/// <summary> /// <summary>
/// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested /// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested
@ -22,16 +22,22 @@ namespace BizHawk.Client.EmuHawk
DisplaySurface trial; DisplaySurface trial;
lock (this) lock (this)
{ {
if (ReleasedSurfaces.Count == 0) break; if (_releasedSurfaces.Count == 0) break;
trial = ReleasedSurfaces.Dequeue(); trial = _releasedSurfaces.Dequeue();
} }
if (trial.Width == width && trial.Height == height) if (trial.Width == width && trial.Height == height)
{ {
if (needsClear) trial.Clear(); if (needsClear)
{
trial.Clear();
}
return trial; return trial;
} }
trial.Dispose(); trial.Dispose();
} }
return new DisplaySurface(width, height); return new DisplaySurface(width, height);
} }
@ -42,15 +48,15 @@ namespace BizHawk.Client.EmuHawk
{ {
lock (this) lock (this)
{ {
if (Pending != null) ReleasedSurfaces.Enqueue(Pending); if (_pending != null) _releasedSurfaces.Enqueue(_pending);
Pending = newPending; _pending = newPending;
IsPending = true; _isPending = true;
} }
} }
public void ReleaseSurface(DisplaySurface surface) public void ReleaseSurface(DisplaySurface surface)
{ {
lock (this) ReleasedSurfaces.Enqueue(surface); lock (this) _releasedSurfaces.Enqueue(surface);
} }
/// <summary> /// <summary>
@ -60,15 +66,16 @@ namespace BizHawk.Client.EmuHawk
{ {
lock (this) lock (this)
{ {
if (IsPending) if (_isPending)
{ {
if (Current != null) ReleasedSurfaces.Enqueue(Current); if (_current != null) _releasedSurfaces.Enqueue(_current);
Current = Pending; _current = _pending;
Pending = null; _pending = null;
IsPending = false; _isPending = false;
} }
} }
return Current;
return _current;
} }
} }
} }

View File

@ -12,13 +12,13 @@ namespace BizHawk.Client.EmuHawk
{ {
public TextureFrugalizer(IGL gl) public TextureFrugalizer(IGL gl)
{ {
GL = gl; _gl = gl;
ResetList(); ResetList();
} }
public void Dispose() public void Dispose()
{ {
foreach (var ct in CurrentTextures) foreach (var ct in _currentTextures)
{ {
ct?.Dispose(); ct?.Dispose();
} }
@ -26,13 +26,13 @@ namespace BizHawk.Client.EmuHawk
ResetList(); ResetList();
} }
void ResetList() private void ResetList()
{ {
CurrentTextures = new List<Texture2d> { null, null }; _currentTextures = new List<Texture2d> { null, null };
} }
private readonly IGL GL; private readonly IGL _gl;
private List<Texture2d> CurrentTextures; private List<Texture2d> _currentTextures;
public Texture2d Get(DisplaySurface ds) public Texture2d Get(DisplaySurface ds)
{ {
@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk
public Texture2d Get(BitmapBuffer bb) public Texture2d Get(BitmapBuffer bb)
{ {
//get the current entry //get the current entry
Texture2d currentTexture = CurrentTextures[0]; Texture2d currentTexture = _currentTextures[0];
// TODO - its a bit cruddy here that we dont respect the current texture HasAlpha condition (in fact, there's no such concept) // TODO - its a bit cruddy here that we dont respect the current texture HasAlpha condition (in fact, there's no such concept)
// we might need to deal with that in the future to fix some bugs. // we might need to deal with that in the future to fix some bugs.
@ -53,17 +53,17 @@ namespace BizHawk.Client.EmuHawk
//needs recreating. be sure to kill the old one... //needs recreating. be sure to kill the old one...
currentTexture?.Dispose(); currentTexture?.Dispose();
//and make a new one //and make a new one
currentTexture = GL.LoadTexture(bb); currentTexture = _gl.LoadTexture(bb);
} }
else else
{ {
//its good! just load in the data //its good! just load in the data
GL.LoadTextureData(currentTexture, bb); _gl.LoadTextureData(currentTexture, bb);
} }
//now shuffle the buffers //now shuffle the buffers
CurrentTextures[0] = CurrentTextures[1]; _currentTextures[0] = _currentTextures[1];
CurrentTextures[1] = currentTexture; _currentTextures[1] = currentTexture;
//deterministic state, i guess //deterministic state, i guess
currentTexture.SetFilterNearest(); currentTexture.SetFilterNearest();

View File

@ -202,7 +202,7 @@ namespace BizHawk.Client.EmuHawk
using (var stream = File.OpenRead(choice)) using (var stream = File.OpenRead(choice))
{ {
var cgp = new BizHawk.Client.EmuHawk.Filters.RetroShaderPreset(stream); var cgp = new BizHawk.Client.EmuHawk.Filters.RetroShaderPreset(stream);
if (cgp.ContainsGLSL) if (cgp.ContainsGlsl)
{ {
MessageBox.Show("Specified CGP contains references to .glsl files. This is illegal. Use .cg"); MessageBox.Show("Specified CGP contains references to .glsl files. This is illegal. Use .cg");
return; return;

View File

@ -271,6 +271,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Justifier/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Justifier/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=keepalives/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=keepalives/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=KEYMENU/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=KEYMENU/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Letterboxing/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Libretro/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Libretro/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lightgun/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Lightgun/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lmsv/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Lmsv/@EntryIndexedValue">True</s:Boolean>
@ -319,6 +320,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=preload/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=preload/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Prereqs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=prescale/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Presize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quantizing/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=quantizing/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=quickload/@EntryIndexedValue">True</s:Boolean>
@ -368,6 +370,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Underruns/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Underruns/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uninitialize/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Uninitialize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unmerge/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=unmerge/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unparsable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unpause/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=unpause/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unpaused/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=unpaused/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unpausing/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Unpausing/@EntryIndexedValue">True</s:Boolean>