MultiHawk - removing more stuff

This commit is contained in:
adelikat 2015-03-09 21:06:40 +00:00
parent e4c2eddc1f
commit eccbe1ce2a
10 changed files with 20 additions and 1401 deletions

View File

@ -13,7 +13,7 @@ namespace BizHawk.Client.EmuHawk
/// Recycles a pair of temporary textures (in case double-buffering helps any) to contain a BitmapBuffer's or DisplaySurface's contents, as long as the dimensions match.
/// When the dimensions dont match, a new one will be allocated
/// </summary>
class TextureFrugalizer : IDisposable
public class TextureFrugalizer : IDisposable
{
public TextureFrugalizer(IGL gl)
{

View File

@ -72,15 +72,7 @@
<DependentUpon>RecordMovie.cs</DependentUpon>
</Compile>
<Compile Include="DisplayManager\DisplayManager.cs" />
<Compile Include="DisplayManager\DisplaySurface.cs" />
<Compile Include="DisplayManager\FilterManager.cs" />
<Compile Include="DisplayManager\Filters\BaseFilter.cs" />
<Compile Include="DisplayManager\Filters\Gui.cs" />
<Compile Include="DisplayManager\Filters\Retro.cs" />
<Compile Include="DisplayManager\Filters\Utils.cs" />
<Compile Include="DisplayManager\RenderTargetFrugalizer.cs" />
<Compile Include="DisplayManager\SwappableDisplaySurfaceSet.cs" />
<Compile Include="DisplayManager\TextureFrugalizer.cs" />
<Compile Include="EmulatorWindow.cs">
<SubType>Form</SubType>
</Compile>

View File

@ -9,7 +9,7 @@ using System.Drawing;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk.FilterManager;
using BizHawk.Client.EmuHawk.FilterManager;
using BizHawk.Bizware.BizwareGL;
using OpenTK;
@ -52,7 +52,7 @@ namespace BizHawk.Client.MultiHawk
else
Renderer = new GDIPlusGuiRenderer((BizHawk.Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus)GL);
VideoTextureFrugalizer = new TextureFrugalizer(GL);
VideoTextureFrugalizer = new BizHawk.Client.EmuHawk.TextureFrugalizer(GL);
ShaderChainFrugalizers = new RenderTargetFrugalizer[16]; //hacky hardcoded limit.. need some other way to manage these
for (int i = 0; i < 16; i++)
@ -96,11 +96,11 @@ namespace BizHawk.Client.MultiHawk
/// </summary>
int currEmuWidth, currEmuHeight;
TextureFrugalizer VideoTextureFrugalizer;
Dictionary<string, TextureFrugalizer> LuaSurfaceFrugalizers = new Dictionary<string, TextureFrugalizer>();
BizHawk.Client.EmuHawk.TextureFrugalizer VideoTextureFrugalizer;
Dictionary<string, BizHawk.Client.EmuHawk.TextureFrugalizer> LuaSurfaceFrugalizers = new Dictionary<string, BizHawk.Client.EmuHawk.TextureFrugalizer>();
RenderTargetFrugalizer[] ShaderChainFrugalizers;
Filters.RetroShaderChain ShaderChain_user;
BizHawk.Client.EmuHawk.Filters.RetroShaderChain ShaderChain_user;
public void RefreshUserShader()
{
@ -110,7 +110,7 @@ namespace BizHawk.Client.MultiHawk
{
var fi = new FileInfo(Global.Config.DispUserFilterPath);
using (var stream = fi.OpenRead())
ShaderChain_user = new Filters.RetroShaderChain(GL, new Filters.RetroShaderPreset(stream), Path.GetDirectoryName(Global.Config.DispUserFilterPath));
ShaderChain_user = new BizHawk.Client.EmuHawk.Filters.RetroShaderChain(GL, new BizHawk.Client.EmuHawk.Filters.RetroShaderPreset(stream), Path.GetDirectoryName(Global.Config.DispUserFilterPath));
}
}
@ -118,14 +118,14 @@ namespace BizHawk.Client.MultiHawk
{
//select user special FX shader chain
Dictionary<string, object> selectedChainProperties = new Dictionary<string, object>();
Filters.RetroShaderChain selectedChain = null;
BizHawk.Client.EmuHawk.Filters.RetroShaderChain selectedChain = null;
if (Global.Config.TargetDisplayFilter == 3 && ShaderChain_user != null && ShaderChain_user.Available)
selectedChain = ShaderChain_user;
Filters.FinalPresentation fPresent = new Filters.FinalPresentation(chain_outsize);
Filters.SourceImage fInput = new Filters.SourceImage(chain_insize);
Filters.OSD fOSD = new Filters.OSD();
BizHawk.Client.EmuHawk.Filters.FinalPresentation fPresent = new BizHawk.Client.EmuHawk.Filters.FinalPresentation(chain_outsize);
BizHawk.Client.EmuHawk.Filters.SourceImage fInput = new BizHawk.Client.EmuHawk.Filters.SourceImage(chain_insize);
BizHawk.Client.EmuHawk.Filters.OSD fOSD = new BizHawk.Client.EmuHawk.Filters.OSD();
fOSD.RenderCallback = () =>
{
if (!includeOSD)
@ -142,11 +142,11 @@ namespace BizHawk.Client.MultiHawk
chain.AddFilter(fInput, "input");
//choose final filter
Filters.FinalPresentation.eFilterOption finalFilter = Filters.FinalPresentation.eFilterOption.None;
if (Global.Config.DispFinalFilter == 1) finalFilter = Filters.FinalPresentation.eFilterOption.Bilinear;
if (Global.Config.DispFinalFilter == 2) finalFilter = Filters.FinalPresentation.eFilterOption.Bicubic;
finalFilter = Filters.FinalPresentation.eFilterOption.None;
BizHawk.Client.EmuHawk.Filters.FinalPresentation.eFilterOption finalFilter = BizHawk.Client.EmuHawk.Filters.FinalPresentation.eFilterOption.None;
if (Global.Config.DispFinalFilter == 1) finalFilter = BizHawk.Client.EmuHawk.Filters.FinalPresentation.eFilterOption.Bilinear;
if (Global.Config.DispFinalFilter == 2) finalFilter = BizHawk.Client.EmuHawk.Filters.FinalPresentation.eFilterOption.Bicubic;
finalFilter = BizHawk.Client.EmuHawk.Filters.FinalPresentation.eFilterOption.None;
fPresent.FilterOption = finalFilter;
@ -156,12 +156,12 @@ namespace BizHawk.Client.MultiHawk
return chain;
}
void AppendRetroShaderChain(FilterProgram program, string name, Filters.RetroShaderChain retroChain, Dictionary<string, object> properties)
void AppendRetroShaderChain(FilterProgram program, string name, BizHawk.Client.EmuHawk.Filters.RetroShaderChain retroChain, Dictionary<string, object> properties)
{
for (int i = 0; i < retroChain.Passes.Length; i++)
{
var pass = retroChain.Passes[i];
var rsp = new Filters.RetroShaderPass(retroChain, i);
var rsp = new BizHawk.Client.EmuHawk.Filters.RetroShaderPass(retroChain, i);
string fname = string.Format("{0}[{1}]", name, i);
program.AddFilter(rsp, fname);
rsp.Parameters = properties;
@ -420,11 +420,11 @@ TESTEROO:
filterProgram.GL = GL;
//setup the source image filter
Filters.SourceImage fInput = filterProgram["input"] as Filters.SourceImage;
BizHawk.Client.EmuHawk.Filters.SourceImage fInput = filterProgram["input"] as BizHawk.Client.EmuHawk.Filters.SourceImage;
fInput.Texture = videoTexture;
//setup the final presentation filter
Filters.FinalPresentation fPresent = filterProgram["presentation"] as Filters.FinalPresentation;
BizHawk.Client.EmuHawk.Filters.FinalPresentation fPresent = filterProgram["presentation"] as BizHawk.Client.EmuHawk.Filters.FinalPresentation;
fPresent.VirtualTextureSize = new Size(vw, vh);
fPresent.TextureSize = new Size(bufferWidth, bufferHeight);
fPresent.BackgroundColor = videoProvider.BackgroundColor;

View File

@ -1,185 +0,0 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.MultiHawk
{
/// <summary>
/// This is a wrapper for a Bitmap, basically, which can also be a int[].
/// It should be phased out, in favor of BitmapBuffer and Texture2d's
/// </summary>
public unsafe class DisplaySurface : IDisposable
{
Bitmap bmp;
BitmapData bmpdata;
int[] pixels;
public unsafe void Clear()
{
FromBitmap(false);
Util.Memset(PixelPtr, 0, Stride * Height);
}
public Bitmap PeekBitmap()
{
ToBitmap();
return bmp;
}
/// <summary>
/// returns a Graphics object used to render to this surface. be sure to dispose it!
/// </summary>
public Graphics GetGraphics()
{
ToBitmap();
return Graphics.FromImage(bmp);
}
public unsafe void ToBitmap(bool copy=true)
{
if (isBitmap) return;
isBitmap = true;
if (bmp == null)
{
bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
}
if (copy)
{
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();
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);
}
}
public bool IsBitmap { get { return isBitmap; } }
bool isBitmap = false;
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);
int w = Width;
int h = Height;
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];
bmp.UnlockBits(bmpdata);
}
}
public static DisplaySurface DisplaySurfaceWrappingBitmap(Bitmap bmp)
{
DisplaySurface ret = new DisplaySurface();
ret.Width = bmp.Width;
ret.Height = bmp.Height;
ret.bmp = bmp;
ret.isBitmap = true;
return ret;
}
private DisplaySurface()
{
}
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;
Width = width;
Height = height;
pixels = new int[width * height];
LockPixels();
}
public int* PixelPtr { get { return (int*)ptr; } }
public IntPtr PixelIntPtr { get { return new IntPtr(ptr); } }
public int Stride { get { return Width*4; } }
public int OffsetOf(int x, int y) { return y * Stride + x*4; }
void* ptr;
GCHandle handle;
void LockPixels()
{
UnlockPixels();
handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
ptr = handle.AddrOfPinnedObject().ToPointer();
}
void UnlockPixels()
{
if(handle.IsAllocated) handle.Free();
}
/// <summary>
/// returns a new surface
/// </summary>
/// <param name="xpad"></param>
/// <param name="ypad"></param>
/// <returns></returns>
public DisplaySurface ToPaddedSurface(int xpad0, int ypad0, int xpad1, int ypad1)
{
int new_width = Width + xpad0 + xpad1;
int new_height = Height + ypad0 + ypad1;
DisplaySurface ret = new DisplaySurface(new_width, new_height);
int* dptr = ret.PixelPtr;
int* sptr = PixelPtr;
int dstride = ret.Stride / 4;
int sstride = Stride / 4;
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
dptr[(y + ypad0) * dstride + x + xpad0] = sptr[y * sstride + x];
}
return ret;
}
public int Width { get; private set; }
public int Height { get; private set; }
public void Dispose()
{
if (bmp != null)
bmp.Dispose();
bmp = null;
UnlockPixels();
}
public void AcceptIntArray(int[] newpixels)
{
FromBitmap(false);
UnlockPixels();
pixels = newpixels;
LockPixels();
}
}
}

