Created
August 16, 2016 14:46
-
-
Save elliotwoods/eefd2c7a269aba4fe9980b4a5c8a5aa5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region usings | |
using System; | |
using System.ComponentModel.Composition; | |
using System.Runtime.InteropServices; | |
using SlimDX; | |
//using SlimDX.Direct3D9; | |
using VVVV.Core.Logging; | |
using VVVV.PluginInterfaces.V1; | |
using VVVV.PluginInterfaces.V2; | |
using VVVV.PluginInterfaces.V2.EX9; | |
using VVVV.Utils.VColor; | |
using VVVV.Utils.VMath; | |
//using VVVV.Utils.SlimDX; | |
using System.Collections.Generic; | |
using System.Drawing; | |
using System.Windows.Forms; | |
using System.IO; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Drawing.Imaging; | |
using System.Diagnostics; | |
using FeralTic.DX11.Resources; | |
using VVVV.DX11; | |
using System.Security.Permissions; | |
using FeralTic.DX11; | |
using SlimDX.Direct3D11; | |
#endregion usings | |
namespace VVVV.Nodes.Recorder | |
{ | |
#region PluginInfo | |
[PluginInfo(Name = "Writer", | |
Category = "DX11.Texture2D", | |
Version = "Parallel", | |
Help = "Write textures to disk in parallel", | |
Tags = "", | |
AutoEvaluate = true)] | |
#endregion PluginInfo | |
public class RecordNodeDX11 : IPluginEvaluate, IDX11ResourceDataRetriever, IDisposable | |
{ | |
class Saver : IDisposable | |
{ | |
public bool Completed { get; private set; } = false; | |
public bool Failed { get; private set; } = false; | |
bool FCompletedBang = false; | |
public bool CompletedBang | |
{ | |
get | |
{ | |
if(FCompletedBang) | |
{ | |
FCompletedBang = false; | |
return true; | |
} else | |
{ | |
return false; | |
} | |
} | |
set | |
{ | |
FCompletedBang = value; | |
} | |
} | |
string FStatus = ""; | |
public string Status | |
{ | |
get | |
{ | |
string copy; | |
lock (FStatus) | |
{ | |
copy = FStatus; | |
} | |
return copy; | |
} | |
set | |
{ | |
lock (FStatus) | |
{ | |
FStatus = value; | |
} | |
} | |
} | |
Thread FThread; | |
public Saver() | |
{ | |
} | |
public void Save(SlimDX.DXGI.Adapter adapter, DX11Texture2D texture, string filename, ImageFileFormat format) | |
{ | |
try | |
{ | |
var renderDevice = texture.Resource.Device; | |
var renderDeviceContext = renderDevice.ImmediateContext; | |
//create a shared texture | |
var sharedTextureDescription = texture.Description; | |
{ | |
sharedTextureDescription.Usage = ResourceUsage.Default; | |
sharedTextureDescription.OptionFlags |= ResourceOptionFlags.Shared; | |
} | |
var sharedTextureOnRenderDevice = new Texture2D(renderDevice, sharedTextureDescription); | |
//copy input texture to shared texture | |
{ | |
renderDeviceContext.CopyResource(texture.Resource, sharedTextureOnRenderDevice); | |
} | |
//create a device/context for saving | |
#if DEBUG | |
Device saveDevice = new SlimDX.Direct3D11.Device(adapter, DeviceCreationFlags.Debug); | |
#else | |
Device saveDevice = new SlimDX.Direct3D11.Device(adapter); | |
#endif | |
DeviceContext saveContext = saveDevice.ImmediateContext; | |
//flush the immediate context to ensure that our shared texture is available | |
{ | |
var queryDescription = new QueryDescription(QueryType.Event, QueryFlags.None); | |
var query = new Query(renderDevice, queryDescription); | |
renderDeviceContext.Flush(); | |
renderDeviceContext.End(query); | |
while(renderDeviceContext.GetData<bool>(query)) | |
{ | |
Thread.Sleep(1); | |
} | |
} | |
//create a new texture in shared context from existing texture | |
Texture2D sharedTextureOnSaveDevice; | |
{ | |
SlimDX.DXGI.Resource r = new SlimDX.DXGI.Resource(sharedTextureOnRenderDevice); | |
sharedTextureOnSaveDevice = saveDevice.OpenSharedResource<Texture2D>(r.SharedHandle); | |
} | |
//copy the shared texture into a staging texture | |
Texture2D stagingTexture; | |
{ | |
var stagingTextureDescription = texture.Description; | |
{ | |
stagingTextureDescription.Usage = ResourceUsage.Default; | |
} | |
stagingTexture = new Texture2D(saveDevice, stagingTextureDescription); | |
saveContext.CopyResource(sharedTextureOnSaveDevice, stagingTexture); | |
} | |
this.FThread = new Thread(() => | |
{ | |
try | |
{ | |
//gain rights to write to file | |
(new FileIOPermission(FileIOPermissionAccess.Write, filename)).Demand(); | |
//perform read back and save in thread | |
try | |
{ | |
Resource.SaveTextureToFile(saveContext, stagingTexture, format, filename); | |
} | |
catch (Exception e) | |
{ | |
throw (new Exception("SaveTextureToFile failed : " + e.Message)); | |
} | |
this.CompletedBang = true; | |
this.Completed = true; | |
this.Status = "OK"; | |
} | |
catch (Exception e) | |
{ | |
this.Completed = true; | |
this.Status = e.Message; | |
this.Failed = true; | |
} | |
}); | |
this.FThread.Name = "DX11 read"; | |
this.FThread.Start(); | |
} | |
catch (Exception e) | |
{ | |
this.Completed = true; | |
this.Failed = true; | |
this.Status = e.Message; | |
} | |
} | |
public void Dispose() | |
{ | |
if(!this.Completed) | |
{ | |
if(this.FThread != null) | |
{ | |
if(!this.FThread.Join(1000)) | |
{ | |
this.FThread.Abort() | |
} | |
this.FThread = null; | |
} | |
this.Completed = true; | |
} | |
} | |
}; | |
#region fields & pins | |
#pragma warning disable 0649 | |
[Input("Input")] | |
Pin<DX11Resource<DX11Texture2D>> FInTexture; | |
[Input("Format")] | |
protected ISpread<SlimDX.Direct3D11.ImageFileFormat> FInFormat; | |
[Input("Filename", StringType = StringType.Filename)] | |
ISpread<string> FInFilename; | |
[Input("Write")] | |
ISpread<bool> FInWrite; | |
[Output("Status")] | |
ISpread<string> FOutStatus; | |
[Output("Valid")] | |
ISpread<bool> FOutValid; | |
[Import()] | |
protected IPluginHost FHost; | |
[Import] | |
public ILogger FLogger; | |
[Import] | |
IHDEHost FHDEHost; | |
List<Saver> FSavers = new List<Saver>(); | |
#pragma warning restore 0649 | |
#endregion fields & pins | |
// import host and hand it to base constructor | |
[ImportingConstructor()] | |
public RecordNodeDX11(IPluginHost host) | |
{ | |
} | |
public void Evaluate(int SpreadMax) | |
{ | |
//Check our GPU connection is setup | |
try | |
{ | |
if (FInTexture.PluginIO.IsConnected) | |
{ | |
if (this.RenderRequest != null) { this.RenderRequest(this, this.FHost); } | |
if (this.AssignedContext == null) { return; } | |
} | |
} | |
catch (Exception e) | |
{ | |
FLogger.Log(e); | |
FOutStatus.SliceCount = 1; | |
FOutStatus[0] = e.Message; | |
return; | |
} | |
//setup the saver slots | |
while(FSavers.Count < SpreadMax) | |
{ | |
FSavers.Add(null); | |
} | |
while (FSavers.Count > SpreadMax) | |
{ | |
if (FSavers[SpreadMax] != null) | |
{ | |
FSavers[SpreadMax].Dispose(); | |
} | |
FSavers.RemoveAt(SpreadMax); | |
} | |
FOutStatus.SliceCount = SpreadMax; | |
FOutValid.SliceCount = SpreadMax; | |
//perform the calls | |
for (int i = 0; i < SpreadMax; i++) | |
{ | |
if (FInWrite[i]) | |
{ | |
try | |
{ | |
Saver saver; | |
if(FSavers[i] != null) | |
{ | |
saver = FSavers[i]; | |
} else | |
{ | |
saver = new Saver(); | |
FSavers[i] = saver; | |
} | |
saver.Save(AssignedContext.Adapter, FInTexture[i][AssignedContext], FInFilename[i], FInFormat[i]); | |
} | |
catch (Exception e) | |
{ | |
FOutStatus[i] = e.Message; | |
} | |
} | |
} | |
//wait for all calls to complete | |
{ | |
while(true) | |
{ | |
bool completed = true; | |
foreach (var saver in FSavers) | |
{ | |
if(saver != null) | |
{ | |
if (!saver.Completed) | |
{ | |
completed = false; | |
break; | |
} | |
} | |
} | |
if (completed) | |
{ | |
break; | |
} else | |
{ | |
Thread.Sleep(1); | |
} | |
} | |
} | |
//read back the status | |
{ | |
for(int i=0; i<SpreadMax; i++) | |
{ | |
var saver = FSavers[i]; | |
if(saver == null) | |
{ | |
FOutValid[i] = false; | |
FOutStatus[i] = ""; | |
} else | |
{ | |
FOutValid[i] = saver.CompletedBang; | |
FOutStatus[i] = saver.Status; | |
} | |
} | |
} | |
} | |
public FeralTic.DX11.DX11RenderContext AssignedContext | |
{ | |
get; | |
set; | |
} | |
public event DX11RenderRequestDelegate RenderRequest; | |
public void Dispose() | |
{ | |
foreach(var saver in this.FSavers) | |
{ | |
if(saver != null) | |
{ | |
saver.Dispose(); | |
} | |
} | |
FSavers.Clear(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment