diff --git a/BizHawk.Client.EmuHawk/AVOut/BitmapBufferVideoProvder.cs b/BizHawk.Client.EmuHawk/AVOut/BitmapBufferVideoProvder.cs
new file mode 100644
index 0000000000..f727cc1398
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/AVOut/BitmapBufferVideoProvder.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+
+using BizHawk.Emulation.Common;
+using BizHawk.Bizware.BizwareGL;
+
+namespace BizHawk.Client.EmuHawk
+{
+ public class BitmapBufferVideoProvider : IVideoProvider, IDisposable
+ {
+ BitmapBuffer bb;
+ public BitmapBufferVideoProvider(BitmapBuffer bb)
+ {
+ this.bb = bb;
+ }
+
+ public void Dispose()
+ {
+ if (bb != null) bb.Dispose();
+ bb = null;
+ }
+
+ public int[] GetVideoBuffer()
+ {
+ return bb.Pixels;
+ }
+
+ public int VirtualWidth
+ {
+ get { return bb.Width; }
+ }
+
+ public int VirtualHeight
+ {
+ get { return bb.Height; }
+ }
+
+ public int BufferWidth
+ {
+ get { return bb.Width; }
+ }
+
+ public int BufferHeight
+ {
+ get { return bb.Height; }
+ }
+
+ public int BackgroundColor
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/AVOut/BmpVideoProvder.cs b/BizHawk.Client.EmuHawk/AVOut/BmpVideoProvder.cs
index d8bf7225a2..5773cb461b 100644
--- a/BizHawk.Client.EmuHawk/AVOut/BmpVideoProvder.cs
+++ b/BizHawk.Client.EmuHawk/AVOut/BmpVideoProvder.cs
@@ -9,12 +9,12 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
///
- /// an IVideoProivder wrapping a Bitmap
+ /// an IVideoProvder wrapping a Bitmap
///
- public class BmpVideoProvder : IVideoProvider, IDisposable
+ public class BmpVideoProvider : IVideoProvider, IDisposable
{
Bitmap bmp;
- public BmpVideoProvder(Bitmap bmp)
+ public BmpVideoProvider(Bitmap bmp)
{
this.bmp = bmp;
}
diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
index 81c3f004f6..6dbb6e855f 100644
--- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
+++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
@@ -123,6 +123,7 @@
ArchiveChooser.cs
+
diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
index a7ac0ef255..c940a4867e 100644
--- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
+++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs
@@ -261,9 +261,28 @@ namespace BizHawk.Client.EmuHawk
///
public void UpdateSource(IVideoProvider videoProvider)
{
- UpdateSourceInternal(videoProvider,false, GraphicsControl.Size);
+ var job = new JobInfo
+ {
+ videoProvider = videoProvider,
+ simulate = false,
+ chain_outsize = GraphicsControl.Size
+ };
+ UpdateSourceInternal(job);
}
+ public BitmapBuffer RenderOffscreen(IVideoProvider videoProvider)
+ {
+ var job = new JobInfo
+ {
+ videoProvider = videoProvider,
+ simulate = false,
+ chain_outsize = GraphicsControl.Size,
+ offscreen = true
+ };
+ UpdateSourceInternal(job);
+ return job.offscreenBB;
+ }
+
class FakeVideoProvider : IVideoProvider
{
public int[] GetVideoBuffer() { return new int[] {}; }
@@ -293,7 +312,13 @@ namespace BizHawk.Client.EmuHawk
if (Global.Config.DispObeyAR && Global.Config.DispFixAspectRatio)
chain_outsize = new Size(fvp.VirtualWidth * zoom, fvp.VirtualHeight * zoom);
- var filterProgram = UpdateSourceInternal(fvp, true, chain_outsize);
+ var job = new JobInfo
+ {
+ videoProvider = fvp,
+ simulate = true,
+ chain_outsize = chain_outsize
+ };
+ var filterProgram = UpdateSourceInternal(job);
var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size;
@@ -313,8 +338,21 @@ namespace BizHawk.Client.EmuHawk
return size;
}
- FilterManager.FilterProgram UpdateSourceInternal(IVideoProvider videoProvider, bool simulate, Size chain_outsize)
+ class JobInfo
{
+ public IVideoProvider videoProvider;
+ public bool simulate;
+ public Size chain_outsize;
+ public bool offscreen;
+ public BitmapBuffer offscreenBB;
+ }
+
+ FilterManager.FilterProgram UpdateSourceInternal(JobInfo job)
+ {
+ IVideoProvider videoProvider = job.videoProvider;
+ bool simulate = job.simulate;
+ Size chain_outsize = job.chain_outsize;
+
int vw = videoProvider.BufferWidth;
int vh = videoProvider.BufferHeight;
@@ -381,7 +419,7 @@ TESTEROO:
fPresent.GuiRenderer = Renderer;
fPresent.GL = GL;
- filterProgram.Compile("default", chain_insize, chain_outsize);
+ filterProgram.Compile("default", chain_insize, chain_outsize, !job.offscreen);
if (simulate)
{
@@ -389,7 +427,7 @@ TESTEROO:
else
{
CurrentFilterProgram = filterProgram;
- UpdateSourceDrawingWork();
+ UpdateSourceDrawingWork(job);
}
//cleanup:
@@ -398,7 +436,7 @@ TESTEROO:
return filterProgram;
}
- void UpdateSourceDrawingWork()
+ void UpdateSourceDrawingWork(JobInfo job)
{
//begin rendering on this context
//should this have been done earlier?
@@ -440,31 +478,41 @@ TESTEROO:
break;
}
case FilterManager.FilterProgram.ProgramStepType.FinalTarget:
- inFinalTarget = true;
- rtCurr = null;
- CurrentFilterProgram.CurrRenderTarget = null;
- GL.BindRenderTarget(null);
- break;
+ {
+ var size = (Size)step.Args;
+ inFinalTarget = true;
+ rtCurr = null;
+ CurrentFilterProgram.CurrRenderTarget = null;
+ GL.BindRenderTarget(null);
+ break;
+ }
}
}
- Debug.Assert(inFinalTarget);
- //apply the vsync setting (should probably try to avoid repeating this)
- bool vsync = Global.Config.VSyncThrottle || Global.Config.VSync;
- if (LastVsyncSetting != vsync || LastVsyncSettingGraphicsControl != presentationPanel.GraphicsControl)
+ if (job.offscreen)
{
- presentationPanel.GraphicsControl.SetVsync(vsync);
- LastVsyncSettingGraphicsControl = presentationPanel.GraphicsControl;
- LastVsyncSetting = vsync;
+ job.offscreenBB = rtCurr.Texture2d.Resolve();
}
+ else
+ {
+ Debug.Assert(inFinalTarget);
+ //apply the vsync setting (should probably try to avoid repeating this)
+ bool vsync = Global.Config.VSyncThrottle || Global.Config.VSync;
+ if (LastVsyncSetting != vsync || LastVsyncSettingGraphicsControl != presentationPanel.GraphicsControl)
+ {
+ presentationPanel.GraphicsControl.SetVsync(vsync);
+ LastVsyncSettingGraphicsControl = presentationPanel.GraphicsControl;
+ LastVsyncSetting = vsync;
+ }
- //present and conclude drawing
- presentationPanel.GraphicsControl.SwapBuffers();
+ //present and conclude drawing
+ presentationPanel.GraphicsControl.SwapBuffers();
- //nope. dont do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything
- //presentationPanel.GraphicsControl.End();
+ //nope. dont do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything
+ //presentationPanel.GraphicsControl.End();
- NeedsToPaint = false; //??
+ NeedsToPaint = false; //??
+ }
}
bool? LastVsyncSetting;
diff --git a/BizHawk.Client.EmuHawk/DisplayManager/FilterManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/FilterManager.cs
index 5470110035..43d9c13404 100644
--- a/BizHawk.Client.EmuHawk/DisplayManager/FilterManager.cs
+++ b/BizHawk.Client.EmuHawk/DisplayManager/FilterManager.cs
@@ -117,7 +117,7 @@ namespace BizHawk.Client.EmuHawk.FilterManager
}
}
- public void Compile(string channel, Size insize, Size outsize)
+ public void Compile(string channel, Size insize, Size outsize, bool finalTarget)
{
RETRY:
@@ -231,16 +231,19 @@ namespace BizHawk.Client.EmuHawk.FilterManager
}
//patch the program so that the final rendertarget set operation is the framebuffer instead
- for (int i = Program.Count - 1; i >= 0; i--)
+ if (finalTarget)
{
- var ps = Program[i];
- if (ps.Type == ProgramStepType.NewTarget)
+ for (int i = Program.Count - 1; i >= 0; i--)
{
- var size = (Size)ps.Args;
- Debug.Assert(size == outsize);
- ps.Type = ProgramStepType.FinalTarget;
- ps.Args = null;
- break;
+ 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;
+ }
}
}
}
diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs
index 994f361f75..c0d4b40c2e 100644
--- a/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.cs
@@ -10,6 +10,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
+using BizHawk.Bizware.BizwareGL;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Cores.Atari.Atari2600;
@@ -758,9 +759,10 @@ namespace BizHawk.Client.EmuHawk
public void TakeScreenshotToClipboard()
{
- using (var img = Global.Config.Screenshot_CaptureOSD ? CaptureOSD() : MakeScreenshotImage())
+ using (var bb = Global.Config.Screenshot_CaptureOSD ? CaptureOSD() : MakeScreenshotImage())
{
- Clipboard.SetImage(img);
+ using(var img = bb.ToSysdrawingBitmap())
+ Clipboard.SetImage(img);
}
GlobalWin.OSD.AddMessage("Screenshot saved to clipboard.");
@@ -781,9 +783,10 @@ namespace BizHawk.Client.EmuHawk
fi.Directory.Create();
}
- using (var img = Global.Config.Screenshot_CaptureOSD ? CaptureOSD() : MakeScreenshotImage())
+ using (var bb = Global.Config.Screenshot_CaptureOSD ? CaptureOSD() : MakeScreenshotImage())
{
- img.Save(fi.FullName, ImageFormat.Png);
+ using(var img = bb.ToSysdrawingBitmap())
+ img.Save(fi.FullName, ImageFormat.Png);
}
GlobalWin.OSD.AddMessage(fi.Name + " saved.");
@@ -1510,43 +1513,46 @@ namespace BizHawk.Client.EmuHawk
}
}
- private static unsafe Image MakeScreenshotImage()
+ private static unsafe BitmapBuffer MakeScreenshotImage()
{
- var video = Global.Emulator.VideoProvider;
- var image = new Bitmap(video.BufferWidth, video.BufferHeight, PixelFormat.Format32bppArgb);
+ //var video = Global.Emulator.VideoProvider;
+ //var image = new Bitmap(video.BufferWidth, video.BufferHeight, PixelFormat.Format32bppArgb);
+ return new BitmapBuffer(Global.Emulator.VideoProvider.BufferWidth, Global.Emulator.VideoProvider.BufferHeight, Global.Emulator.VideoProvider.GetVideoBuffer());
+ //this is all rotten.
+ //among other things, cores are required to set 0xFF000000 themselves
// TODO - replace with BitmapBuffer
- var framebuf = video.GetVideoBuffer();
- var bmpdata = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
- int* ptr = (int*)bmpdata.Scan0.ToPointer();
- int stride = bmpdata.Stride / 4;
- for (int y = 0; y < video.BufferHeight; y++)
- {
- for (int x = 0; x < video.BufferWidth; x++)
- {
- int col = framebuf[(y * video.BufferWidth) + x];
+ //var framebuf = video.GetVideoBuffer();
+ //var bmpdata = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
+ //int* ptr = (int*)bmpdata.Scan0.ToPointer();
+ //int stride = bmpdata.Stride / 4;
+ //for (int y = 0; y < video.BufferHeight; y++)
+ //{
+ // for (int x = 0; x < video.BufferWidth; x++)
+ // {
+ // int col = framebuf[(y * video.BufferWidth) + x];
- if (Global.Emulator is TI83)
- {
- if (col == 0)
- {
- col = Color.Black.ToArgb();
- }
- else
- {
- col = Color.White.ToArgb();
- }
- }
+ // if (Global.Emulator is TI83)
+ // {
+ // if (col == 0)
+ // {
+ // col = Color.Black.ToArgb();
+ // }
+ // else
+ // {
+ // col = Color.White.ToArgb();
+ // }
+ // }
- // make opaque
- col |= unchecked((int)0xff000000);
+ // // make opaque
+ // col |= unchecked((int)0xff000000);
- ptr[(y * stride) + x] = col;
- }
- }
+ // ptr[(y * stride) + x] = col;
+ // }
+ //}
- image.UnlockBits(bmpdata);
- return image;
+ //image.UnlockBits(bmpdata);
+ //return image;
}
private void SaveStateAs()
@@ -1944,26 +1950,11 @@ namespace BizHawk.Client.EmuHawk
Slot9StatusButton.BackColor = Global.Config.SaveSlot == 9 ? SystemColors.Highlight : SystemColors.Control;
}
- //TODO GL - this whole feature will have to be re-added
- private Bitmap CaptureOSD() // sort of like MakeScreenShot(), but with OSD and LUA captured as well. slow and bad.
+ private BitmapBuffer CaptureOSD()
{
- // // this code captures the emu display with OSD and lua composited onto it.
- // // it's slow and a bit hackish; a better solution is to create a new
- // // "dummy render" class that implements IRenderer, IBlitter, and possibly
- // // IVideoProvider, and pass that to DisplayManager.UpdateSourceEx()
- // if (_captureOsdRvp == null)
- // {
- // _captureOsdRvp = new RetainedViewportPanel();
- // _captureOsdSrp = new SysdrawingRenderPanel(_captureOsdRvp);
- // }
-
- // // this size can be different for showing off stretching or filters
- // _captureOsdRvp.Width = Global.Emulator.VideoProvider.BufferWidth;
- // _captureOsdRvp.Height = Global.Emulator.VideoProvider.BufferHeight;
-
- // GlobalWin.DisplayManager.UpdateSourceEx(Global.Emulator.VideoProvider, _captureOsdSrp);
- // return (Bitmap)_captureOsdRvp.GetBitmap().Clone();
- return null;
+ var bb = GlobalWin.DisplayManager.RenderOffscreen(Global.Emulator.VideoProvider);
+ bb.Normalize(true);
+ return bb;
}
private void IncreaseWindowSize()
@@ -2713,7 +2704,7 @@ namespace BizHawk.Client.EmuHawk
var sfd = new SaveFileDialog();
if (!(Global.Emulator is NullEmulator))
{
- sfd.FileName = PathManager.FilesystemSafeName(Global.Game);
+ sfd.FileName = PathManager.FilesystemSafeName(Global.Game) + "." + aw.DesiredExtension(); //dont use Path.ChangeExtension, it might wreck game names with dots in them
sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.AvPathFragment, null);
}
else
@@ -2816,57 +2807,68 @@ namespace BizHawk.Client.EmuHawk
_aviSoundInput.GetSamples(temp);
_dumpProxy.buffer.enqueue_samples(temp, (int)nsamp);
+ //TODO ZERO - this code is pretty jacked. we'll want to frugalize buffers better for speedier dumping, and we might want to rely on the GL layer for padding
try
{
IVideoProvider output;
+ IDisposable disposableOutput = null;
if (_avwriterResizew > 0 && _avwriterResizeh > 0)
{
- Bitmap bmpin;
- if (Global.Config.AVI_CaptureOSD)
+ BizHawk.Bizware.BizwareGL.BitmapBuffer bbin = null;
+ Bitmap bmpin = null;
+ Bitmap bmpout = null;
+ try
{
- bmpin = CaptureOSD();
- }
- else
- {
- bmpin = new Bitmap(
- Global.Emulator.VideoProvider.BufferWidth,
- Global.Emulator.VideoProvider.BufferHeight,
- PixelFormat.Format32bppArgb);
- var lockdata = bmpin.LockBits(
- new Rectangle(0, 0, bmpin.Width, bmpin.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
- System.Runtime.InteropServices.Marshal.Copy(
- Global.Emulator.VideoProvider.GetVideoBuffer(), 0, lockdata.Scan0, bmpin.Width * bmpin.Height);
- bmpin.UnlockBits(lockdata);
- }
-
- var bmpout = new Bitmap(_avwriterResizew, _avwriterResizeh, PixelFormat.Format32bppArgb);
- using (var g = Graphics.FromImage(bmpout))
- {
- if (_avwriterpad)
+ if (Global.Config.AVI_CaptureOSD)
{
- g.Clear(Color.FromArgb(Global.Emulator.VideoProvider.BackgroundColor));
- g.DrawImageUnscaled(bmpin, (bmpout.Width - bmpin.Width) / 2, (bmpout.Height - bmpin.Height) / 2);
+ bbin = CaptureOSD();
}
else
{
- g.DrawImage(bmpin, new Rectangle(0, 0, bmpout.Width, bmpout.Height));
+ bbin = new Bizware.BizwareGL.BitmapBuffer(Global.Emulator.VideoProvider.BufferWidth, Global.Emulator.VideoProvider.BufferHeight, Global.Emulator.VideoProvider.GetVideoBuffer());
}
- }
- bmpin.Dispose();
- output = new BmpVideoProvder(bmpout);
+
+ bmpout = new Bitmap(_avwriterResizew, _avwriterResizeh, PixelFormat.Format32bppArgb);
+ bmpin = bbin.ToSysdrawingBitmap();
+ using (var g = Graphics.FromImage(bmpout))
+ {
+ if (_avwriterpad)
+ {
+ g.Clear(Color.FromArgb(Global.Emulator.VideoProvider.BackgroundColor));
+ g.DrawImageUnscaled(bmpin, (bmpout.Width - bmpin.Width) / 2, (bmpout.Height - bmpin.Height) / 2);
+ }
+ else
+ {
+ g.DrawImage(bmpin, new Rectangle(0, 0, bmpout.Width, bmpout.Height));
+ }
+ }
+
+ output = new BmpVideoProvider(bmpout);
+ disposableOutput = (IDisposable)output;
+ }
+ finally
+ {
+ if (bbin != null) bbin.Dispose();
+ if (bmpin != null) bmpin.Dispose();
+ }
}
else
{
- output = Global.Config.AVI_CaptureOSD
- ? new BmpVideoProvder(CaptureOSD())
- : Global.Emulator.VideoProvider;
+ if (Global.Config.AVI_CaptureOSD)
+ {
+ output = new BitmapBufferVideoProvider(CaptureOSD());
+ disposableOutput = (IDisposable)output;
+ }
+ else
+ output = Global.Emulator.VideoProvider;
}
_currAviWriter.AddFrame(output);
- if (output is BmpVideoProvder)
+
+ if (disposableOutput != null)
{
- (output as BmpVideoProvder).Dispose();
+ disposableOutput.Dispose();
}
_currAviWriter.AddSamples(temp);
diff --git a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/IGL_TK.cs b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/IGL_TK.cs
index 0e4b279e2d..2fdb0c4f22 100644
--- a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/IGL_TK.cs
+++ b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/IGL_TK.cs
@@ -465,7 +465,7 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
BindTexture2d(tex);
var bb = new BitmapBuffer(tex.IntWidth, tex.IntHeight);
var bmpdata = bb.LockBits();
- GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Bgra, PixelType.Byte, bmpdata.Scan0);
+ GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Bgra, PixelType.UnsignedByte, bmpdata.Scan0);
bb.UnlockBits(bmpdata);
return bb;
}
diff --git a/Bizware/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs b/Bizware/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs
index 218eef9e57..ae84c7fc10 100644
--- a/Bizware/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs
+++ b/Bizware/BizHawk.Bizware.BizwareGL/BitmapBuffer.cs
@@ -76,6 +76,34 @@ namespace BizHawk.Bizware.BizwareGL
UnlockBits(CurrLock);
}
+ public unsafe void Normalize(bool yflip)
+ {
+ var bmpdata = LockBits();
+ int[] newPixels = new int[Width * Height];
+ int todo = Width*Height;
+ int* s = (int*)bmpdata.Scan0.ToPointer();
+ fixed (int* d = newPixels)
+ {
+ if (yflip)
+ for (int y = 0, si = 0, di = (Height - 1) * Width; y < Height; y++)
+ {
+ for (int x = 0; x < Width; x++, si++, di++)
+ {
+ d[di] = s[si] | unchecked((int)0xFF000000);
+ }
+ di -= Width * 2;
+ }
+ else
+ {
+ //TODO
+ }
+ }
+
+ UnlockBits(bmpdata);
+
+ Pixels = newPixels;
+ }
+
public int GetPixel(int x, int y) { return Pixels[Width * y + x]; }
public void SetPixel(int x, int y, int value) { Pixels[Width * y + x] = value; }
public Color GetPixelAsColor(int x, int y)