View File

@ -1,263 +0,0 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk.Filters;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK;
using OpenTK.Graphics;
namespace BizHawk.Client.MultiHawk.FilterManager
{
public enum SurfaceDisposition
{
Unspecified, Texture, RenderTarget
}
public class SurfaceFormat
{
public SurfaceFormat(Size size) { this.Size = size; }
public Size Size { get; private set; }
}
public class SurfaceState
{
public SurfaceState() { }
public SurfaceState(SurfaceFormat surfaceFormat, SurfaceDisposition surfaceDisposition = SurfaceDisposition.Unspecified)
{
this.SurfaceFormat = surfaceFormat;
this.SurfaceDisposition = surfaceDisposition;
}
public SurfaceFormat SurfaceFormat;
public SurfaceDisposition SurfaceDisposition;
}
public interface IRenderTargetProvider
{
RenderTarget Get(Size size);
}
public class FilterProgram
{
public List<BaseFilter> Filters = new List<BaseFilter>();
Dictionary<string, BaseFilter> FilterNameIndex = new Dictionary<string, BaseFilter>();
public List<ProgramStep> Program = new List<ProgramStep>();
public BaseFilter this[string name]
{
get
{
BaseFilter ret;
FilterNameIndex.TryGetValue(name, out ret);
return ret;
}
}
public enum ProgramStepType
{
Run,
NewTarget,
FinalTarget
}
//services to filters:
public IGuiRenderer GuiRenderer;
public IGL GL;
public IRenderTargetProvider RenderTargetProvider;
public RenderTarget GetRenderTarget(string channel = "default") { return CurrRenderTarget; }
public RenderTarget CurrRenderTarget;
public void AddFilter(BaseFilter filter, string name = "")
{
Filters.Add(filter);
FilterNameIndex[name] = filter;
}
/// <summary>
/// Receives a point in the coordinate space of the output of the filter program and untransforms it back to input points
/// </summary>
public Vector2 UntransformPoint(string channel, Vector2 point)
{
for (int i = Filters.Count - 1; i >= 0; i--)
{
var filter = Filters[i];
point = filter.UntransformPoint(channel, point);
}
return point;
}
/// <summary>
/// Receives a point in the input space of the filter program and transforms it through to output points
/// </summary>
public Vector2 TransformPoint(string channel, Vector2 point)
{
for (int i = 0; i < Filters.Count; i++)
{
var filter = Filters[i];
point = filter.TransformPoint(channel, point);
}
return point;
}
public class ProgramStep
{
public ProgramStep(ProgramStepType type, object args, string comment = null)
{
this.Type = type;
this.Args = args;
this.Comment = comment;
}
public ProgramStepType Type;
public object Args;
public string Comment;
public override string ToString()
{
if (Type == ProgramStepType.Run)
return string.Format("Run {0} ({1})", (int)Args, Comment);
if (Type == ProgramStepType.NewTarget)
return string.Format("NewTarget {0}", (Size)Args);
if (Type == ProgramStepType.FinalTarget)
return string.Format("FinalTarget");
return null;
}
}
public void Compile(string channel, Size insize, Size outsize, bool finalTarget)
{
RETRY:
Program.Clear();
//prep filters for initialization
foreach (var f in Filters)
{
f.BeginInitialization(this);
f.Initialize();
}
//propagate input size forwards through filter chain to allow a 'flex' filter to determine what its input will be
Size presize = insize;
for (int i = 0; i < Filters.Count; i++)
{
var filter = Filters[i];
presize = filter.PresizeInput(channel, presize);
}
//propagate output size backwards through filter chain to allow a 'flex' filter to determine its output based on the desired output needs
presize = outsize;
for (int i = Filters.Count - 1; i >= 0; i--)
{
var filter = Filters[i];
presize = filter.PresizeOutput(channel, presize);
}
SurfaceState currState = null;
for (int i = 0; i < Filters.Count; i++)
{
BaseFilter f = Filters[i];
//check whether this filter needs input. if so, notify it of the current pipeline state
var iosi = f.FindInput(channel);
if (iosi != null)
{
iosi.SurfaceFormat = currState.SurfaceFormat;
f.SetInputFormat(channel, currState);
//check if the desired disposition needs to change from texture to render target
//(if so, insert a render filter)
if (iosi.SurfaceDisposition == SurfaceDisposition.RenderTarget && currState.SurfaceDisposition == SurfaceDisposition.Texture)
{
var renderer = new Render();
Filters.Insert(i, renderer);
goto RETRY;
}
//check if the desired disposition needs to change from a render target to a texture
//(if so, the current render target gets resolved, and made no longer current
else if (iosi.SurfaceDisposition == SurfaceDisposition.Texture && currState.SurfaceDisposition == SurfaceDisposition.RenderTarget)
{
var resolver = new Resolve();
Filters.Insert(i, resolver);
goto RETRY;
}
}
//now, the filter will have set its output state depending on its input state. check if it outputs:
iosi = f.FindOutput(channel);
if (iosi != null)
{
if (currState == null)
{
currState = new SurfaceState();
currState.SurfaceFormat = iosi.SurfaceFormat;
currState.SurfaceDisposition = iosi.SurfaceDisposition;
}
else
{
//if output disposition is unspecified, change it to whatever we've got right now
if (iosi.SurfaceDisposition == SurfaceDisposition.Unspecified)
{
iosi.SurfaceDisposition = currState.SurfaceDisposition;
}
bool newTarget = false;
if (iosi.SurfaceFormat.Size != currState.SurfaceFormat.Size)
newTarget = true;
else if (currState.SurfaceDisposition == SurfaceDisposition.Texture && iosi.SurfaceDisposition == SurfaceDisposition.RenderTarget)
newTarget = true;
if (newTarget)
{
currState = new SurfaceState();
iosi.SurfaceFormat = currState.SurfaceFormat = iosi.SurfaceFormat;
iosi.SurfaceDisposition = currState.SurfaceDisposition = iosi.SurfaceDisposition;
Program.Add(new ProgramStep(ProgramStepType.NewTarget, currState.SurfaceFormat.Size));
}
else
{
currState.SurfaceDisposition = iosi.SurfaceDisposition;
}
}
}
Program.Add(new ProgramStep(ProgramStepType.Run, i, f.GetType().Name));
} //filter loop
//if the current output disposition is a texture, we need to render it
if (currState.SurfaceDisposition == SurfaceDisposition.Texture)
{
var renderer = new Render();
Filters.Insert(Filters.Count, renderer);
goto RETRY;
}
//patch the program so that the final rendertarget set operation is the framebuffer instead
if (finalTarget)
{
for (int i = Program.Count - 1; i >= 0; i--)
{
var ps = Program[i];
if (ps.Type == ProgramStepType.NewTarget)
{
var size = (Size)ps.Args;
Debug.Assert(size == outsize);
ps.Type = ProgramStepType.FinalTarget;
ps.Args = size;
break;
}
}
}
}
}
}

