/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2015-2016 Baldur Karlsson * Copyright (c) 2014 Crytek * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ using System; using System.Runtime.InteropServices; using System.Collections.Generic; namespace renderdoc { [StructLayout(LayoutKind.Sequential)] public class RemoteMessage { public RemoteMessageType Type; [StructLayout(LayoutKind.Sequential)] public struct NewCaptureData { public UInt32 ID; public UInt64 timestamp; [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] public byte[] thumbnail; [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] public string localpath; }; [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public NewCaptureData NewCapture; [StructLayout(LayoutKind.Sequential)] public struct RegisterAPIData { [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] public string APIName; }; [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public RegisterAPIData RegisterAPI; [StructLayout(LayoutKind.Sequential)] public struct BusyData { [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] public string ClientName; }; [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public BusyData Busy; [StructLayout(LayoutKind.Sequential)] public struct NewChildData { public UInt32 PID; public UInt32 ident; }; [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public NewChildData NewChild; }; public class ReplayOutput { [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetOutputConfig(IntPtr real, OutputConfig o); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetTextureDisplay(IntPtr real, TextureDisplay o); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetMeshDisplay(IntPtr real, MeshDisplay o); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_ClearThumbnails(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_AddThumbnail(IntPtr real, IntPtr wnd, ResourceId texID); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_Display(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetPixelContext(IntPtr real, IntPtr wnd); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_SetPixelContextLocation(IntPtr real, UInt32 x, UInt32 y); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayOutput_DisablePixelContext(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayOutput_GetCustomShaderTexID(IntPtr real, ref ResourceId texid); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_PickPixel(IntPtr real, ResourceId texID, bool customShader, UInt32 x, UInt32 y, UInt32 sliceFace, UInt32 mip, UInt32 sample, IntPtr outval); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 ReplayOutput_PickVertex(IntPtr real, UInt32 eventID, UInt32 x, UInt32 y); private IntPtr m_Real = IntPtr.Zero; public ReplayOutput(IntPtr real) { m_Real = real; } public bool SetOutputConfig(OutputConfig o) { return ReplayOutput_SetOutputConfig(m_Real, o); } public bool SetTextureDisplay(TextureDisplay o) { return ReplayOutput_SetTextureDisplay(m_Real, o); } public bool SetMeshDisplay(MeshDisplay o) { return ReplayOutput_SetMeshDisplay(m_Real, o); } public bool ClearThumbnails() { return ReplayOutput_ClearThumbnails(m_Real); } public bool AddThumbnail(IntPtr wnd, ResourceId texID) { return ReplayOutput_AddThumbnail(m_Real, wnd, texID); } public bool Display() { return ReplayOutput_Display(m_Real); } public bool SetPixelContext(IntPtr wnd) { return ReplayOutput_SetPixelContext(m_Real, wnd); } public bool SetPixelContextLocation(UInt32 x, UInt32 y) { return ReplayOutput_SetPixelContextLocation(m_Real, x, y); } public void DisablePixelContext() { ReplayOutput_DisablePixelContext(m_Real); } public ResourceId GetCustomShaderTexID() { ResourceId ret = ResourceId.Null; ReplayOutput_GetCustomShaderTexID(m_Real, ref ret); return ret; } public PixelValue PickPixel(ResourceId texID, bool customShader, UInt32 x, UInt32 y, UInt32 sliceFace, UInt32 mip, UInt32 sample) { IntPtr mem = CustomMarshal.Alloc(typeof(PixelValue)); bool success = ReplayOutput_PickPixel(m_Real, texID, customShader, x, y, sliceFace, mip, sample, mem); PixelValue ret = null; if(success) ret = (PixelValue)CustomMarshal.PtrToStructure(mem, typeof(PixelValue), false); CustomMarshal.Free(mem); return ret; } public UInt32 PickVertex(UInt32 eventID, UInt32 x, UInt32 y) { return ReplayOutput_PickVertex(m_Real, eventID, x, y); } }; public class ReplayRenderer { [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_Shutdown(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_GetAPIProperties(IntPtr real, IntPtr propsOut); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr ReplayRenderer_CreateOutput(IntPtr real, IntPtr WindowHandle, OutputType type); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_ShutdownOutput(IntPtr real, IntPtr replayOutput); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_FileChanged(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_HasCallstacks(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_InitResolver(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_SetContextFilter(IntPtr real, ResourceId id, UInt32 firstDefEv, UInt32 lastDefEv); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_SetFrameEvent(IntPtr real, UInt32 eventID, bool force); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetD3D11PipelineState(IntPtr real, IntPtr mem); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetGLPipelineState(IntPtr real, IntPtr mem); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetVulkanPipelineState(IntPtr real, IntPtr mem); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_BuildCustomShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_FreeCustomShader(IntPtr real, ResourceId id); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void ReplayRenderer_BuildTargetShader(IntPtr real, IntPtr entry, IntPtr source, UInt32 compileFlags, ShaderStageType type, ref ResourceId shaderID, IntPtr errorMem); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_ReplaceResource(IntPtr real, ResourceId from, ResourceId to); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_RemoveReplacement(IntPtr real, ResourceId id); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_FreeTargetResource(IntPtr real, ResourceId id); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetFrameInfo(IntPtr real, IntPtr outframe); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetDrawcalls(IntPtr real, IntPtr outdraws); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_FetchCounters(IntPtr real, IntPtr counters, UInt32 numCounters, IntPtr outresults); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_EnumerateCounters(IntPtr real, IntPtr outcounters); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_DescribeCounter(IntPtr real, UInt32 counter, IntPtr outdesc); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetTextures(IntPtr real, IntPtr outtexs); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetBuffers(IntPtr real, IntPtr outbufs); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetResolve(IntPtr real, UInt64[] callstack, UInt32 callstackLen, IntPtr outtrace); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetDebugMessages(IntPtr real, IntPtr outmsgs); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_PixelHistory(IntPtr real, ResourceId target, UInt32 x, UInt32 y, UInt32 slice, UInt32 mip, UInt32 sampleIdx, IntPtr history); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_DebugVertex(IntPtr real, UInt32 vertid, UInt32 instid, UInt32 idx, UInt32 instOffset, UInt32 vertOffset, IntPtr outtrace); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_DebugPixel(IntPtr real, UInt32 x, UInt32 y, UInt32 sample, UInt32 primitive, IntPtr outtrace); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_DebugThread(IntPtr real, UInt32[] groupid, UInt32[] threadid, IntPtr outtrace); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetUsage(IntPtr real, ResourceId id, IntPtr outusage); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetCBufferVariableContents(IntPtr real, ResourceId shader, IntPtr entryPoint, UInt32 cbufslot, ResourceId buffer, UInt64 offs, IntPtr outvars); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_SaveTexture(IntPtr real, TextureSave saveData, IntPtr path); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetPostVSData(IntPtr real, UInt32 instID, MeshDataStage stage, IntPtr outdata); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetMinMax(IntPtr real, ResourceId tex, UInt32 sliceFace, UInt32 mip, UInt32 sample, IntPtr outminval, IntPtr outmaxval); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetHistogram(IntPtr real, ResourceId tex, UInt32 sliceFace, UInt32 mip, UInt32 sample, float minval, float maxval, bool[] channels, IntPtr outhistogram); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetBufferData(IntPtr real, ResourceId buff, UInt64 offset, UInt64 len, IntPtr outdata); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetTextureData(IntPtr real, ResourceId tex, UInt32 arrayIdx, UInt32 mip, IntPtr outdata); private IntPtr m_Real = IntPtr.Zero; public ReplayRenderer(IntPtr real) { m_Real = real; } public void Shutdown() { if (m_Real != IntPtr.Zero) { ReplayRenderer_Shutdown(m_Real); m_Real = IntPtr.Zero; } } public APIProperties GetAPIProperties() { IntPtr mem = CustomMarshal.Alloc(typeof(APIProperties)); ReplayRenderer_GetAPIProperties(m_Real, mem); APIProperties ret = (APIProperties)CustomMarshal.PtrToStructure(mem, typeof(APIProperties), true); CustomMarshal.Free(mem); return ret; } public ReplayOutput CreateOutput(IntPtr WindowHandle, OutputType type) { IntPtr ret = ReplayRenderer_CreateOutput(m_Real, WindowHandle, type); if (ret == IntPtr.Zero) return null; return new ReplayOutput(ret); } public void FileChanged() { ReplayRenderer_FileChanged(m_Real); } public bool HasCallstacks() { return ReplayRenderer_HasCallstacks(m_Real); } public bool InitResolver() { return ReplayRenderer_InitResolver(m_Real); } public bool SetContextFilter(ResourceId id, UInt32 firstDefEv, UInt32 lastDefEv) { return ReplayRenderer_SetContextFilter(m_Real, id, firstDefEv, lastDefEv); } public bool SetFrameEvent(UInt32 eventID, bool force) { return ReplayRenderer_SetFrameEvent(m_Real, eventID, force); } public GLPipelineState GetGLPipelineState() { IntPtr mem = CustomMarshal.Alloc(typeof(GLPipelineState)); bool success = ReplayRenderer_GetGLPipelineState(m_Real, mem); GLPipelineState ret = null; if (success) ret = (GLPipelineState)CustomMarshal.PtrToStructure(mem, typeof(GLPipelineState), true); CustomMarshal.Free(mem); return ret; } public D3D11PipelineState GetD3D11PipelineState() { IntPtr mem = CustomMarshal.Alloc(typeof(D3D11PipelineState)); bool success = ReplayRenderer_GetD3D11PipelineState(m_Real, mem); D3D11PipelineState ret = null; if (success) ret = (D3D11PipelineState)CustomMarshal.PtrToStructure(mem, typeof(D3D11PipelineState), true); CustomMarshal.Free(mem); return ret; } public VulkanPipelineState GetVulkanPipelineState() { IntPtr mem = CustomMarshal.Alloc(typeof(VulkanPipelineState)); bool success = ReplayRenderer_GetVulkanPipelineState(m_Real, mem); VulkanPipelineState ret = null; if (success) ret = (VulkanPipelineState)CustomMarshal.PtrToStructure(mem, typeof(VulkanPipelineState), true); CustomMarshal.Free(mem); return ret; } public ResourceId BuildCustomShader(string entry, string source, UInt32 compileFlags, ShaderStageType type, out string errors) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); ResourceId ret = ResourceId.Null; IntPtr entry_mem = CustomMarshal.MakeUTF8String(entry); IntPtr source_mem = CustomMarshal.MakeUTF8String(source); ReplayRenderer_BuildCustomShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem); CustomMarshal.Free(entry_mem); CustomMarshal.Free(source_mem); errors = CustomMarshal.TemplatedArrayToString(mem, true); CustomMarshal.Free(mem); return ret; } public bool FreeCustomShader(ResourceId id) { return ReplayRenderer_FreeCustomShader(m_Real, id); } public ResourceId BuildTargetShader(string entry, string source, UInt32 compileFlags, ShaderStageType type, out string errors) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); ResourceId ret = ResourceId.Null; IntPtr entry_mem = CustomMarshal.MakeUTF8String(entry); IntPtr source_mem = CustomMarshal.MakeUTF8String(source); ReplayRenderer_BuildTargetShader(m_Real, entry_mem, source_mem, compileFlags, type, ref ret, mem); CustomMarshal.Free(entry_mem); CustomMarshal.Free(source_mem); errors = CustomMarshal.TemplatedArrayToString(mem, true); CustomMarshal.Free(mem); return ret; } public bool ReplaceResource(ResourceId from, ResourceId to) { return ReplayRenderer_ReplaceResource(m_Real, from, to); } public bool RemoveReplacement(ResourceId id) { return ReplayRenderer_RemoveReplacement(m_Real, id); } public bool FreeTargetResource(ResourceId id) { return ReplayRenderer_FreeTargetResource(m_Real, id); } public FetchFrameInfo GetFrameInfo() { IntPtr mem = CustomMarshal.Alloc(typeof(FetchFrameInfo)); bool success = ReplayRenderer_GetFrameInfo(m_Real, mem); FetchFrameInfo ret = null; if (success) ret = (FetchFrameInfo)CustomMarshal.PtrToStructure(mem, typeof(FetchFrameInfo), true); CustomMarshal.Free(mem); return ret; } private void PopulateDraws(ref Dictionary map, FetchDrawcall[] draws) { if (draws.Length == 0) return; foreach (var d in draws) { map.Add((Int64)d.eventID, d); PopulateDraws(ref map, d.children); } } private void FixupDraws(Dictionary map, FetchDrawcall[] draws) { if (draws.Length == 0) return; foreach (var d in draws) { if (d.previousDrawcall != 0 && map.ContainsKey(d.previousDrawcall)) d.previous = map[d.previousDrawcall]; if (d.nextDrawcall != 0 && map.ContainsKey(d.nextDrawcall)) d.next = map[d.nextDrawcall]; if (d.parentDrawcall != 0 && map.ContainsKey(d.parentDrawcall)) d.parent = map[d.parentDrawcall]; FixupDraws(map, d.children); } } public Dictionary> FetchCounters(UInt32[] counters) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); IntPtr countersmem = CustomMarshal.Alloc(typeof(UInt32), counters.Length); // there's no Marshal.Copy for uint[], which is stupid. for (int i = 0; i < counters.Length; i++) Marshal.WriteInt32(countersmem, sizeof(UInt32) * i, (int)counters[i]); bool success = ReplayRenderer_FetchCounters(m_Real, countersmem, (uint)counters.Length, mem); CustomMarshal.Free(countersmem); Dictionary> ret = null; if (success) { CounterResult[] resultArray = (CounterResult[])CustomMarshal.GetTemplatedArray(mem, typeof(CounterResult), true); // fixup previous/next/parent pointers ret = new Dictionary>(); foreach (var result in resultArray) { if (!ret.ContainsKey(result.eventID)) ret.Add(result.eventID, new List()); ret[result.eventID].Add(result); } } CustomMarshal.Free(mem); return ret; } public UInt32[] EnumerateCounters() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_EnumerateCounters(m_Real, mem); UInt32[] ret = null; if (success) { ret = (UInt32[])CustomMarshal.GetTemplatedArray(mem, typeof(UInt32), true); } CustomMarshal.Free(mem); return ret; } public CounterDescription DescribeCounter(UInt32 counterID) { IntPtr mem = CustomMarshal.Alloc(typeof(CounterDescription)); bool success = ReplayRenderer_DescribeCounter(m_Real, counterID, mem); CounterDescription ret = null; if (success) { ret = (CounterDescription)CustomMarshal.PtrToStructure(mem, typeof(CounterDescription), false); } CustomMarshal.Free(mem); return ret; } public FetchDrawcall[] GetDrawcalls() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetDrawcalls(m_Real, mem); FetchDrawcall[] ret = null; if (success) { ret = (FetchDrawcall[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchDrawcall), true); // fixup previous/next/parent pointers var map = new Dictionary(); PopulateDraws(ref map, ret); FixupDraws(map, ret); } CustomMarshal.Free(mem); return ret; } public FetchTexture[] GetTextures() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetTextures(m_Real, mem); FetchTexture[] ret = null; if (success) ret = (FetchTexture[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchTexture), true); CustomMarshal.Free(mem); return ret; } public FetchBuffer[] GetBuffers() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetBuffers(m_Real, mem); FetchBuffer[] ret = null; if (success) ret = (FetchBuffer[])CustomMarshal.GetTemplatedArray(mem, typeof(FetchBuffer), true); CustomMarshal.Free(mem); return ret; } public string[] GetResolve(UInt64[] callstack) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); UInt32 len = (UInt32)callstack.Length; bool success = ReplayRenderer_GetResolve(m_Real, callstack, len, mem); string[] ret = null; if (success) ret = CustomMarshal.TemplatedArrayToStringArray(mem, true); CustomMarshal.Free(mem); return ret; } public DebugMessage[] GetDebugMessages() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetDebugMessages(m_Real, mem); DebugMessage[] ret = null; if (success) ret = (DebugMessage[])CustomMarshal.GetTemplatedArray(mem, typeof(DebugMessage), true); CustomMarshal.Free(mem); return ret; } public PixelModification[] PixelHistory(ResourceId target, UInt32 x, UInt32 y, UInt32 slice, UInt32 mip, UInt32 sampleIdx) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_PixelHistory(m_Real, target, x, y, slice, mip, sampleIdx, mem); PixelModification[] ret = null; if (success) ret = (PixelModification[])CustomMarshal.GetTemplatedArray(mem, typeof(PixelModification), true); CustomMarshal.Free(mem); return ret; } public ShaderDebugTrace DebugVertex(UInt32 vertid, UInt32 instid, UInt32 idx, UInt32 instOffset, UInt32 vertOffset) { IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); bool success = ReplayRenderer_DebugVertex(m_Real, vertid, instid, idx, instOffset, vertOffset, mem); ShaderDebugTrace ret = null; if (success) ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); CustomMarshal.Free(mem); return ret; } public ShaderDebugTrace DebugPixel(UInt32 x, UInt32 y, UInt32 sample, UInt32 primitive) { IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); bool success = ReplayRenderer_DebugPixel(m_Real, x, y, sample, primitive, mem); ShaderDebugTrace ret = null; if (success) ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); CustomMarshal.Free(mem); return ret; } public ShaderDebugTrace DebugThread(UInt32[] groupid, UInt32[] threadid) { IntPtr mem = CustomMarshal.Alloc(typeof(ShaderDebugTrace)); bool success = ReplayRenderer_DebugThread(m_Real, groupid, threadid, mem); ShaderDebugTrace ret = null; if (success) ret = (ShaderDebugTrace)CustomMarshal.PtrToStructure(mem, typeof(ShaderDebugTrace), true); CustomMarshal.Free(mem); return ret; } public EventUsage[] GetUsage(ResourceId id) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetUsage(m_Real, id, mem); EventUsage[] ret = null; if (success) ret = (EventUsage[])CustomMarshal.GetTemplatedArray(mem, typeof(EventUsage), true); CustomMarshal.Free(mem); return ret; } public ShaderVariable[] GetCBufferVariableContents(ResourceId shader, string entryPoint, UInt32 cbufslot, ResourceId buffer, UInt64 offs) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); IntPtr entry_mem = CustomMarshal.MakeUTF8String(entryPoint); bool success = ReplayRenderer_GetCBufferVariableContents(m_Real, shader, entry_mem, cbufslot, buffer, offs, mem); ShaderVariable[] ret = null; if (success) ret = (ShaderVariable[])CustomMarshal.GetTemplatedArray(mem, typeof(ShaderVariable), true); CustomMarshal.Free(entry_mem); CustomMarshal.Free(mem); return ret; } public bool SaveTexture(TextureSave saveData, string path) { IntPtr path_mem = CustomMarshal.MakeUTF8String(path); bool ret = ReplayRenderer_SaveTexture(m_Real, saveData, path_mem); CustomMarshal.Free(path_mem); return ret; } public MeshFormat GetPostVSData(UInt32 instID, MeshDataStage stage) { IntPtr mem = CustomMarshal.Alloc(typeof(MeshFormat)); MeshFormat ret = new MeshFormat(); ret.buf = ResourceId.Null; bool success = ReplayRenderer_GetPostVSData(m_Real, instID, stage, mem); if (success) ret = (MeshFormat)CustomMarshal.PtrToStructure(mem, typeof(MeshFormat), true); CustomMarshal.Free(mem); return ret; } public bool GetMinMax(ResourceId tex, UInt32 sliceFace, UInt32 mip, UInt32 sample, out PixelValue minval, out PixelValue maxval) { IntPtr mem1 = CustomMarshal.Alloc(typeof(PixelValue)); IntPtr mem2 = CustomMarshal.Alloc(typeof(PixelValue)); bool success = ReplayRenderer_GetMinMax(m_Real, tex, sliceFace, mip, sample, mem1, mem2); if (success) { minval = (PixelValue)CustomMarshal.PtrToStructure(mem1, typeof(PixelValue), true); maxval = (PixelValue)CustomMarshal.PtrToStructure(mem2, typeof(PixelValue), true); } else { minval = null; maxval = null; } CustomMarshal.Free(mem1); CustomMarshal.Free(mem2); return success; } public bool GetHistogram(ResourceId tex, UInt32 sliceFace, UInt32 mip, UInt32 sample, float minval, float maxval, bool Red, bool Green, bool Blue, bool Alpha, out UInt32[] histogram) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool[] channels = new bool[] { Red, Green, Blue, Alpha }; bool success = ReplayRenderer_GetHistogram(m_Real, tex, sliceFace, mip, sample, minval, maxval, channels, mem); histogram = null; if (success) histogram = (UInt32[])CustomMarshal.GetTemplatedArray(mem, typeof(UInt32), true); CustomMarshal.Free(mem); return success; } public byte[] GetBufferData(ResourceId buff, UInt64 offset, UInt64 len) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetBufferData(m_Real, buff, offset, len, mem); byte[] ret = null; if (success) ret = (byte[])CustomMarshal.GetTemplatedArray(mem, typeof(byte), true); CustomMarshal.Free(mem); return ret; } public byte[] GetTextureData(ResourceId tex, UInt32 arrayIdx, UInt32 mip) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = ReplayRenderer_GetTextureData(m_Real, tex, arrayIdx, mip, mem); byte[] ret = null; if (success) ret = (byte[])CustomMarshal.GetTemplatedArray(mem, typeof(byte), true); CustomMarshal.Free(mem); return ret; } }; public class RemoteRenderer { [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteRenderer_Shutdown(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool RemoteRenderer_LocalProxies(IntPtr real, IntPtr outlist); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool RemoteRenderer_RemoteSupportedReplays(IntPtr real, IntPtr outlist); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern ReplayCreateStatus RemoteRenderer_CreateProxyRenderer(IntPtr real, UInt32 proxyid, IntPtr logfile, ref float progress, ref IntPtr rendPtr); private IntPtr m_Real = IntPtr.Zero; public RemoteRenderer(IntPtr real) { m_Real = real; } public void Shutdown() { if (m_Real != IntPtr.Zero) { RemoteRenderer_Shutdown(m_Real); m_Real = IntPtr.Zero; } } public string[] LocalProxies() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = RemoteRenderer_LocalProxies(m_Real, mem); string[] ret = null; if (success) ret = CustomMarshal.TemplatedArrayToStringArray(mem, true); CustomMarshal.Free(mem); return ret; } public string[] RemoteSupportedReplays() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); bool success = RemoteRenderer_RemoteSupportedReplays(m_Real, mem); string[] ret = null; if (success) ret = CustomMarshal.TemplatedArrayToStringArray(mem, true); CustomMarshal.Free(mem); return ret; } public ReplayRenderer CreateProxyRenderer(int proxyid, string logfile, ref float progress) { IntPtr rendPtr = IntPtr.Zero; IntPtr logfile_mem = CustomMarshal.MakeUTF8String(logfile); ReplayCreateStatus ret = RemoteRenderer_CreateProxyRenderer(m_Real, (UInt32)proxyid, logfile_mem, ref progress, ref rendPtr); CustomMarshal.Free(logfile_mem); if (rendPtr == IntPtr.Zero || ret != ReplayCreateStatus.Success) { var e = new System.ApplicationException("Failed to set up local proxy replay with remote connection"); e.Data.Add("status", ret); throw e; } return new ReplayRenderer(rendPtr); } }; public class RemoteAccess { [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteAccess_Shutdown(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr RemoteAccess_GetTarget(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr RemoteAccess_GetAPI(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 RemoteAccess_GetPID(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr RemoteAccess_GetBusyClient(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteAccess_TriggerCapture(IntPtr real); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteAccess_QueueCapture(IntPtr real, UInt32 frameNumber); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteAccess_CopyCapture(IntPtr real, UInt32 remoteID, IntPtr localpath); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteAccess_ReceiveMessage(IntPtr real, IntPtr outmsg); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 RENDERDOC_EnumerateRemoteConnections(IntPtr host, UInt32[] idents); private IntPtr m_Real = IntPtr.Zero; private bool m_Connected; public RemoteAccess(IntPtr real) { m_Real = real; if (real == IntPtr.Zero) { m_Connected = false; Target = ""; API = ""; BusyClient = ""; } else { m_Connected = true; Target = CustomMarshal.PtrToStringUTF8(RemoteAccess_GetTarget(m_Real)); API = CustomMarshal.PtrToStringUTF8(RemoteAccess_GetAPI(m_Real)); PID = RemoteAccess_GetPID(m_Real); BusyClient = CustomMarshal.PtrToStringUTF8(RemoteAccess_GetBusyClient(m_Real)); } CaptureExists = false; CaptureCopied = false; InfoUpdated = false; } public static UInt32[] GetRemoteIdents(string host) { UInt32 numIdents = RENDERDOC_EnumerateRemoteConnections(IntPtr.Zero, null); UInt32[] idents = new UInt32[numIdents]; IntPtr host_mem = CustomMarshal.MakeUTF8String(host); RENDERDOC_EnumerateRemoteConnections(host_mem, idents); CustomMarshal.Free(host_mem); return idents; } public bool Connected { get { return m_Connected; } } public void Shutdown() { m_Connected = false; if (m_Real != IntPtr.Zero) RemoteAccess_Shutdown(m_Real); m_Real = IntPtr.Zero; } public void TriggerCapture() { RemoteAccess_TriggerCapture(m_Real); } public void QueueCapture(UInt32 frameNum) { RemoteAccess_QueueCapture(m_Real, frameNum); } public void CopyCapture(UInt32 id, string localpath) { IntPtr localpath_mem = CustomMarshal.MakeUTF8String(localpath); RemoteAccess_CopyCapture(m_Real, id, localpath_mem); CustomMarshal.Free(localpath_mem); } public void ReceiveMessage() { if (m_Real != IntPtr.Zero) { RemoteMessage msg = null; { IntPtr mem = CustomMarshal.Alloc(typeof(RemoteMessage)); RemoteAccess_ReceiveMessage(m_Real, mem); if (mem != IntPtr.Zero) msg = (RemoteMessage)CustomMarshal.PtrToStructure(mem, typeof(RemoteMessage), true); CustomMarshal.Free(mem); } if (msg.Type == RemoteMessageType.Disconnected) { m_Connected = false; RemoteAccess_Shutdown(m_Real); m_Real = IntPtr.Zero; } else if (msg.Type == RemoteMessageType.NewCapture) { CaptureFile = msg.NewCapture; CaptureExists = true; } else if (msg.Type == RemoteMessageType.CaptureCopied) { CaptureFile.ID = msg.NewCapture.ID; CaptureFile.localpath = msg.NewCapture.localpath; CaptureCopied = true; } else if (msg.Type == RemoteMessageType.RegisterAPI) { API = msg.RegisterAPI.APIName; InfoUpdated = true; } else if (msg.Type == RemoteMessageType.NewChild) { NewChild = msg.NewChild; ChildAdded = true; } } } public string BusyClient; public string Target; public string API; public UInt32 PID; public bool CaptureExists; public bool ChildAdded; public bool CaptureCopied; public bool InfoUpdated; public RemoteMessage.NewCaptureData CaptureFile = new RemoteMessage.NewCaptureData(); public RemoteMessage.NewChildData NewChild = new RemoteMessage.NewChildData(); }; };