fix av dumping with osd enabled (screenshots as well);

default av dumping extension to the dumper plugin's desired default
This commit is contained in:
zeromus 2014-06-02 20:16:59 +00:00
parent 239eb5b268
commit bb1b1ff5b5
8 changed files with 260 additions and 122 deletions

View File

@ -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; }
}
}
}

View File

@ -9,12 +9,12 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// an IVideoProivder wrapping a Bitmap
/// an IVideoProvder wrapping a Bitmap
/// </summary>
public class BmpVideoProvder : IVideoProvider, IDisposable
public class BmpVideoProvider : IVideoProvider, IDisposable
{
Bitmap bmp;
public BmpVideoProvder(Bitmap bmp)
public BmpVideoProvider(Bitmap bmp)
{
this.bmp = bmp;
}

View File

@ -123,6 +123,7 @@
<DependentUpon>ArchiveChooser.cs</DependentUpon>
</Compile>
<Compile Include="AVOut\AviWriter.cs" />
<Compile Include="AVOut\BitmapBufferVideoProvder.cs" />
<Compile Include="AVOut\BmpVideoProvder.cs" />
<Compile Include="AVOut\FFmpegWriter.cs" />
<Compile Include="AVOut\FFmpegWriterForm.cs">

View File

@ -261,9 +261,28 @@ namespace BizHawk.Client.EmuHawk
/// </summary>
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;

View File

@ -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;
}
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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)