View File

@ -1,134 +0,0 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk.FilterManager;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK;
using OpenTK.Graphics;
//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
namespace BizHawk.Client.MultiHawk.Filters
{
public class BaseFilter
{
//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 void SetInputFormat(string channel, SurfaceState state) { }
public Dictionary<string, object> Parameters = new Dictionary<string, object>();
//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
var input = FindInput(channel);
var output = FindOutput(channel);
if (input != null && output != null)
{
point.X *= ((float)input.SurfaceFormat.Size.Width) / (float)output.SurfaceFormat.Size.Width;
point.Y *= ((float)input.SurfaceFormat.Size.Height) / (float)output.SurfaceFormat.Size.Height;
}
return point;
}
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
var input = FindInput(channel);
var output = FindOutput(channel);
if (input != null && output != null)
{
point.X *= ((float)output.SurfaceFormat.Size.Width) / (float)input.SurfaceFormat.Size.Width;
point.Y *= ((float)output.SurfaceFormat.Size.Height) / (float)input.SurfaceFormat.Size.Height;
}
return point;
}
public void SetInput(Texture2d tex)
{
InputTexture = tex;
}
public virtual void Run() { }
public Texture2d GetOutput() { return OutputTexture; }
//filter actions
protected void YieldOutput(Texture2d tex)
{
OutputTexture = tex;
}
protected FilterProgram FilterProgram;
protected Texture2d InputTexture;
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); }
protected IOSurfaceInfo DeclareOutput(SurfaceState state, string channel = "default")
{
var iosi = DeclareIO(SurfaceDirection.Output, channel, state.SurfaceDisposition);
iosi.SurfaceFormat = state.SurfaceFormat;
return iosi;
}
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);
return iosi;
}
List<IOSurfaceInfo> IOSurfaceInfos = new List<IOSurfaceInfo>();
IOSurfaceInfo FindIOSurfaceInfo(string channel, SurfaceDirection direction)
{
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 enum SurfaceDirection
{
Input, Output
}
}
}

