cleanup display manager code
This commit is contained in:
parent
7a3606d684
commit
0f33e2b1e7
|
@ -16,10 +16,8 @@
|
|||
|
||||
//BizHawk says: adapted from https://github.com/inexorabletash/PcxFileType/blob/master/Quantize
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//TODO
|
||||
//we could flag textures as 'actually' render targets (keep a reference to the render target?) which could allow us to convert between them more quickly in some cases
|
||||
// TODO
|
||||
// we could flag textures as 'actually' render targets (keep a reference to the render target?) which could allow us to convert between them more quickly in some cases
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
@ -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
|
||||
/// THIS IS OLD JUNK. I should get rid of it, I think. complex results from the last filter ingestion should be saved instead.
|
||||
/// </summary>
|
||||
int currEmuWidth, currEmuHeight;
|
||||
private int currEmuWidth, currEmuHeight;
|
||||
|
||||
/// <summary>
|
||||
/// 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:
|
||||
{
|
||||
var size = (Size)step.Args;
|
||||
inFinalTarget = true;
|
||||
rtCurr = null;
|
||||
_currentFilterProgram.CurrRenderTarget = null;
|
||||
|
@ -927,17 +926,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
Debug.Assert(inFinalTarget);
|
||||
|
||||
//wait for vsync to begin
|
||||
// wait for vsync to begin
|
||||
if (alternateVsync) dx9.AlternateVsyncPass(0);
|
||||
|
||||
//present and conclude drawing
|
||||
// present and conclude drawing
|
||||
presentationPanel.GraphicsControl.SwapBuffers();
|
||||
|
||||
//wait for vsync to end
|
||||
// wait for vsync to end
|
||||
if (alternateVsync) dx9.AlternateVsyncPass(1);
|
||||
|
||||
//nope. don't do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything
|
||||
//presentationPanel.GraphicsControl.End();
|
||||
// nope. don't do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything
|
||||
// presentationPanel.GraphicsControl.End();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -955,9 +954,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
private bool? LastVsyncSetting;
|
||||
private GraphicsControl LastVsyncSettingGraphicsControl;
|
||||
|
||||
private Dictionary<string, DisplaySurface> MapNameToLuaSurface = new Dictionary<string,DisplaySurface>();
|
||||
private Dictionary<DisplaySurface, string> MapLuaSurfaceToName = new Dictionary<DisplaySurface, string>();
|
||||
private Dictionary<string, SwappableDisplaySurfaceSet> LuaSurfaceSets = new Dictionary<string, SwappableDisplaySurfaceSet>();
|
||||
private readonly Dictionary<string, DisplaySurface> MapNameToLuaSurface = new Dictionary<string,DisplaySurface>();
|
||||
private readonly Dictionary<DisplaySurface, string> MapLuaSurfaceToName = new Dictionary<DisplaySurface, string>();
|
||||
private readonly Dictionary<string, SwappableDisplaySurfaceSet> LuaSurfaceSets = new Dictionary<string, SwappableDisplaySurfaceSet>();
|
||||
|
||||
/// <summary>
|
||||
/// Peeks a locked lua surface, or returns null if it isn't locked
|
||||
|
@ -993,13 +992,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
currNativeHeight += ClientExtraPadding.Vertical;
|
||||
|
||||
int width,height;
|
||||
if(name == "emu") {
|
||||
if (name == "emu")
|
||||
{
|
||||
width = currEmuWidth;
|
||||
height = currEmuHeight;
|
||||
width += GameExtraPadding.Horizontal;
|
||||
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}");
|
||||
|
||||
DisplaySurface ret = sdss.AllocateSurface(width, height, clear);
|
||||
|
@ -1018,7 +1021,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
DisplaySurface surfLocked = null;
|
||||
if (surf == null)
|
||||
{
|
||||
surfLocked = LockLuaSurface(kvp.Key,true);
|
||||
surfLocked = LockLuaSurface(kvp.Key, true);
|
||||
}
|
||||
|
||||
if (surfLocked != null)
|
||||
|
|
|
@ -12,9 +12,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public unsafe class DisplaySurface : IDisposable
|
||||
{
|
||||
private Bitmap bmp;
|
||||
private BitmapData bmpdata;
|
||||
private int[] pixels;
|
||||
private Bitmap _bmp;
|
||||
private BitmapData _bmpData;
|
||||
private readonly int[] _pixels;
|
||||
|
||||
public unsafe void Clear()
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Bitmap PeekBitmap()
|
||||
{
|
||||
ToBitmap();
|
||||
return bmp;
|
||||
return _bmp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -34,7 +34,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Graphics GetGraphics()
|
||||
{
|
||||
ToBitmap();
|
||||
return Graphics.FromImage(bmp);
|
||||
return Graphics.FromImage(_bmp);
|
||||
}
|
||||
|
||||
public unsafe void ToBitmap(bool copy=true)
|
||||
|
@ -42,79 +42,101 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (_isBitmap) return;
|
||||
_isBitmap = true;
|
||||
|
||||
if (bmp == null)
|
||||
if (_bmp == null)
|
||||
{
|
||||
bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
|
||||
_bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
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 h = Height;
|
||||
int stride = bmpdata.Stride / 4;
|
||||
int* bmpbuf = (int*)bmpdata.Scan0.ToPointer();
|
||||
int stride = _bmpData.Stride / 4;
|
||||
int* bmpBuf = (int*)_bmpData.Scan0.ToPointer();
|
||||
for (int y = 0, i = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
bmpbuf[y * stride + x] = pixels[i++];
|
||||
|
||||
bmp.UnlockBits(bmpdata);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool _isBitmap;
|
||||
|
||||
public unsafe void FromBitmap(bool copy=true)
|
||||
{
|
||||
if (!_isBitmap) return;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
bmpBuf[y * stride + x] = _pixels[i++];
|
||||
}
|
||||
}
|
||||
|
||||
_bmp.UnlockBits(_bmpData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool _isBitmap;
|
||||
|
||||
public unsafe void FromBitmap(bool copy = true)
|
||||
{
|
||||
if (!_isBitmap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isBitmap = false;
|
||||
|
||||
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 h = Height;
|
||||
int stride = bmpdata.Stride / 4;
|
||||
int* bmpbuf = (int*)bmpdata.Scan0.ToPointer();
|
||||
int stride = _bmpData.Stride / 4;
|
||||
int* bmpBuf = (int*)_bmpData.Scan0.ToPointer();
|
||||
for (int y = 0, i = 0; y < h; y++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
//can't create a bitmap with zero dimensions, so for now, just bump it up to one
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
// can't create a bitmap with zero dimensions, so for now, just bump it up to one
|
||||
if (width == 0)
|
||||
{
|
||||
width = 1;
|
||||
}
|
||||
|
||||
if (height == 0)
|
||||
{
|
||||
height = 1;
|
||||
}
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
||||
pixels = new int[width * height];
|
||||
_pixels = new int[width * height];
|
||||
LockPixels();
|
||||
}
|
||||
|
||||
public int* PixelPtr => (int*)ptr;
|
||||
public int* PixelPtr => (int*)_ptr;
|
||||
public int Stride => Width * 4;
|
||||
|
||||
void* ptr;
|
||||
GCHandle handle;
|
||||
void LockPixels()
|
||||
private void* _ptr;
|
||||
private GCHandle _handle;
|
||||
private void LockPixels()
|
||||
{
|
||||
UnlockPixels();
|
||||
handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
|
||||
ptr = handle.AddrOfPinnedObject().ToPointer();
|
||||
_handle = GCHandle.Alloc(_pixels, GCHandleType.Pinned);
|
||||
_ptr = _handle.AddrOfPinnedObject().ToPointer();
|
||||
}
|
||||
|
||||
private void UnlockPixels()
|
||||
{
|
||||
if(handle.IsAllocated) handle.Free();
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public int Width { get; }
|
||||
|
@ -122,8 +144,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
bmp?.Dispose();
|
||||
bmp = null;
|
||||
_bmp?.Dispose();
|
||||
_bmp = null;
|
||||
UnlockPixels();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace BizHawk.Client.EmuHawk.FilterManager
|
|||
iosi.SurfaceFormat = currState.SurfaceFormat;
|
||||
f.SetInputFormat(channel, currState);
|
||||
|
||||
if (f.IsNOP)
|
||||
if (f.IsNop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using BizHawk.Client.EmuHawk.FilterManager;
|
||||
|
@ -6,35 +5,33 @@ using BizHawk.Client.EmuHawk.FilterManager;
|
|||
using BizHawk.Bizware.BizwareGL;
|
||||
using OpenTK;
|
||||
|
||||
//Here's how to make a filter:
|
||||
//1. Reset your state entirely in Initialize().
|
||||
// Here's how to make a filter:
|
||||
// 1. Reset your state entirely in Initialize().
|
||||
// The filter will be re-initialized several times while the chain is getting worked out, but not re-instantiated.
|
||||
// This is sort of annoying, but there's pretty good reasons for it (some external process has created the filters and set parameters needed to govern their chaining and surface properties)
|
||||
//2. In Initialize(), be sure to use DeclareInput
|
||||
//(something about PresizeInput())
|
||||
//3. PresizeOutput() will be called next
|
||||
//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
|
||||
//6. In Run(), if supplying an output texture, use YieldOutput
|
||||
|
||||
// 2. In Initialize(), be sure to use DeclareInput
|
||||
// (something about PresizeInput())
|
||||
// 3. PresizeOutput() will be called next
|
||||
// 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
|
||||
// 6. In Run(), if supplying an output texture, use YieldOutput
|
||||
namespace BizHawk.Client.EmuHawk.Filters
|
||||
{
|
||||
public class BaseFilter
|
||||
{
|
||||
//initialization stuff
|
||||
public void BeginInitialization(FilterProgram program) { IOSurfaceInfos.Clear(); FilterProgram = program; }
|
||||
// initialization stuff
|
||||
public void BeginInitialization(FilterProgram program) { _ioSurfaceInfos.Clear(); FilterProgram = program; }
|
||||
public virtual void Initialize() { }
|
||||
public virtual Size PresizeInput(string channel, Size size) { return size; }
|
||||
public virtual Size PresizeOutput(string channel, Size size) { return size; }
|
||||
public virtual Size PresizeInput(string channel, Size size) => 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 Dictionary<string, object> Parameters = new Dictionary<string, object>();
|
||||
public bool IsNOP { get => _IsNop; protected set => _IsNop = value; }
|
||||
private Boolean _IsNop = false;
|
||||
public bool IsNop { get; set; }
|
||||
|
||||
//runtime signals
|
||||
// runtime signals
|
||||
public virtual Vector2 UntransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
//base class behaviour here just uses the input and output sizes, if appropriate. few filters will have to do anything more complex
|
||||
// base class behaviour here just uses the input and output sizes, if appropriate. few filters will have to do anything more complex
|
||||
var input = FindInput(channel);
|
||||
var output = FindOutput(channel);
|
||||
if (input != null && output != null)
|
||||
|
@ -47,7 +44,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public virtual Vector2 TransformPoint(string channel, Vector2 point)
|
||||
{
|
||||
//base class behaviour here just uses the input and output sizes, if appropriate. few filters will have to do anything more complex
|
||||
// base class behaviour here just uses the input and output sizes, if appropriate. few filters will have to do anything more complex
|
||||
var input = FindInput(channel);
|
||||
var output = FindOutput(channel);
|
||||
if (input != null && output != null)
|
||||
|
@ -63,24 +60,34 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
InputTexture = tex;
|
||||
}
|
||||
public virtual void Run() { }
|
||||
public Texture2d GetOutput() { return OutputTexture; }
|
||||
public Texture2d GetOutput() => _outputTexture;
|
||||
|
||||
//filter actions
|
||||
// filter actions
|
||||
protected void YieldOutput(Texture2d tex)
|
||||
{
|
||||
OutputTexture = tex;
|
||||
_outputTexture = tex;
|
||||
}
|
||||
|
||||
protected FilterProgram FilterProgram;
|
||||
protected Texture2d InputTexture;
|
||||
private Texture2d OutputTexture;
|
||||
private Texture2d _outputTexture;
|
||||
|
||||
//setup utilities
|
||||
protected IOSurfaceInfo DeclareInput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default") { return DeclareIO(SurfaceDirection.Input, channel, disposition); }
|
||||
protected IOSurfaceInfo DeclareOutput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default") { return DeclareIO(SurfaceDirection.Output, channel, disposition); }
|
||||
//TODO - why a different param order than DeclareOutput?
|
||||
// setup utilities
|
||||
protected IOSurfaceInfo DeclareInput(SurfaceDisposition disposition = SurfaceDisposition.Unspecified, string channel = "default")
|
||||
{
|
||||
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")
|
||||
{
|
||||
|
@ -89,36 +96,51 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
return iosi;
|
||||
}
|
||||
|
||||
public IOSurfaceInfo FindInput(string channel = "default") { return FindIOSurfaceInfo(channel, SurfaceDirection.Input); }
|
||||
public IOSurfaceInfo FindOutput(string channel = "default") { return FindIOSurfaceInfo(channel, SurfaceDirection.Output); }
|
||||
public IOSurfaceInfo FindInput(string channel = "default")
|
||||
{
|
||||
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)
|
||||
{
|
||||
var iosi = new IOSurfaceInfo();
|
||||
iosi.SurfaceDirection = direction;
|
||||
iosi.Channel = channel;
|
||||
iosi.SurfaceDisposition = disposition;
|
||||
IOSurfaceInfos.Add(iosi);
|
||||
var iosi = new IOSurfaceInfo
|
||||
{
|
||||
SurfaceDirection = direction,
|
||||
Channel = channel,
|
||||
SurfaceDisposition = disposition
|
||||
};
|
||||
|
||||
_ioSurfaceInfos.Add(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)
|
||||
{
|
||||
foreach (var iosi in IOSurfaceInfos)
|
||||
foreach (var iosi in _ioSurfaceInfos)
|
||||
{
|
||||
if (iosi.Channel == channel && iosi.SurfaceDirection == direction)
|
||||
{
|
||||
return iosi;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public class IOSurfaceInfo
|
||||
{
|
||||
public SurfaceFormat SurfaceFormat;
|
||||
public SurfaceDirection SurfaceDirection;
|
||||
public SurfaceDisposition SurfaceDisposition;
|
||||
public string Channel;
|
||||
public SurfaceFormat SurfaceFormat { get; set; }
|
||||
public SurfaceDirection SurfaceDirection { get; set; }
|
||||
public SurfaceDisposition SurfaceDisposition { get; set; }
|
||||
public string Channel { get; set; }
|
||||
}
|
||||
|
||||
public enum SurfaceDirection
|
||||
|
|
|
@ -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.
|
||||
/// In the future this could also apply rules like integer-only scaling, etc.
|
||||
/// </summary>
|
||||
class LetterboxingLogic
|
||||
public class LetterboxingLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// the location within the destination region of the output content (scaled and translated)
|
||||
|
@ -28,7 +28,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
/// </summary>
|
||||
public LetterboxingLogic() { }
|
||||
|
||||
//do maths on the viewport and the native resolution and the user settings to get a display rectangle
|
||||
// do maths on the viewport and the native resolution and the user settings to get a display rectangle
|
||||
public LetterboxingLogic(bool maintainAspect, bool maintainInteger, int targetWidth, int targetHeight, int sourceWidth, int sourceHeight, Size textureSize, Size virtualSize)
|
||||
{
|
||||
int textureWidth = textureSize.Width;
|
||||
|
@ -42,15 +42,17 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
sourceWidth = (int)virtualWidth;
|
||||
sourceHeight = (int)virtualHeight;
|
||||
|
||||
//this doesnt make sense
|
||||
// this doesn't make sense
|
||||
if (!maintainAspect)
|
||||
{
|
||||
maintainInteger = false;
|
||||
}
|
||||
|
||||
float widthScale = (float)targetWidth / sourceWidth;
|
||||
float heightScale = (float)targetHeight / sourceHeight;
|
||||
|
||||
if (maintainAspect
|
||||
//zero 20-jul-2014 - hacks upon hacks, this function needs rewriting
|
||||
// zero 20-jul-2014 - hacks upon hacks, this function needs rewriting
|
||||
&& !maintainInteger
|
||||
)
|
||||
{
|
||||
|
@ -60,51 +62,53 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
if (maintainInteger)
|
||||
{
|
||||
//just totally different code
|
||||
//apply the zooming algorithm (pasted and reworked, for now)
|
||||
//ALERT COPYPASTE LAUNDROMAT
|
||||
// just totally different code
|
||||
// apply the zooming algorithm (pasted and reworked, for now)
|
||||
// ALERT COPYPASTE LAUNDROMAT
|
||||
|
||||
Vector2 VS = new Vector2(virtualWidth, virtualHeight);
|
||||
Vector2 BS = new Vector2(textureWidth, textureHeight);
|
||||
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
|
||||
|
||||
for(;;)
|
||||
{
|
||||
//TODO - would be good not to run this per frame....
|
||||
Vector2[] trials = new[] {
|
||||
// TODO - would be good not to run this per frame....
|
||||
Vector2[] trials =
|
||||
{
|
||||
PS + new Vector2(1, 0),
|
||||
PS + new Vector2(0, 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;
|
||||
float bestValue = 1000.0f;
|
||||
for (int t = 0; t < trials.Length; t++)
|
||||
{
|
||||
Vector2 vTrial = trials[t];
|
||||
trials_limited[t] = false;
|
||||
trialsLimited[t] = false;
|
||||
|
||||
//check whether this is going to exceed our allotted area
|
||||
int test_vw = (int)(vTrial.X * textureWidth);
|
||||
int test_vh = (int)(vTrial.Y * textureHeight);
|
||||
if (test_vw > targetWidth) trials_limited[t] = true;
|
||||
if (test_vh > targetHeight) trials_limited[t] = true;
|
||||
int testVw = (int)(vTrial.X * textureWidth);
|
||||
int testVh = (int)(vTrial.Y * textureHeight);
|
||||
if (testVw > targetWidth) trialsLimited[t] = true;
|
||||
if (testVh > targetHeight) trialsLimited[t] = true;
|
||||
|
||||
//I.
|
||||
float test_ar = vTrial.X / vTrial.Y;
|
||||
// I.
|
||||
float testAr = vTrial.X / vTrial.Y;
|
||||
|
||||
//II.
|
||||
//Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||
//float test_ar = calc.X / calc.Y;
|
||||
// II.
|
||||
// Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||
// float test_ar = calc.X / calc.Y;
|
||||
|
||||
//not clear which approach is superior
|
||||
float deviation_linear = Math.Abs(test_ar - target_par);
|
||||
float deviation_geom = test_ar / target_par;
|
||||
if (deviation_geom < 1) deviation_geom = 1.0f / deviation_geom;
|
||||
// not clear which approach is superior
|
||||
float deviationLinear = Math.Abs(testAr - targetPar);
|
||||
float deviationGeom = testAr / targetPar;
|
||||
if (deviationGeom < 1) deviationGeom = 1.0f / deviationGeom;
|
||||
|
||||
float value = deviation_linear;
|
||||
float value = deviationLinear;
|
||||
if (value < bestValue)
|
||||
{
|
||||
bestIndex = t;
|
||||
|
@ -112,20 +116,20 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
}
|
||||
}
|
||||
|
||||
//last result was best, so bail out
|
||||
// last result was best, so bail out
|
||||
if (bestIndex == -1)
|
||||
break;
|
||||
|
||||
//if the winner ran off the edge, bail out
|
||||
if (trials_limited[bestIndex])
|
||||
// if the winner ran off the edge, bail out
|
||||
if (trialsLimited[bestIndex])
|
||||
break;
|
||||
|
||||
PS = trials[bestIndex];
|
||||
}
|
||||
|
||||
//"fix problems with gameextrapadding in >1x window scales" (other edits were made, maybe theyre whats important)
|
||||
//vw = (int)(PS.X * oldSourceWidth);
|
||||
//vh = (int)(PS.Y * oldSourceHeight);
|
||||
// "fix problems with gameextrapadding in >1x window scales" (other edits were made, maybe theyre whats important)
|
||||
// vw = (int)(PS.X * oldSourceWidth);
|
||||
// vh = (int)(PS.Y * oldSourceHeight);
|
||||
vw = (int)(PS.X * sourceWidth);
|
||||
vh = (int)(PS.Y * sourceHeight);
|
||||
widthScale = PS.X;
|
||||
|
@ -137,27 +141,31 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
vh = (int)(heightScale * sourceHeight);
|
||||
}
|
||||
|
||||
//theres 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
|
||||
//instead, since we're more about biz than gaming, lets shrink the view to fit in the small dimension
|
||||
// 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
|
||||
// instead, since we're more about biz than gaming, lets shrink the view to fit in the small dimension
|
||||
if (targetWidth < vw)
|
||||
{
|
||||
vw = targetWidth;
|
||||
}
|
||||
|
||||
if (targetHeight < vh)
|
||||
{
|
||||
vh = targetHeight;
|
||||
}
|
||||
|
||||
//determine letterboxing parameters
|
||||
vx = (targetWidth - vw) / 2;
|
||||
vy = (targetHeight - vh) / 2;
|
||||
|
||||
//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.
|
||||
//FinalPresentation doesnt use the LL.WidthScale, so this is unlikely to be breaking anything old that depends on it
|
||||
//WidthScale = widthScale;
|
||||
//HeightScale = heightScale;
|
||||
// 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.
|
||||
// FinalPresentation doesn't use the LL.WidthScale, so this is unlikely to be breaking anything old that depends on it
|
||||
// WidthScale = widthScale;
|
||||
// HeightScale = heightScale;
|
||||
WidthScale = (float)vw / oldSourceWidth;
|
||||
HeightScale = (float)vh / oldSourceHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class FinalPresentation : BaseFilter
|
||||
|
@ -168,23 +176,22 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
}
|
||||
|
||||
public eFilterOption FilterOption = eFilterOption.None;
|
||||
public RetroShaderChain BicubicFilter;
|
||||
|
||||
public FinalPresentation(Size size)
|
||||
{
|
||||
this.OutputSize = size;
|
||||
}
|
||||
|
||||
Size OutputSize, InputSize;
|
||||
private Size OutputSize, InputSize;
|
||||
public Size TextureSize, VirtualTextureSize;
|
||||
public int BackgroundColor;
|
||||
public bool AutoPrescale;
|
||||
public IGuiRenderer GuiRenderer;
|
||||
public bool Flip;
|
||||
public IGL GL;
|
||||
bool nop;
|
||||
LetterboxingLogic LL;
|
||||
Size ContentSize;
|
||||
private bool nop;
|
||||
private LetterboxingLogic LL;
|
||||
private Size ContentSize;
|
||||
|
||||
public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly;
|
||||
|
||||
|
@ -278,10 +285,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
ContentSize = new Size(LL.vw,LL.vh);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -350,10 +357,10 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
var OutputSize = state.SurfaceFormat.Size;
|
||||
OutputSize.Width *= Scale;
|
||||
OutputSize.Height *= Scale;
|
||||
var ss = new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget);
|
||||
var outputSize = state.SurfaceFormat.Size;
|
||||
outputSize.Width *= Scale;
|
||||
outputSize.Height *= Scale;
|
||||
var ss = new SurfaceState(new SurfaceFormat(outputSize), SurfaceDisposition.RenderTarget);
|
||||
DeclareOutput(ss, channel);
|
||||
}
|
||||
|
||||
|
@ -370,8 +377,8 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public class AutoPrescaleFilter : BaseFilter
|
||||
{
|
||||
Size OutputSize, InputSize;
|
||||
int XIS, YIS;
|
||||
private Size OutputSize, InputSize;
|
||||
private int XIS, YIS;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
@ -391,7 +398,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
if (XIS <= 1 && YIS <= 1)
|
||||
{
|
||||
IsNOP = true;
|
||||
IsNop = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -411,14 +418,15 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
return base.PresizeOutput(channel, size);
|
||||
}
|
||||
|
||||
public override Size PresizeInput(string channel, Size insize)
|
||||
public override Size PresizeInput(string channel, Size inSize)
|
||||
{
|
||||
InputSize = insize;
|
||||
return insize;
|
||||
InputSize = inSize;
|
||||
return inSize;
|
||||
}
|
||||
|
||||
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.Modelview.Scale(XIS,YIS);
|
||||
FilterProgram.GuiRenderer.Draw(InputTexture);
|
||||
|
@ -437,11 +445,11 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
DeclareOutput(state);
|
||||
}
|
||||
|
||||
Texture2d Texture;
|
||||
private Texture2d _texture;
|
||||
|
||||
public void SetTexture(Texture2d tex)
|
||||
{
|
||||
Texture = tex;
|
||||
_texture = tex;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
|
@ -449,7 +457,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
var outSize = FindOutput().SurfaceFormat.Size;
|
||||
FilterProgram.GuiRenderer.Begin(outSize);
|
||||
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNormal);
|
||||
FilterProgram.GuiRenderer.Draw(Texture);
|
||||
FilterProgram.GuiRenderer.Draw(_texture);
|
||||
FilterProgram.GuiRenderer.End();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,27 @@
|
|||
//https://github.com/Themaister/RetroArch/wiki/GLSL-shaders
|
||||
//https://github.com/Themaister/Emulator-Shader-Pack/blob/master/Cg/README
|
||||
//https://github.com/libretro/common-shaders/
|
||||
// https://github.com/Themaister/RetroArch/wiki/GLSL-shaders
|
||||
// https://github.com/Themaister/Emulator-Shader-Pack/blob/master/Cg/README
|
||||
// https://github.com/libretro/common-shaders/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk;
|
||||
using BizHawk.Client.EmuHawk.FilterManager;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk.Filters
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
var match = rxInclude.Match(content);
|
||||
var match = RxInclude.Match(content);
|
||||
if(match.Value == "") break;
|
||||
string fname = match.Groups[4].Value;
|
||||
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)
|
||||
{
|
||||
Owner = owner;
|
||||
this.Preset = preset;
|
||||
Preset = preset;
|
||||
Passes = preset.Passes.ToArray();
|
||||
Errors = "";
|
||||
|
||||
|
@ -82,9 +73,16 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var s in Shaders)
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
|
@ -107,13 +105,13 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
public RetroShaderPreset(Stream stream)
|
||||
{
|
||||
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
|
||||
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 == "") continue; //empty line
|
||||
int eq = line.IndexOf('=');
|
||||
|
@ -133,12 +131,11 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
dict[key.ToLower()] = value;
|
||||
}
|
||||
|
||||
//process the keys
|
||||
// process the keys
|
||||
int nShaders = FetchInt(dict, "shaders", 0);
|
||||
for (int i = 0; i < nShaders; i++)
|
||||
{
|
||||
ShaderPass sp = new ShaderPass();
|
||||
sp.Index = i;
|
||||
var sp = new ShaderPass { Index = i };
|
||||
Passes.Add(sp);
|
||||
|
||||
sp.InputFilterLinear = FetchBool(dict, $"filter_linear{i}", false); //Should this value not be defined, the filtering option is implementation defined.
|
||||
|
@ -146,37 +143,44 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
sp.FrameCountMod = FetchInt(dict, $"frame_count_mod{i}", 1);
|
||||
sp.ShaderPath = FetchString(dict, $"shader{i}", "?"); //todo - change extension to .cg for better compatibility? just change .cg to .glsl transparently at last second?
|
||||
|
||||
//If no scale type is assumed, it is assumed that it is set to "source" with scaleN set to 1.0.
|
||||
//It is possible to set scale_type_xN and scale_type_yN to specialize the scaling type in either direction. scale_typeN however overrides both of these.
|
||||
// If no scale type is assumed, it is assumed that it is set to "source" with scaleN set to 1.0.
|
||||
// It is possible to set scale_type_xN and scale_type_yN to specialize the scaling type in either direction. scale_typeN however overrides both of these.
|
||||
sp.ScaleTypeX = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type_x{i}", "Source"), true);
|
||||
sp.ScaleTypeY = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type_y{i}", "Source"), true);
|
||||
ScaleType st = (ScaleType)Enum.Parse(typeof(ScaleType), FetchString(dict, $"scale_type{i}", "NotSet"), true);
|
||||
if (st != ScaleType.NotSet)
|
||||
sp.ScaleTypeX = sp.ScaleTypeY = st;
|
||||
|
||||
//scaleN controls both scaling type in horizontal and vertical directions. If scaleN is defined, scale_xN and scale_yN have no effect.
|
||||
// scaleN controls both scaling type in horizontal and vertical directions. If scaleN is defined, scale_xN and scale_yN have no effect.
|
||||
sp.Scale.X = FetchFloat(dict, $"scale_x{i}", 1);
|
||||
sp.Scale.Y = FetchFloat(dict, $"scale_y{i}", 1);
|
||||
float scale = FetchFloat(dict, $"scale{i}", -999);
|
||||
if (scale != -999)
|
||||
{
|
||||
sp.Scale.X = sp.Scale.Y = FetchFloat(dict, $"scale{i}", 1);
|
||||
}
|
||||
|
||||
//TODO - LUTs
|
||||
}
|
||||
}
|
||||
|
||||
public List<ShaderPass> Passes = new List<ShaderPass>();
|
||||
public List<ShaderPass> Passes { get; set; } = new List<ShaderPass>();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether any of the passes contain GLSL filenames (these are invalid now)
|
||||
/// </summary>
|
||||
public bool ContainsGLSL
|
||||
public bool ContainsGlsl
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var pass in Passes)
|
||||
if (Path.GetExtension(pass.ShaderPath).ToLowerInvariant() == ".glsl")
|
||||
{
|
||||
if (Path.GetExtension(pass.ShaderPath)?.ToLowerInvariant() == ".glsl")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -198,64 +202,51 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
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;
|
||||
if (dict.TryGetValue(key, out str))
|
||||
return str;
|
||||
else return @default;
|
||||
return dict.TryGetValue(key, out var str) ? str : @default;
|
||||
}
|
||||
|
||||
int FetchInt(Dictionary<string, string> dict, string key, int @default)
|
||||
private int FetchInt(IDictionary<string, string> dict, string key, int @default)
|
||||
{
|
||||
string str;
|
||||
if (dict.TryGetValue(key, out str))
|
||||
return int.Parse(str);
|
||||
else return @default;
|
||||
return dict.TryGetValue(key, out var str) ? int.Parse(str) : @default;
|
||||
}
|
||||
|
||||
float FetchFloat(Dictionary<string, string> dict, string key, float @default)
|
||||
private float FetchFloat(IDictionary<string, string> dict, string key, float @default)
|
||||
{
|
||||
string str;
|
||||
if (dict.TryGetValue(key, out str))
|
||||
return float.Parse(str);
|
||||
else return @default;
|
||||
return dict.TryGetValue(key, out var str) ? float.Parse(str) : @default;
|
||||
}
|
||||
|
||||
bool FetchBool(Dictionary<string, string> dict, string key, bool @default)
|
||||
private bool FetchBool(IDictionary<string, string> dict, string key, bool @default)
|
||||
{
|
||||
string str;
|
||||
if (dict.TryGetValue(key, out str))
|
||||
return ParseBool(str);
|
||||
else return @default;
|
||||
return dict.TryGetValue(key, out var str) ? ParseBool(str) : @default;
|
||||
}
|
||||
|
||||
|
||||
bool ParseBool(string value)
|
||||
private bool ParseBool(string value)
|
||||
{
|
||||
if (value == "1") return true;
|
||||
if (value == "0") return false;
|
||||
value = value.ToLower();
|
||||
if (value == "true") return true;
|
||||
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
|
||||
{
|
||||
RetroShaderChain RSC;
|
||||
RetroShaderPreset.ShaderPass SP;
|
||||
int RSI;
|
||||
Size OutputSize;
|
||||
private readonly RetroShaderChain _rsc;
|
||||
private readonly RetroShaderPreset.ShaderPass _sp;
|
||||
private readonly int _rsi;
|
||||
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;
|
||||
this.RSI = index;
|
||||
this.SP = RSC.Passes[index];
|
||||
_rsc = rsc;
|
||||
_rsi = index;
|
||||
_sp = _rsc.Passes[index];
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
|
@ -265,59 +256,66 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
public override void SetInputFormat(string channel, SurfaceState state)
|
||||
{
|
||||
Size insize = state.SurfaceFormat.Size;
|
||||
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.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);
|
||||
Size inSize = state.SurfaceFormat.Size;
|
||||
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.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);
|
||||
|
||||
var outState = new SurfaceState();
|
||||
outState.SurfaceFormat = new SurfaceFormat(OutputSize);
|
||||
outState.SurfaceDisposition = SurfaceDisposition.RenderTarget;
|
||||
DeclareOutput(outState);
|
||||
DeclareOutput(new SurfaceState
|
||||
{
|
||||
SurfaceFormat = new SurfaceFormat(_outputSize),
|
||||
SurfaceDisposition = SurfaceDisposition.RenderTarget
|
||||
});
|
||||
}
|
||||
|
||||
public override Size PresizeOutput(string channel, Size size)
|
||||
{
|
||||
OutputSize = size;
|
||||
_outputSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public override Size PresizeInput(string channel, Size insize)
|
||||
public override Size PresizeInput(string channel, Size inSize)
|
||||
{
|
||||
Size outsize = insize;
|
||||
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.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);
|
||||
Size outsize = inSize;
|
||||
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.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);
|
||||
return outsize;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
var shader = RSC.Shaders[RSI];
|
||||
|
||||
var shader = _rsc.Shaders[_rsi];
|
||||
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)
|
||||
{
|
||||
foreach (var kvp in Parameters)
|
||||
{
|
||||
if (kvp.Value is float)
|
||||
shader.Pipeline[kvp.Key].Set((float)kvp.Value);
|
||||
if (kvp.Value is float value)
|
||||
{
|
||||
shader.Pipeline[kvp.Key].Set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var input = InputTexture;
|
||||
if (SP.InputFilterLinear)
|
||||
if (_sp.InputFilterLinear)
|
||||
{
|
||||
InputTexture.SetFilterLinear();
|
||||
}
|
||||
else
|
||||
{
|
||||
InputTexture.SetFilterNearest();
|
||||
RSC.Shaders[RSI].Run(input, input.Size, OutputSize, InputTexture.IsUpsideDown);
|
||||
}
|
||||
|
||||
//maintain invariant.. i think.
|
||||
_rsc.Shaders[_rsi].Run(input, input.Size, _outputSize, InputTexture.IsUpsideDown);
|
||||
|
||||
// maintain invariant.. i think.
|
||||
InputTexture.SetFilterNearest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
{
|
||||
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()
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
|
||||
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)
|
||||
|
@ -35,7 +35,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
/// <summary>
|
||||
/// transforms an input texture to an output render target (by rendering it)
|
||||
/// </summary>
|
||||
class Render : BaseFilter
|
||||
public class Render : BaseFilter
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
|||
}
|
||||
}
|
||||
|
||||
class Resolve : BaseFilter
|
||||
public class Resolve : BaseFilter
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
@ -7,59 +8,64 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public class RenderTargetFrugalizer : IDisposable
|
||||
{
|
||||
public RenderTargetFrugalizer(IGL gl)
|
||||
{
|
||||
GL = gl;
|
||||
_gl = gl;
|
||||
ResetList();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var ct in CurrentRenderTargets)
|
||||
if (ct != null)
|
||||
ct.Dispose();
|
||||
foreach (var ct in _currentRenderTargets)
|
||||
{
|
||||
ct?.Dispose();
|
||||
}
|
||||
|
||||
ResetList();
|
||||
}
|
||||
|
||||
void ResetList()
|
||||
private void ResetList()
|
||||
{
|
||||
CurrentRenderTargets = new List<RenderTarget>();
|
||||
CurrentRenderTargets.Add(null);
|
||||
CurrentRenderTargets.Add(null);
|
||||
_currentRenderTargets = new List<RenderTarget> { null, null };
|
||||
}
|
||||
|
||||
IGL GL;
|
||||
List<RenderTarget> CurrentRenderTargets;
|
||||
private readonly IGL _gl;
|
||||
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)
|
||||
{
|
||||
//get the current entry
|
||||
RenderTarget CurrentRenderTarget = CurrentRenderTargets[0];
|
||||
RenderTarget currentRenderTarget = _currentRenderTargets[0];
|
||||
|
||||
//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...
|
||||
if (CurrentRenderTarget != null)
|
||||
CurrentRenderTarget.Dispose();
|
||||
//and make a new one
|
||||
CurrentRenderTarget = GL.CreateRenderTarget(width, height);
|
||||
// needs recreating. be sure to kill the old one...
|
||||
currentRenderTarget?.Dispose();
|
||||
// and make a new one
|
||||
currentRenderTarget = _gl.CreateRenderTarget(width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
//its good! nothing more to do
|
||||
// its good! nothing more to do
|
||||
}
|
||||
|
||||
//now shuffle the buffers
|
||||
CurrentRenderTargets[0] = CurrentRenderTargets[1];
|
||||
CurrentRenderTargets[1] = CurrentRenderTarget;
|
||||
// now shuffle the buffers
|
||||
_currentRenderTargets[0] = _currentRenderTargets[1];
|
||||
_currentRenderTargets[1] = currentRenderTarget;
|
||||
|
||||
return CurrentRenderTarget;
|
||||
return currentRenderTarget;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public class SwappableDisplaySurfaceSet
|
||||
{
|
||||
private DisplaySurface Pending, Current;
|
||||
private bool IsPending;
|
||||
private readonly Queue<DisplaySurface> ReleasedSurfaces = new Queue<DisplaySurface>();
|
||||
private DisplaySurface _pending, _current;
|
||||
private bool _isPending;
|
||||
private readonly Queue<DisplaySurface> _releasedSurfaces = new Queue<DisplaySurface>();
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
lock (this)
|
||||
{
|
||||
if (ReleasedSurfaces.Count == 0) break;
|
||||
trial = ReleasedSurfaces.Dequeue();
|
||||
if (_releasedSurfaces.Count == 0) break;
|
||||
trial = _releasedSurfaces.Dequeue();
|
||||
}
|
||||
if (trial.Width == width && trial.Height == height)
|
||||
{
|
||||
if (needsClear) trial.Clear();
|
||||
if (needsClear)
|
||||
{
|
||||
trial.Clear();
|
||||
}
|
||||
|
||||
return trial;
|
||||
}
|
||||
|
||||
trial.Dispose();
|
||||
}
|
||||
|
||||
return new DisplaySurface(width, height);
|
||||
}
|
||||
|
||||
|
@ -42,15 +48,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
lock (this)
|
||||
{
|
||||
if (Pending != null) ReleasedSurfaces.Enqueue(Pending);
|
||||
Pending = newPending;
|
||||
IsPending = true;
|
||||
if (_pending != null) _releasedSurfaces.Enqueue(_pending);
|
||||
_pending = newPending;
|
||||
_isPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseSurface(DisplaySurface surface)
|
||||
{
|
||||
lock (this) ReleasedSurfaces.Enqueue(surface);
|
||||
lock (this) _releasedSurfaces.Enqueue(surface);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -60,15 +66,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
lock (this)
|
||||
{
|
||||
if (IsPending)
|
||||
if (_isPending)
|
||||
{
|
||||
if (Current != null) ReleasedSurfaces.Enqueue(Current);
|
||||
Current = Pending;
|
||||
Pending = null;
|
||||
IsPending = false;
|
||||
if (_current != null) _releasedSurfaces.Enqueue(_current);
|
||||
_current = _pending;
|
||||
_pending = null;
|
||||
_isPending = false;
|
||||
}
|
||||
}
|
||||
return Current;
|
||||
|
||||
return _current;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,13 +12,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public TextureFrugalizer(IGL gl)
|
||||
{
|
||||
GL = gl;
|
||||
_gl = gl;
|
||||
ResetList();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var ct in CurrentTextures)
|
||||
foreach (var ct in _currentTextures)
|
||||
{
|
||||
ct?.Dispose();
|
||||
}
|
||||
|
@ -26,13 +26,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
ResetList();
|
||||
}
|
||||
|
||||
void ResetList()
|
||||
private void ResetList()
|
||||
{
|
||||
CurrentTextures = new List<Texture2d> { null, null };
|
||||
_currentTextures = new List<Texture2d> { null, null };
|
||||
}
|
||||
|
||||
private readonly IGL GL;
|
||||
private List<Texture2d> CurrentTextures;
|
||||
private readonly IGL _gl;
|
||||
private List<Texture2d> _currentTextures;
|
||||
|
||||
public Texture2d Get(DisplaySurface ds)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Texture2d Get(BitmapBuffer bb)
|
||||
{
|
||||
//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)
|
||||
// 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...
|
||||
currentTexture?.Dispose();
|
||||
//and make a new one
|
||||
currentTexture = GL.LoadTexture(bb);
|
||||
currentTexture = _gl.LoadTexture(bb);
|
||||
}
|
||||
else
|
||||
{
|
||||
//its good! just load in the data
|
||||
GL.LoadTextureData(currentTexture, bb);
|
||||
_gl.LoadTextureData(currentTexture, bb);
|
||||
}
|
||||
|
||||
//now shuffle the buffers
|
||||
CurrentTextures[0] = CurrentTextures[1];
|
||||
CurrentTextures[1] = currentTexture;
|
||||
_currentTextures[0] = _currentTextures[1];
|
||||
_currentTextures[1] = currentTexture;
|
||||
|
||||
//deterministic state, i guess
|
||||
currentTexture.SetFilterNearest();
|
||||
|
|
|
@ -202,7 +202,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
using (var stream = File.OpenRead(choice))
|
||||
{
|
||||
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");
|
||||
return;
|
||||
|
|
|
@ -271,6 +271,7 @@
|
|||
<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/=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/=Lightgun/@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/=Prereqs/@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/=quantizing/@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/=Uninitialize/@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/=unpaused/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unpausing/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
Loading…
Reference in New Issue