View File

@ -1,334 +0,0 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk;
using BizHawk.Client.MultiHawk.FilterManager;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK;
using OpenTK.Graphics;
namespace BizHawk.Client.MultiHawk.Filters
{
/// <summary>
/// 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
{
/// <summary>
/// the location within the destination region of the output content (scaled and translated)
/// </summary>
public int vx, vy, vw, vh;
/// <summary>
/// the scale factor eventually used
/// </summary>
public float WidthScale, HeightScale;
//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;
int textureHeight = textureSize.Height;
int virtualWidth = virtualSize.Width;
int virtualHeight = virtualSize.Height;
//zero 02-jun-2014 - we passed these in, but ignored them. kind of weird..
int oldSourceWidth = sourceWidth;
int oldSourceHeight = sourceHeight;
sourceWidth = (int)virtualWidth;
sourceHeight = (int)virtualHeight;
//this doesnt 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
&& !maintainInteger
)
{
if (widthScale > heightScale) widthScale = heightScale;
if (heightScale > widthScale) heightScale = widthScale;
}
if (maintainInteger)
{
//just totally different code
//apply the zooming algorithm (pasted and reworked, for now)
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);
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[] {
PS + new Vector2(1, 0),
PS + new Vector2(0, 1),
PS + new Vector2(1, 1)
};
bool[] trials_limited = 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;
//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;
//I.
float test_ar = vTrial.X / vTrial.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;
float value = deviation_linear;
if (value < bestValue)
{
bestIndex = t;
bestValue = value;
}
}
//last result was best, so bail out
if (bestIndex == -1)
break;
//if the winner ran off the edge, bail out
if (trials_limited[bestIndex])
break;
PS = trials[bestIndex];
}
vw = (int)(PS.X * textureWidth);
vh = (int)(PS.Y * textureHeight);
widthScale = PS.X;
heightScale = PS.Y;
}
else
{
vw = (int)(widthScale * sourceWidth);
vh = (int)(heightScale * sourceHeight);
}
//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;
WidthScale = (float)vw / oldSourceWidth;
HeightScale = (float)vh / oldSourceHeight;
}
}
public class FinalPresentation : BaseFilter
{
public enum eFilterOption
{
None, Bilinear, Bicubic
}
public eFilterOption FilterOption = eFilterOption.None;
public RetroShaderChain BicubicFilter;
public FinalPresentation(Size size)
{
this.OutputSize = size;
}
Size OutputSize, InputSize;
public Size TextureSize, VirtualTextureSize;
public int BackgroundColor;
public IGuiRenderer GuiRenderer;
public IGL GL;
bool nop;
LetterboxingLogic LL;
Size ContentSize;
public override void Initialize()
{
DeclareInput();
nop = false;
}
public override Size PresizeOutput(string channel, Size size)
{
if (FilterOption == eFilterOption.Bicubic)
{
size.Width = LL.vw;
size.Height = LL.vh;
return size;
}
return base.PresizeOutput(channel, size);
}
public override Size PresizeInput(string channel, Size size)
{
if (FilterOption != eFilterOption.Bicubic)
return size;
LL = new LetterboxingLogic(Global.Config.DispFixAspectRatio, Global.Config.DispFixScaleInteger, OutputSize.Width, OutputSize.Height, size.Width, size.Height, TextureSize, VirtualTextureSize);
return size;
}
public override void SetInputFormat(string channel, SurfaceState state)
{
bool need = false;
if (state.SurfaceFormat.Size != OutputSize)
need = true;
if (FilterOption != eFilterOption.None)
need = true;
if (!need)
{
nop = true;
ContentSize = state.SurfaceFormat.Size;
return;
}
FindInput().SurfaceDisposition = SurfaceDisposition.Texture;
DeclareOutput(new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget));
InputSize = state.SurfaceFormat.Size;
LL = new LetterboxingLogic(Global.Config.DispFixAspectRatio, Global.Config.DispFixScaleInteger, OutputSize.Width, OutputSize.Height, InputSize.Width, InputSize.Height, TextureSize, VirtualTextureSize);
ContentSize = new Size(LL.vw,LL.vh);
}
public Size GetContentSize() { return ContentSize; }
public override Vector2 UntransformPoint(string channel, Vector2 point)
{
if (nop)
return point;
point.X -= LL.vx;
point.Y -= LL.vy;
point.X /= LL.WidthScale;
point.Y /= LL.HeightScale;
return point;
}
public override Vector2 TransformPoint(string channel, Vector2 point)
{
if (nop)
return point;
point.X *= LL.WidthScale;
point.Y *= LL.HeightScale;
point.X += LL.vx;
point.Y += LL.vy;
return point;
}
public override void Run()
{
if (nop)
return;
GL.SetClearColor(Color.FromArgb(BackgroundColor));
GL.Clear(OpenTK.Graphics.OpenGL.ClearBufferMask.ColorBufferBit);
GuiRenderer.Begin(OutputSize.Width, OutputSize.Height);
GuiRenderer.SetBlendState(GL.BlendNoneCopy);
if(FilterOption != eFilterOption.None)
InputTexture.SetFilterLinear();
else
InputTexture.SetFilterNearest();
if (FilterOption == eFilterOption.Bicubic)
{
}
GuiRenderer.Draw(InputTexture,LL.vx,LL.vy,LL.vw,LL.vh);
GuiRenderer.End();
}
}
public class LuaLayer : BaseFilter
{
public override void Initialize()
{
DeclareInput(SurfaceDisposition.RenderTarget);
}
public override void SetInputFormat(string channel, SurfaceState state)
{
DeclareOutput(state);
}
Texture2d Texture;
public void SetTexture(Texture2d tex)
{
Texture = tex;
}
public override void Run()
{
var outSize = FindOutput().SurfaceFormat.Size;
FilterProgram.GuiRenderer.Begin(outSize);
FilterProgram.GuiRenderer.SetBlendState(FilterProgram.GL.BlendNormal);
FilterProgram.GuiRenderer.Draw(Texture);
FilterProgram.GuiRenderer.End();
}
}
public class OSD : BaseFilter
{
//this class has the ability to disable its operations for higher performance when the callback is removed,
//without having to take it out of the chain. although, its presence in the chain may slow down performance due to added resolves/renders
//so, we should probably rebuild the chain.
public override void Initialize()
{
if (RenderCallback == null) return;
DeclareInput(SurfaceDisposition.RenderTarget);
}
public override void SetInputFormat(string channel, SurfaceState state)
{
if (RenderCallback == null) return;
DeclareOutput(state);
}
public Action RenderCallback;
public override void Run()
{
if (RenderCallback == null) return;
RenderCallback();
}
}
}

View File

@ -1,285 +0,0 @@
//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.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk;
using BizHawk.Client.MultiHawk.FilterManager;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK;
using OpenTK.Graphics;
namespace BizHawk.Client.MultiHawk.Filters
{
public class RetroShaderChain : IDisposable
{
public RetroShaderChain(IGL owner, RetroShaderPreset preset, string baseDirectory, bool debug = false)
{
Owner = owner;
this.Preset = preset;
Passes = preset.Passes.ToArray();
bool ok = true;
//load up the shaders
Shaders = new RetroShader[preset.Passes.Count];
for (int i = 0; i < preset.Passes.Count; i++)
{
RetroShaderPreset.ShaderPass pass = preset.Passes[i];
//acquire content
string path = Path.Combine(baseDirectory, pass.ShaderPath);
if (!File.Exists(path))
{
ok = false;
break;
}
string content = File.ReadAllText(path);
var shader = new RetroShader(Owner, content, debug);
Shaders[i] = shader;
if (!shader.Pipeline.Available)
ok = false;
}
Available = ok;
}
public void Dispose()
{
//todo
}
/// <summary>
/// Whether this shader chain is available (it wont be available if some resources failed to load or compile)
/// </summary>
public bool Available { get; private set; }
public readonly IGL Owner;
public readonly RetroShaderPreset Preset;
public readonly RetroShader[] Shaders;
public readonly RetroShaderPreset.ShaderPass[] Passes;
}
public class RetroShaderPreset
{
/// <summary>
/// Parses an instance from a stream to a CGP file
/// </summary>
public RetroShaderPreset(Stream stream)
{
var content = new StreamReader(stream).ReadToEnd();
Dictionary<string, string> 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'))
{
var line = _line.Trim();
if (line.StartsWith("#")) continue; //lines that are solely comments
if (line == "") continue; //empty line
int eq = line.IndexOf('=');
var key = line.Substring(0, eq).Trim();
var value = line.Substring(eq + 1).Trim();
int quote = value.IndexOf('\"');
if (quote != -1)
value = value.Substring(quote + 1, value.IndexOf('\"', quote + 1) - (quote + 1));
else
{
//remove comments from end of value. exclusive from above condition, since comments after quoted strings would be snipped by the quoted string extraction
int hash = value.IndexOf('#');
if (hash != -1)
value = value.Substring(0, hash);
value = value.Trim();
}
dict[key.ToLower()] = value;
}
//process the keys
int nShaders = FetchInt(dict, "shaders", 0);
for (int i = 0; i < nShaders; i++)
{
ShaderPass sp = new ShaderPass();
sp.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.
sp.OuputFloat = FetchBool(dict, "float_framebuffer" + i, false);
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.
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.
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 enum ScaleType
{
NotSet, Source, Viewport, Absolute
}
public class ShaderPass
{
public int Index;
public string ShaderPath;
public bool InputFilterLinear;
public bool OuputFloat;
public int FrameCountMod;
public ScaleType ScaleTypeX;
public ScaleType ScaleTypeY;
public Vector2 Scale;
}
string FetchString(Dictionary<string, string> dict, string key, string @default)
{
string str;
if (dict.TryGetValue(key, out str))
return str;
else return @default;
}
int FetchInt(Dictionary<string, string> dict, string key, int @default)
{
string str;
if (dict.TryGetValue(key, out str))
return int.Parse(str);
else return @default;
}
float FetchFloat(Dictionary<string, string> dict, string key, float @default)
{
string str;
if (dict.TryGetValue(key, out str))
return float.Parse(str);
else return @default;
}
bool FetchBool(Dictionary<string, string> dict, string key, bool @default)
{
string str;
if (dict.TryGetValue(key, out str))
return ParseBool(str);
else return @default;
}
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");
}
}
public class RetroShaderPass : BaseFilter
{
RetroShaderChain RSC;
RetroShaderPreset.ShaderPass SP;
int RSI;
Size OutputSize;
public override string ToString()
{
return string.Format("RetroShaderPass[#{0}]", RSI);
}
public RetroShaderPass(RetroShaderChain RSC, int index)
{
this.RSC = RSC;
this.RSI = index;
this.SP = RSC.Passes[index];
}
public override void Initialize()
{
DeclareInput(SurfaceDisposition.Texture);
}
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);
var outState = new SurfaceState();
outState.SurfaceFormat = new SurfaceFormat(OutputSize);
outState.SurfaceDisposition = SurfaceDisposition.RenderTarget;
DeclareOutput(outState);
}
public override Size PresizeOutput(string channel, Size size)
{
OutputSize = size;
return size;
}
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);
return outsize;
}
public override void Run()
{
var shader = RSC.Shaders[RSI];
shader.Bind();
//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);
}
var input = InputTexture;
if (SP.InputFilterLinear)
InputTexture.SetFilterLinear();
else
InputTexture.SetFilterNearest();
RSC.Shaders[RSI].Run(input, input.Size, OutputSize, InputTexture.IsUpsideDown);
//maintain invariant.. i think.
InputTexture.SetFilterNearest();
}
}
}

View File

@ -1,90 +0,0 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Client.MultiHawk;
using BizHawk.Client.MultiHawk.FilterManager;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.BizwareGL.Drivers.OpenTK;
using OpenTK;
using OpenTK.Graphics;
namespace BizHawk.Client.MultiHawk.Filters
{
public class SourceImage : BaseFilter
{
public SourceImage(Size size)
{
this.Size = size;
}
Size Size;
public Texture2d Texture;
public override void Run()
{
YieldOutput(Texture);
}
public override void Initialize()
{
DeclareOutput(new SurfaceState(new SurfaceFormat(Size), SurfaceDisposition.Texture));
}
public override void SetInputFormat(string channel, SurfaceState format)
{
DeclareOutput(SurfaceDisposition.Texture);
}
}
/// <summary>
/// transforms an input texture to an output render target (by rendering it)
/// </summary>
class Render : BaseFilter
{
public override void Initialize()
{
DeclareInput(SurfaceDisposition.Texture);
}
public override void SetInputFormat(string channel, SurfaceState state)
{
DeclareOutput(new SurfaceState(state.SurfaceFormat, SurfaceDisposition.RenderTarget));
}
public override void Run()
{
var renderer = FilterProgram.GuiRenderer;
renderer.Begin(FindOutput().SurfaceFormat.Size);
renderer.SetBlendState(FilterProgram.GL.BlendNoneCopy);
renderer.Draw(InputTexture);
renderer.End();
}
}
class Resolve : BaseFilter
{
public override void Initialize()
{
DeclareInput(SurfaceDisposition.RenderTarget);
}
public override void SetInputFormat(string channel, SurfaceState state)
{
DeclareOutput(new SurfaceState(state.SurfaceFormat, SurfaceDisposition.Texture));
}
public override void Run()
{
YieldOutput(FilterProgram.GetRenderTarget().Texture2d);
}
}
}

View File

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Bizware.BizwareGL;
namespace BizHawk.Client.MultiHawk
{
/// <summary>
/// Recycles a pair of temporary textures (in case double-buffering helps any) to contain a BitmapBuffer's or DisplaySurface's contents, as long as the dimensions match.
/// When the dimensions dont match, a new one will be allocated
/// </summary>
class TextureFrugalizer : IDisposable
{
public TextureFrugalizer(IGL gl)
{
GL = gl;
ResetList();
}
public void Dispose()
{
foreach (var ct in CurrentTextures)
if(ct != null)
ct.Dispose();
ResetList();
}
void ResetList()
{
CurrentTextures = new List<Texture2d>();
CurrentTextures.Add(null);
CurrentTextures.Add(null);
}
IGL GL;
List<Texture2d> CurrentTextures;
public Texture2d Get(DisplaySurface ds)
{
using (var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions()))
{
return Get(bb);
}
}
public Texture2d Get(BitmapBuffer bb)
{
//get the current entry
Texture2d CurrentTexture = CurrentTextures[0];
//TODO - its a bit cruddy here that we dont respect the current texture HasAlpha condition (in fact, theres no such concept)
//we might need to deal with that in the future to fix some bugs.
//check if its rotten and needs recreating
if (CurrentTexture == null || CurrentTexture.IntWidth != bb.Width || CurrentTexture.IntHeight != bb.Height)
{
//needs recreating. be sure to kill the old one...
if (CurrentTexture != null)
CurrentTexture.Dispose();
//and make a new one
CurrentTexture = GL.LoadTexture(bb);
}
else
{
//its good! just load in the data
GL.LoadTextureData(CurrentTexture, bb);
}
//now shuffle the buffers
CurrentTextures[0] = CurrentTextures[1];
CurrentTextures[1] = CurrentTexture;
//deterministic state, i guess
CurrentTexture.SetFilterNearest();
return CurrentTexture;
}
}
}