private unsafe IntPtr PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { var swapChain = new SwapChain(swapChainPtr); var device = swapChain.GetDevice <Device>(); if (!_initialized) { _windowHandle = swapChain.Description.OutputHandle; ImGui.ImGuiImplDX11Init((void *)device.NativePointer, (void *)device.ImmediateContext.NativePointer); var backBuffer = swapChain.GetBackBuffer <Texture2D>(0); _renderTargetView = new RenderTargetView(device, backBuffer); _initialized = true; backBuffer.Dispose(); } ImGui.ImGuiImplDX11NewFrame(); ImguiHook.NewFrame(); device.ImmediateContext.OutputMerger.SetRenderTargets(_renderTargetView); ImGui.ImGuiImplDX11RenderDrawData(ImGui.GetDrawData()); swapChain.Dispose(); device.Dispose(); return(_presentHook.OriginalFunction(swapChainPtr, syncInterval, flags)); }
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="presentFlags"></param> /// <returns>The HRESULT of the original method</returns> private Int32 PresentHook(IntPtr swapChainPtr, Int32 syncInterval, PresentFlags presentFlags) { this.Frame(); SwapChain swapChain = (SwapChain)swapChainPtr; try { if (this.SwapChainPointer != swapChain.NativePointer || this.OverlayEngine == null) { // Draw FPS //// if (this.OverlayEngine != null) //// { //// this.OverlayEngine.Dispose(); //// } this.OverlayEngine = new DXOverlayEngine(); this.OverlayEngine.Initialize(swapChain); this.SwapChainPointer = swapChain.NativePointer; } else if (this.OverlayEngine != null) { // Draw Overlay(s) this.OverlayEngine.Draw(); } } catch { } // As always we need to call the original method, note that EasyHook will automatically skip the hook and call the original method // i.e. calling it here will not cause a stack overflow into this function return(this.DXGISwapChainPresentHook.Original(swapChainPtr, syncInterval, presentFlags)); }
public void Present() { Stopwatch sw = Stopwatch.StartNew(); try { PresentFlags flags = this.FInDNW[0] ? (PresentFlags)8 : PresentFlags.None; if (this.FInVsync[0]) { this.FOutBackBuffer[0][this.RenderContext].Present(1, flags); } else { this.FOutBackBuffer[0][this.RenderContext].Present(0, flags); } } catch { } sw.Stop(); this.FOutPresent[0] = sw.Elapsed.TotalMilliseconds; this.FResized = false; }
public override void Render(int syncInterval, PresentFlags presentFlags) { base.Render(syncInterval, presentFlags); if (!_mcWindow.IsDisposed) { _mcWindow.Render(syncInterval, presentFlags); } }
private int presentHandler(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { if (OnRender != null) { OnRender(); } return(originalFunc(swapChainPtr, syncInterval, flags)); }
public void Present(int syncInterval, PresentFlags flags) { try { this.swapchain.Present(syncInterval, flags); } catch { } }
public SharpDX.Result PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { if (!init) { swapChain = SwapChain3.FromPointer <SwapChain3>(swapChainPtr); device = swapChain.GetDevice <D3D12.Device>(); init = true; } return(swapChain.Present(syncInterval, flags)); }
public void InitDefaults() { AutoDepthStencilFormat = Format.D24X8; BackBufferWidth = 800; BackBufferHeight = 600; BackBufferFormat = Format.X8R8G8B8; BackBufferCount = 1; DeviceWindowHandle = IntPtr.Zero; EnableAutoDepthStencil = true; PresentFlags = PresentFlags.None; PresentationInterval = PresentInterval.Immediate; SwapEffect = SwapEffect.Discard; Windowed = true; }
private unsafe IntPtr PresentImpl(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { if (_presentRecursionLock) { Debug.WriteLine($"[DX11 Present] Discarding via Recursion Lock"); return(_presentHook.OriginalFunction.Value.Invoke(swapChainPtr, syncInterval, flags)); } _presentRecursionLock = true; try { var swapChain = new SwapChain(swapChainPtr); var windowHandle = swapChain.Description.OutputHandle; // Ignore windows which don't belong to us. if (!ImguiHook.CheckWindowHandle(windowHandle)) { Debug.WriteLine($"[DX11 Present] Discarding Window Handle {windowHandle} due to Mismatch"); return(_presentHook.OriginalFunction.Value.Invoke(swapChainPtr, syncInterval, flags)); } // Initialise using var device = swapChain.GetDevice <Device>(); if (!_initialized) { Debug.WriteLine($"[DX11 Present] Init DX11, Window Handle: {windowHandle:X}"); ImguiHook.InitializeWithHandle(windowHandle); ImGui.ImGuiImplDX11Init((void *)device.NativePointer, (void *)device.ImmediateContext.NativePointer); using var backBuffer = swapChain.GetBackBuffer <Texture2D>(0); _renderTargetView = new RenderTargetView(device, backBuffer); _initialized = true; } ImGui.ImGuiImplDX11NewFrame(); ImguiHook.NewFrame(); device.ImmediateContext.OutputMerger.SetRenderTargets(_renderTargetView); using var drawData = ImGui.GetDrawData(); ImGui.ImGuiImplDX11RenderDrawData(drawData); return(_presentHook.OriginalFunction.Value.Invoke(swapChainPtr, syncInterval, flags)); } finally { _presentRecursionLock = false; } }
/// <summary> /// Initializes a new instance of the <see cref="PresentParameters"/> struct. /// </summary> /// <param name="backBufferWidth">Width of the back buffer.</param> /// <param name="backBufferHeight">Height of the back buffer.</param> /// <param name="backBufferFormat">The back buffer format.</param> /// <param name="backBufferCount">The back buffer count.</param> /// <param name="multiSampleType">Type of the multi sample.</param> /// <param name="multiSampleQuality">The multi sample quality.</param> /// <param name="swapEffect">The swap effect.</param> /// <param name="deviceWindowHandle">The device window handle.</param> /// <param name="windowed">if set to <c>true</c> [windowed].</param> /// <param name="enableAutoDepthStencil">if set to <c>true</c> [enable auto depth stencil].</param> /// <param name="autoDepthStencilFormat">The auto depth stencil format.</param> /// <param name="presentFlags">The present flags.</param> /// <param name="fullScreenRefreshRateInHz">The full screen refresh rate in hz.</param> /// <param name="presentationInterval">The presentation interval.</param> public PresentParameters(int backBufferWidth, int backBufferHeight, Format backBufferFormat, int backBufferCount, MultisampleType multiSampleType, int multiSampleQuality, SwapEffect swapEffect, IntPtr deviceWindowHandle, bool windowed, bool enableAutoDepthStencil, Format autoDepthStencilFormat, PresentFlags presentFlags, int fullScreenRefreshRateInHz, PresentInterval presentationInterval) { BackBufferWidth = backBufferWidth; BackBufferHeight = backBufferHeight; BackBufferFormat = backBufferFormat; BackBufferCount = backBufferCount; MultiSampleType = multiSampleType; MultiSampleQuality = multiSampleQuality; SwapEffect = swapEffect; DeviceWindowHandle = deviceWindowHandle; Windowed = windowed; EnableAutoDepthStencil = enableAutoDepthStencil; AutoDepthStencilFormat = autoDepthStencilFormat; PresentFlags = presentFlags; FullScreenRefreshRateInHz = fullScreenRefreshRateInHz; PresentationInterval = presentationInterval; }
/// <summary> /// Initializes a new instance of the <see cref="PresentParameters"/> struct. /// </summary> /// <param name="backBufferWidth">Width of the back buffer.</param> /// <param name="backBufferHeight">Height of the back buffer.</param> /// <param name="backBufferFormat">The back buffer format.</param> /// <param name="backBufferCount">The back buffer count.</param> /// <param name="multiSampleType">Type of the multi sample.</param> /// <param name="multiSampleQuality">The multi sample quality.</param> /// <param name="swapEffect">The swap effect.</param> /// <param name="deviceWindowHandle">The device window handle.</param> /// <param name="windowed">if set to <c>true</c> [windowed].</param> /// <param name="enableAutoDepthStencil">if set to <c>true</c> [enable auto depth stencil].</param> /// <param name="autoDepthStencilFormat">The auto depth stencil format.</param> /// <param name="presentFlags">The present flags.</param> /// <param name="fullScreenRefreshRateInHz">The full screen refresh rate in Hz.</param> /// <param name="presentationInterval">The presentation interval.</param> public PresentParameters(int backBufferWidth, int backBufferHeight, Format backBufferFormat, int backBufferCount, MultisampleType multiSampleType, int multiSampleQuality, SwapEffect swapEffect, IntPtr deviceWindowHandle, bool windowed, bool enableAutoDepthStencil, Format autoDepthStencilFormat, PresentFlags presentFlags, int fullScreenRefreshRateInHz, PresentInterval presentationInterval) { BackBufferWidth = backBufferWidth; BackBufferHeight = backBufferHeight; BackBufferFormat = backBufferFormat; BackBufferCount = backBufferCount; MultiSampleType = multiSampleType; MultiSampleQuality = multiSampleQuality; SwapEffect = swapEffect; DeviceWindowHandle = deviceWindowHandle; Windowed = windowed; EnableAutoDepthStencil = enableAutoDepthStencil; AutoDepthStencilFormat = autoDepthStencilFormat; PresentFlags = presentFlags; FullScreenRefreshRateInHz = fullScreenRefreshRateInHz; PresentationInterval = presentationInterval; }
public virtual void Render(int syncInterval, PresentFlags presentFlags) { if (WindowState == FormWindowState.Minimized) { Thread.Sleep(1); return; } if (!XResource.DeviceAvailable) { InitializeResources(); } float lastFrameTimeInSecond = RenderTimer.BeginFrame(); RenderCore(syncInterval, presentFlags, lastFrameTimeInSecond); RenderTimer.EndFrame(); }
public void Present(int syncInterval, PresentFlags flags) { try { this.swapchain.Present(syncInterval, flags); } catch (SharpDXException exception) { if (exception.ResultCode == SharpDX.DXGI.ResultCode.DeviceRemoved || exception.ResultCode == SharpDX.DXGI.ResultCode.DeviceReset) { this.device.NotifyDeviceLost(); } else { throw; } } }
/// <summary> /// [This documentation is preliminary and is subject to change.] /// </summary> /// <param name="syncInterval"><para>An integer that specifies how to synchronize presentation of a frame with the vertical blank.</para> <para>For the bit-block transfer (bitblt) model, values are:</para> 0 - The presentation occurs immediately, there is no synchronization. 1,2,3,4 - Synchronize presentation after the nth vertical blank. <para>For the flip model, values are:</para> 0 - Discard this frame if you submitted a more recent presentation. n > 0 - Synchronize presentation for at least n vertical blanks. <para>For an example that shows how sync-interval values affect a flip presentation queue, see Remarks.</para> <para>If the update region straddles more than one output (each represented by <see cref="SharpDX.DXGI.Output1"/>), Present1 performs the synchronization to the output that contains the largest subrectangle of the target window's client area.</para></param> /// <param name="presentFlags"><para>An integer value that contains swap-chain presentation options. These options are defined by the DXGI_PRESENT constants.</para></param> /// <param name="presentParametersRef"><para>A reference to a <see cref="SharpDX.DXGI.PresentParameters"/> structure that describes updated rectangles and scroll information of the frame to present.</para></param> /// <returns>Possible return values include: <see cref="SharpDX.Result.Ok"/>, <see cref="SharpDX.DXGI.ResultCode.DeviceRemoved"/> , <see cref="SharpDX.DXGI.DXGIStatus.Occluded"/>, <see cref="SharpDX.DXGI.ResultCode.InvalidCall"/>, or E_OUTOFMEMORY.</returns> /// <remarks> /// An application can use Present1 to optimize presentation by specifying scroll and dirty rectangles. When the runtime has information about these rectangles, the runtime can then perform necessary bitblts during presentation more efficiently and pass this metadata to the Desktop Window Manager (DWM). The DWM can then use the metadata to optimize presentation and pass the metadata to indirect displays and terminal servers to optimize traffic over the wire. An application must confine its modifications to only the dirty regions that it passes to Present1, as well as modify the entire dirty region to avoid undefined resource contents from being exposed.For flip presentation model swap chains that you create with the <see cref="SharpDX.DXGI.SwapEffect.FlipSequential"/> value set, a successful presentation results in an unbind of back buffer 0 from the graphics pipeline, except for when you pass the <see cref="SharpDX.DXGI.PresentFlags.DoNotSequence"/> flag in the Flags parameter.Flip presentation model queueSuppose the following frames with sync-interval values are queued from oldest (A) to newest (E) before you call Present1.A: 3, B: 0, C: 0, D: 1, E: 0When you call Present1, the runtime shows frame A for 3 vertical blank intervals, then frame D for 1 vertical blank interval, and then frame E until you submit a new presentation. The runtime discards frames C and D. /// </remarks> /// <include file='.\..\Documentation\CodeComments.xml' path="/comments/comment[@id='IDXGISwapChain1::Present1']/*"/> /// <unmanaged>HRESULT IDXGISwapChain1::Present1([In] unsigned int SyncInterval,[In] unsigned int PresentFlags,[In] const void* pPresentParameters)</unmanaged> public unsafe void Present(int syncInterval, PresentFlags presentFlags, PresentParameters presentParameters) { bool hasScrollRectangle = presentParameters.ScrollRectangle.HasValue; bool hasScrollOffset = presentParameters.ScrollOffset.HasValue; var scrollRectangle = hasScrollRectangle ? presentParameters.ScrollRectangle.Value : Rectangle.Empty; var scrollOffset = hasScrollOffset? presentParameters.ScrollOffset.Value : default(Point); fixed (void* pDirtyRects = presentParameters.DirtyRectangles) { var native = default(PresentParameters.__Native); native.DirtyRectsCount = presentParameters.DirtyRectangles != null ? presentParameters.DirtyRectangles.Length : 0; native.PDirtyRects = (IntPtr)pDirtyRects; native.PScrollRect = hasScrollRectangle ? new IntPtr(&scrollRectangle) : IntPtr.Zero; native.PScrollOffset = hasScrollOffset ? new IntPtr(&scrollOffset) : IntPtr.Zero; Present1(syncInterval, presentFlags, new IntPtr(&native)); } }
/// <summary> /// [This documentation is preliminary and is subject to change.] /// </summary> /// <param name="syncInterval"><para>An integer that specifies how to synchronize presentation of a frame with the vertical blank.</para> <para>For the bit-block transfer (bitblt) model, values are:</para> 0 - The presentation occurs immediately, there is no synchronization. 1,2,3,4 - Synchronize presentation after the nth vertical blank. <para>For the flip model, values are:</para> 0 - Discard this frame if you submitted a more recent presentation. n > 0 - Synchronize presentation for at least n vertical blanks. <para>For an example that shows how sync-interval values affect a flip presentation queue, see Remarks.</para> <para>If the update region straddles more than one output (each represented by <see cref="SharpDX.DXGI.Output1"/>), Present1 performs the synchronization to the output that contains the largest subrectangle of the target window's client area.</para></param> /// <param name="presentFlags"><para>An integer value that contains swap-chain presentation options. These options are defined by the DXGI_PRESENT constants.</para></param> /// <param name="presentParameters"><para>A reference to a <see cref="SharpDX.DXGI.PresentParameters"/> structure that describes updated rectangles and scroll information of the frame to present.</para></param> /// <returns>Possible return values include: <see cref="SharpDX.Result.Ok"/>, <see cref="SharpDX.DXGI.ResultCode.DeviceRemoved"/> , <see cref="SharpDX.DXGI.DXGIStatus.Occluded"/>, <see cref="SharpDX.DXGI.ResultCode.InvalidCall"/>, or E_OUTOFMEMORY.</returns> /// <remarks> /// An application can use Present1 to optimize presentation by specifying scroll and dirty rectangles. When the runtime has information about these rectangles, the runtime can then perform necessary bitblts during presentation more efficiently and pass this metadata to the Desktop Window Manager (DWM). The DWM can then use the metadata to optimize presentation and pass the metadata to indirect displays and terminal servers to optimize traffic over the wire. An application must confine its modifications to only the dirty regions that it passes to Present1, as well as modify the entire dirty region to avoid undefined resource contents from being exposed.For flip presentation model swap chains that you create with the <see cref="SharpDX.DXGI.SwapEffect.FlipSequential"/> value set, a successful presentation results in an unbind of back buffer 0 from the graphics pipeline, except for when you pass the <see cref="SharpDX.DXGI.PresentFlags.DoNotSequence"/> flag in the Flags parameter.Flip presentation model queueSuppose the following frames with sync-interval values are queued from oldest (A) to newest (E) before you call Present1.A: 3, B: 0, C: 0, D: 1, E: 0When you call Present1, the runtime shows frame A for 3 vertical blank intervals, then frame D for 1 vertical blank interval, and then frame E until you submit a new presentation. The runtime discards frames C and D. /// </remarks> /// <include file='.\..\Documentation\CodeComments.xml' path="/comments/comment[@id='IDXGISwapChain1::Present1']/*"/> /// <unmanaged>HRESULT IDXGISwapChain1::Present1([In] unsigned int SyncInterval,[In] unsigned int PresentFlags,[In] const void* pPresentParameters)</unmanaged> public unsafe void Present(int syncInterval, PresentFlags presentFlags, PresentParameters presentParameters) { bool hasScrollRectangle = presentParameters.ScrollRectangle.HasValue; bool hasScrollOffset = presentParameters.ScrollOffset.HasValue; var scrollRectangle = hasScrollRectangle ? presentParameters.ScrollRectangle.Value : Rectangle.Empty; var scrollOffset = hasScrollOffset ? presentParameters.ScrollOffset.Value : default(Point); fixed(void *pDirtyRects = presentParameters.DirtyRectangles) { var native = default(PresentParameters.__Native); native.DirtyRectsCount = presentParameters.DirtyRectangles != null ? presentParameters.DirtyRectangles.Length : 0; native.PDirtyRects = (IntPtr)pDirtyRects; native.PScrollRect = hasScrollRectangle ? new IntPtr(&scrollRectangle) : IntPtr.Zero; native.PScrollOffset = hasScrollOffset ? new IntPtr(&scrollOffset) : IntPtr.Zero; Present1(syncInterval, presentFlags, new IntPtr(&native)); } }
private void RenderCore(int syncInterval, PresentFlags presentFlags, float lastFrameTimeInSecond) { try { // Freeze logic when render time is slow if (lastFrameTimeInSecond < 0.2f) { XResource.UpdateLogic(RenderTimer.DurationSinceLastFrame); OnUpdateLogic(lastFrameTimeInSecond); } XResource.RenderTarget.BeginDraw(); { OnDraw(XResource.RenderTarget); OnPostDraw(); } XResource.RenderTarget.EndDraw(); XResource.SwapChain.Present(syncInterval, presentFlags); } catch (SharpGenException e) { unchecked { const int DeviceRemoved = (int)0x887a0005; const int DeviceReset = (int)0x887A0007; if (e.ResultCode == DeviceRemoved || e.ResultCode == DeviceReset) { OnReleaseDeviceSizeResources(); OnReleaseDeviceResources(); XResource.ReleaseDeviceResources(); } else { throw; } } } }
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { SwapChain swapChain = (SharpDX.DXGI.SwapChain)swapChainPtr; try { #region Draw overlay using (Texture2D texture = Texture2D.FromSwapChain <SharpDX.Direct3D10.Texture2D>(swapChain, 0)) { } #endregion } catch (Exception e) { // If there is an error we do not want to crash the hooked application, so swallow the exception this.DebugMessage("PresentHook: Exeception: " + e.GetType().FullName + ": " + e.Message); } // As always we need to call the original method, note that EasyHook has already repatched the original method // so calling it here will not cause an endless recursion to this function swapChain.Present(syncInterval, flags); return(SharpDX.Result.Ok.Code); }
private int Callback(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { RaiseEvent(); return((int)_presentHook.CallOriginal(swapChainPtr, syncInterval, flags)); }
public void Present(int syncInterval = 0, PresentFlags presentFlags = PresentFlags.None) { _swapChain.Present(syncInterval, presentFlags); }
protected unsafe DXGISwapchain( GraphicsDevice device, PresentationParameters presentationParameters, ComObject deviceOrCommandQueue, int bufferCount, int frameCount) : base(device) { _frameCount = frameCount; var width = Math.Max(presentationParameters.BackBufferWidth, 1); var height = Math.Max(presentationParameters.BackBufferHeight, 1); switch (presentationParameters.DeviceWindowHandle) { case IntPtr hwnd: { using (var dxgiDevice = deviceOrCommandQueue.QueryInterface <SharpDX.DXGI.Device>()) { using (var dxgiFactory = dxgiDevice.Adapter.GetParent <Factory2>()) { // Check tearing support. RawBool allowTearing = false; using (var factory5 = dxgiFactory.QueryInterfaceOrNull <DXGI.Factory5>()) { factory5.CheckFeatureSupport(DXGI.Feature.PresentAllowTearing, new IntPtr(&allowTearing), sizeof(RawBool) ); // Recommended to always use tearing if supported when using a sync interval of 0. _syncInterval = 0; _presentFlags |= DXGI.PresentFlags.AllowTearing; } var swapchainDesc = new SharpDX.DXGI.SwapChainDescription1() { Width = width, Height = height, Format = Format.B8G8R8A8_UNorm, Stereo = false, SampleDescription = new DXGI.SampleDescription(1, 0), Usage = DXGI.Usage.RenderTargetOutput, BufferCount = bufferCount, Scaling = Scaling.Stretch, SwapEffect = allowTearing ? SwapEffect.FlipDiscard : DXGI.SwapEffect.Discard, AlphaMode = AlphaMode.Ignore, Flags = allowTearing ? SwapChainFlags.AllowTearing : DXGI.SwapChainFlags.None, }; var fullscreenDescription = new DXGI.SwapChainFullScreenDescription { Windowed = true }; _swapChain = new DXGI.SwapChain1(dxgiFactory, deviceOrCommandQueue, hwnd, ref swapchainDesc, fullscreenDescription); dxgiFactory.MakeWindowAssociation(hwnd, DXGI.WindowAssociationFlags.IgnoreAll); } } } break; //case CoreWindow coreWindowHandle: // { // var coreWindow = coreWindowHandle.CoreWindow; // var swapchainDesc = new DXGI.SwapChainDescription1() // { // Width = width, // Height = height, // Format = DXGI.Format.B8G8R8A8_UNorm, // Stereo = false, // SampleDescription = new DXGI.SampleDescription(1, 0), // Usage = DXGI.Usage.RenderTargetOutput, // BufferCount = FrameCount, // Scaling = DXGI.Scaling.AspectRatioStretch, // SwapEffect = DXGI.SwapEffect.FlipDiscard, // AlphaMode = DXGI.AlphaMode.Ignore, // Flags = DXGI.SwapChainFlags.None, // }; // using (var comCoreWindow = new ComObject(coreWindow)) // { // _swapChain = new DXGI.SwapChain1( // factory, // device.D3DDevice, // comCoreWindow, // ref swapchainDesc); // } // } // break; } }
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling /// (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> private int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { Frame(); var swapChain = (SwapChain) swapChainPtr; try { #region Screenshot Request if (Request != null) { DebugMessage("PresentHook: Request Start"); var startTime = DateTime.Now; using (var currentRT = SharpDX.Direct3D11.Resource.FromSwapChain<Texture2D>(swapChain, 0)) { #region Determine region to capture var captureRegion = new Rectangle(0, 0, currentRT.Description.Width, currentRT.Description.Height); if (Request.RegionToCapture.Width > 0) { captureRegion = new Rectangle(Request.RegionToCapture.Left, Request.RegionToCapture.Top, Request.RegionToCapture.Right, Request.RegionToCapture.Bottom); } else if (Request.Resize.HasValue) { captureRegion = new Rectangle(0, 0, Request.Resize.Value.Width, Request.Resize.Value.Height); } #endregion // Create / Recreate resources as necessary EnsureResources(currentRT.Device, currentRT.Description, captureRegion, Request); Texture2D sourceTexture = null; // If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture if (currentRT.Description.SampleDescription.Count > 1 || Request.Resize.HasValue) { if (Request.Resize.HasValue) DebugMessage("PresentHook: resizing texture"); else DebugMessage("PresentHook: resolving multi-sampled texture"); // Resolve into _resolvedRT if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Acquire(0, int.MaxValue); currentRT.Device.ImmediateContext.ResolveSubresource(currentRT, 0, _resolvedRT, 0, _resolvedRT.Description.Format); if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Release(1); if (Request.Resize.HasValue) { lock (_lock) { if (_resolvedRTKeyedMutex_Dev2 != null) _resolvedRTKeyedMutex_Dev2.Acquire(1, int.MaxValue); _saQuad.ShaderResource = _resolvedSharedSRV; _saQuad.RenderTargetView = _resizedRTV; _saQuad.RenderTarget = _resizedRT; _saQuad.Render(); if (_resolvedRTKeyedMutex_Dev2 != null) _resolvedRTKeyedMutex_Dev2.Release(0); } // set sourceTexture to the resized RT sourceTexture = _resizedRT; } else { // Make sourceTexture be the resolved texture sourceTexture = _resolvedRTShared; } } else { // Copy the resource into the shared texture if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Acquire(0, int.MaxValue); currentRT.Device.ImmediateContext.CopySubresourceRegion(currentRT, 0, null, _resolvedRT, 0); if (_resolvedRTKeyedMutex != null) _resolvedRTKeyedMutex.Release(1); sourceTexture = _resolvedRTShared; } // Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline _requestCopy = Request.Clone(); // this.Request gets set to null, so copy the Request for use in the thread // Prevent the request from being processed a second time Request = null; var acquireLock = sourceTexture == _resolvedRTShared; ThreadPool.QueueUserWorkItem(o => { // Acquire lock on second device if (acquireLock && _resolvedRTKeyedMutex_Dev2 != null) _resolvedRTKeyedMutex_Dev2.Acquire(1, int.MaxValue); lock (_lock) { // Copy the subresource region, we are dealing with a flat 2D texture with no MipMapping, so 0 is the subresource index sourceTexture.Device.ImmediateContext.CopySubresourceRegion(sourceTexture, 0, new ResourceRegion { Top = captureRegion.Top, Bottom = captureRegion.Bottom, Left = captureRegion.Left, Right = captureRegion.Right, Front = 0, Back = 1 // Must be 1 or only black will be copied }, _finalRT, 0, 0, 0, 0); // Release lock upon shared surface on second device if (acquireLock && _resolvedRTKeyedMutex_Dev2 != null) _resolvedRTKeyedMutex_Dev2.Release(0); _finalRT.Device.ImmediateContext.End(_query); _queryIssued = true; while (!_finalRT.Device.ImmediateContext.GetData(_query).ReadBoolean()) { // Spin (usually no spin takes place) } var startCopyToSystemMemory = DateTime.Now; try { var db = default(DataBox); if (_requestCopy.Format == ImageFormat.PixelData) { db = _finalRT.Device.ImmediateContext.MapSubresource(_finalRT, 0, MapMode.Read, MapFlags.DoNotWait); _finalRTMapped = true; } _queryIssued = false; try { using (var ms = new MemoryStream()) { switch (_requestCopy.Format) { case ImageFormat.Bitmap: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Bmp, ms); break; case ImageFormat.Jpeg: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Jpg, ms); break; case ImageFormat.Png: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Png, ms); break; case ImageFormat.PixelData: if (db.DataPointer != IntPtr.Zero) { ProcessCapture(_finalRT.Description.Width, _finalRT.Description.Height, db.RowPitch, PixelFormat.Format32bppArgb, db.DataPointer, _requestCopy); } return; } ms.Position = 0; ProcessCapture(ms, _requestCopy); } } finally { DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory).ToString()); } if (_finalRTMapped) { lock (_lock) { _finalRT.Device.ImmediateContext.UnmapSubresource(_finalRT, 0); _finalRTMapped = false; } } } catch (SharpDXException exc) { // Catch DXGI_ERROR_WAS_STILL_DRAWING and ignore - the data isn't available yet } } }); // Note: it would be possible to capture multiple frames and process them in a background thread } DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime)); DebugMessage("PresentHook: Request End"); } #endregion #region Draw overlay (after screenshot so we don't capture overlay as well) if (Config.ShowOverlay) { // Initialise Overlay Engine if (_swapChainPointer != swapChain.NativePointer || _overlayEngine == null || IsOverlayUpdatePending) { if (_overlayEngine != null) _overlayEngine.Dispose(); _overlayEngine = new DXOverlayEngine(); _overlayEngine.Overlays.Add(new Overlay { Elements = OverlayElements }); _overlayEngine.Initialise(swapChain); _swapChainPointer = swapChain.NativePointer; } // Draw Overlay(s) else if (_overlayEngine != null) { foreach (var overlay in _overlayEngine.Overlays) overlay.Frame(); _overlayEngine.Draw(); } } #endregion } catch (Exception e) { // If there is an error we do not want to crash the hooked application, so swallow the exception DebugMessage("PresentHook: Exeception: " + e.GetType().FullName + ": " + e); //return unchecked((int)0x8000FFFF); //E_UNEXPECTED } // As always we need to call the original method, note that EasyHook will automatically skip the hook and call the original method // i.e. calling it here will not cause a stack overflow into this function return DXGISwapChain_PresentHook.Original(swapChainPtr, syncInterval, flags); }
private int Callback(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { RaiseEvent(); return (int)_presentHook.CallOriginal(swapChainPtr, syncInterval, flags); }
private int MyPresent(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { return(presentHook.Origin(swapChainPtr, syncInterval, flags)); }
private int Present(IntPtr swapChainPtr, int syncInterval, PresentFlags dwFlags) { var swapChain = (SwapChain) swapChainPtr; try { if (RenderEngine == null) { RenderEngine = new Renderer(swapChainPtr, OverlayConfig); var baseFont = new Font("Arial", 16, FontStyle.Bold); var elements = new ConcurrentDictionary<Guid, IOverlayElement>(); elements.TryAdd(FramesPerSecondID, new FramesPerSecond(baseFont) { Location = new Point(10, 10), Color = Color.Lime, AntiAliased = true, Hidden = !OverlayConfig.ShowFPS }); RenderEngine.Overlays.Add(new Overlay { Elements = elements }); RenderEngine.Overlays.Add(new Overlay()); } else { foreach (var overlay in RenderEngine?.Overlays) { overlay.Frame(); } RenderEngine?.Render(); } } catch (Exception ex) { Log.Write("Failed present: {0}", ex.Message); } finally { swapChain.Present(syncInterval, dwFlags); } return Result.Ok.Code; }
protected unsafe SwapChainDXGI( GraphicsDevice device, SwapChainDescriptor descriptor, IDXGIFactory1 dxgiFactory, ComObject deviceOrCommandQueue, int bufferCount, int backBufferCount) : base(device, descriptor) { BackBufferCount = backBufferCount; var width = Math.Max(descriptor.Width, 1); var height = Math.Max(descriptor.Height, 1); switch (descriptor.Handle) { case Win32SwapChainHandle win32Handle: { // Check tearing support. var dxgiFactory5 = dxgiFactory.QueryInterfaceOrNull <IDXGIFactory5>(); var allowTearing = false; if (dxgiFactory5 != null) { if (dxgiFactory5.PresentAllowTearing) { // Recommended to always use tearing if supported when using a sync interval of 0. _syncInterval = 0; _presentFlags |= PresentFlags.AllowTearing; allowTearing = true; } dxgiFactory5.Dispose(); } var dxgiFactory2 = dxgiFactory.QueryInterfaceOrNull <IDXGIFactory2>(); if (dxgiFactory2 != null) { var swapchainDesc = new SwapChainDescription1() { Width = width, Height = height, Format = BackBufferFormat, Stereo = false, SampleDescription = new SampleDescription(1, 0), Usage = Vortice.DirectX.Usage.RenderTargetOutput, BufferCount = bufferCount, Scaling = Scaling.Stretch, SwapEffect = allowTearing ? SwapEffect.FlipDiscard : SwapEffect.Discard, AlphaMode = AlphaMode.Ignore, Flags = allowTearing ? SwapChainFlags.AllowTearing : SwapChainFlags.None, }; var fullscreenDescription = new SwapChainFullscreenDescription { Windowed = true }; _swapChain = dxgiFactory2.CreateSwapChainForHwnd( deviceOrCommandQueue, win32Handle.HWnd, swapchainDesc, fullscreenDescription); dxgiFactory2.Dispose(); } else { SwapChainDescription dxgiSCDesc = new SwapChainDescription { BufferCount = bufferCount, IsWindowed = true, BufferDescription = new ModeDescription(width, height, BackBufferFormat), OutputWindow = win32Handle.HWnd, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Vortice.DirectX.Usage.Backbuffer | Vortice.DirectX.Usage.RenderTargetOutput }; _swapChain = dxgiFactory.CreateSwapChain(deviceOrCommandQueue, dxgiSCDesc); } dxgiFactory.MakeWindowAssociation(win32Handle.HWnd, WindowAssociationFlags.IgnoreAll); } break; //case CoreWindow coreWindowHandle: // { // var coreWindow = coreWindowHandle.CoreWindow; // var swapchainDesc = new DXGI.SwapChainDescription1() // { // Width = width, // Height = height, // Format = DXGI.Format.B8G8R8A8_UNorm, // Stereo = false, // SampleDescription = new DXGI.SampleDescription(1, 0), // Usage = DXGI.Usage.RenderTargetOutput, // BufferCount = FrameCount, // Scaling = DXGI.Scaling.AspectRatioStretch, // SwapEffect = DXGI.SwapEffect.FlipDiscard, // AlphaMode = DXGI.AlphaMode.Ignore, // Flags = DXGI.SwapChainFlags.None, // }; // using (var comCoreWindow = new ComObject(coreWindow)) // { // _swapChain = new DXGI.SwapChain1( // factory, // device.D3DDevice, // comCoreWindow, // ref swapchainDesc); // } // } // break; } }
private static IntPtr PresentImplStatic(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) => Instance.PresentImpl(swapChainPtr, syncInterval, flags);
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling /// (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> private int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { Frame(); var swapChain = (SwapChain) swapChainPtr; { try { #region Screenshot Request if (Request != null) { try { DebugMessage("PresentHook: Request Start"); var startTime = DateTime.Now; using (var texture = Resource.FromSwapChain<Texture2D>(swapChain, 0)) { #region Determine region to capture var regionToCapture = new Rectangle(0, 0, texture.Description.Width, texture.Description.Height); if (Request.RegionToCapture.Width > 0) { regionToCapture = Request.RegionToCapture; } #endregion var theTexture = texture; // If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture Texture2D textureResolved = null; if (texture.Description.SampleDescription.Count > 1) { DebugMessage("PresentHook: resolving multi-sampled texture"); // texture is multi-sampled, lets resolve it down to single sample textureResolved = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, Format = texture.Description.Format, Height = texture.Description.Height, Usage = ResourceUsage.Default, Width = texture.Description.Width, ArraySize = 1, SampleDescription = new SampleDescription(1, 0), // Ensure single sample BindFlags = BindFlags.None, MipLevels = 1, OptionFlags = texture.Description.OptionFlags }); // Resolve into textureResolved texture.Device.ResolveSubresource(texture, 0, textureResolved, 0, texture.Description.Format); // Make "theTexture" be the resolved texture theTexture = textureResolved; } // Create destination texture var textureDest = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, // CpuAccessFlags.Write | CpuAccessFlags.Read, Format = Format.R8G8B8A8_UNorm, // Supports BMP/PNG Height = regionToCapture.Height, Usage = ResourceUsage.Default, // ResourceUsage.Staging, Width = regionToCapture.Width, ArraySize = 1, //texture.Description.ArraySize, SampleDescription = new SampleDescription(1, 0), // texture.Description.SampleDescription, BindFlags = BindFlags.None, MipLevels = 1, //texture.Description.MipLevels, OptionFlags = texture.Description.OptionFlags }); // Copy the subresource region, we are dealing with a flat 2D texture with no MipMapping, so 0 is the subresource index theTexture.Device.CopySubresourceRegion(theTexture, 0, new ResourceRegion { Top = regionToCapture.Top, Bottom = regionToCapture.Bottom, Left = regionToCapture.Left, Right = regionToCapture.Right, Front = 0, Back = 1 // Must be 1 or only black will be copied }, textureDest, 0, 0, 0, 0); // Note: it would be possible to capture multiple frames and process them in a background thread // Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline var request = Request.Clone(); // this.Request gets set to null, so copy the Request for use in the thread ThreadPool.QueueUserWorkItem(delegate { //FileStream fs = new FileStream(@"c:\temp\temp.bmp", FileMode.Create); //Texture2D.ToStream(testSubResourceCopy, ImageFileFormat.Bmp, fs); var startCopyToSystemMemory = DateTime.Now; using (var ms = new MemoryStream()) { Resource.ToStream(textureDest, ImageFileFormat.Bmp, ms); ms.Position = 0; this.DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory)); var startSendResponse = DateTime.Now; ProcessCapture(ms, request); this.DebugMessage("PresentHook: Send response time: " + (DateTime.Now - startSendResponse)); } // Free the textureDest as we no longer need it. textureDest.Dispose(); textureDest = null; this.DebugMessage("PresentHook: Full Capture time: " + (DateTime.Now - startTime)); }); // Make sure we free up the resolved texture if it was created if (textureResolved != null) { textureResolved.Dispose(); textureResolved = null; } } DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime)); DebugMessage("PresentHook: Request End"); } finally { // Prevent the request from being processed a second time Request = null; } } #endregion #region Example: Draw overlay (after screenshot so we don't capture overlay as well) if (Config.ShowOverlay) { using (var texture = Resource.FromSwapChain<Texture2D>(swapChain, 0)) { if (FPS.GetFPS() >= 1) { var fd = new FontDescription { Height = 16, FaceName = "Arial", Italic = false, Width = 0, MipLevels = 1, CharacterSet = FontCharacterSet.Default, OutputPrecision = FontPrecision.Default, Quality = FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Bold }; // TODO: do not create font every frame! using (var font = new Font(texture.Device, fd)) { DrawText(font, new Vector2(5, 5), string.Format("{0:N0} fps", FPS.GetFPS()), new Color4(Color.Red.ToColor3())); if (TextDisplay != null && TextDisplay.Display) { DrawText(font, new Vector2(5, 25), TextDisplay.Text, new Color4(Color.Red.ToColor3(), (Math.Abs(1.0f - TextDisplay.Remaining)))); } } } } } #endregion } catch (Exception e) { // If there is an error we do not want to crash the hooked application, so swallow the exception DebugMessage("PresentHook: Exeception: " + e.GetType().FullName + ": " + e.Message); } // As always we need to call the original method, note that EasyHook has already repatched the original method // so calling it here will not cause an endless recursion to this function swapChain.Present(syncInterval, flags); return Result.Ok.Code; } }
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling /// (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> private int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { Frame(); var swapChain = (SwapChain)swapChainPtr; try { #region Screenshot Request if (Request != null) { DebugMessage("PresentHook: Request Start"); var startTime = DateTime.Now; using (var currentRT = SharpDX.Direct3D11.Resource.FromSwapChain <Texture2D>(swapChain, 0)) { #region Determine region to capture var captureRegion = new Rectangle(0, 0, currentRT.Description.Width, currentRT.Description.Height); if (Request.RegionToCapture.Width > 0) { captureRegion = new Rectangle(Request.RegionToCapture.Left, Request.RegionToCapture.Top, Request.RegionToCapture.Right, Request.RegionToCapture.Bottom); } else if (Request.Resize.HasValue) { captureRegion = new Rectangle(0, 0, Request.Resize.Value.Width, Request.Resize.Value.Height); } #endregion // Create / Recreate resources as necessary EnsureResources(currentRT.Device, currentRT.Description, captureRegion, Request); Texture2D sourceTexture = null; // If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture if (currentRT.Description.SampleDescription.Count > 1 || Request.Resize.HasValue) { if (Request.Resize.HasValue) { DebugMessage("PresentHook: resizing texture"); } else { DebugMessage("PresentHook: resolving multi-sampled texture"); } // Resolve into _resolvedRT if (_resolvedRTKeyedMutex != null) { _resolvedRTKeyedMutex.Acquire(0, int.MaxValue); } currentRT.Device.ImmediateContext.ResolveSubresource(currentRT, 0, _resolvedRT, 0, _resolvedRT.Description.Format); if (_resolvedRTKeyedMutex != null) { _resolvedRTKeyedMutex.Release(1); } if (Request.Resize.HasValue) { lock (_lock) { if (_resolvedRTKeyedMutex_Dev2 != null) { _resolvedRTKeyedMutex_Dev2.Acquire(1, int.MaxValue); } _saQuad.ShaderResource = _resolvedSharedSRV; _saQuad.RenderTargetView = _resizedRTV; _saQuad.RenderTarget = _resizedRT; _saQuad.Render(); if (_resolvedRTKeyedMutex_Dev2 != null) { _resolvedRTKeyedMutex_Dev2.Release(0); } } // set sourceTexture to the resized RT sourceTexture = _resizedRT; } else { // Make sourceTexture be the resolved texture sourceTexture = _resolvedRTShared; } } else { // Copy the resource into the shared texture if (_resolvedRTKeyedMutex != null) { _resolvedRTKeyedMutex.Acquire(0, int.MaxValue); } currentRT.Device.ImmediateContext.CopySubresourceRegion(currentRT, 0, null, _resolvedRT, 0); if (_resolvedRTKeyedMutex != null) { _resolvedRTKeyedMutex.Release(1); } sourceTexture = _resolvedRTShared; } // Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline _requestCopy = Request.Clone(); // this.Request gets set to null, so copy the Request for use in the thread // Prevent the request from being processed a second time Request = null; var acquireLock = sourceTexture == _resolvedRTShared; ThreadPool.QueueUserWorkItem(o => { // Acquire lock on second device if (acquireLock && _resolvedRTKeyedMutex_Dev2 != null) { _resolvedRTKeyedMutex_Dev2.Acquire(1, int.MaxValue); } lock (_lock) { // Copy the subresource region, we are dealing with a flat 2D texture with no MipMapping, so 0 is the subresource index sourceTexture.Device.ImmediateContext.CopySubresourceRegion(sourceTexture, 0, new ResourceRegion { Top = captureRegion.Top, Bottom = captureRegion.Bottom, Left = captureRegion.Left, Right = captureRegion.Right, Front = 0, Back = 1 // Must be 1 or only black will be copied }, _finalRT, 0, 0, 0, 0); // Release lock upon shared surface on second device if (acquireLock && _resolvedRTKeyedMutex_Dev2 != null) { _resolvedRTKeyedMutex_Dev2.Release(0); } _finalRT.Device.ImmediateContext.End(_query); _queryIssued = true; while (!_finalRT.Device.ImmediateContext.GetData(_query).ReadBoolean()) { // Spin (usually no spin takes place) } var startCopyToSystemMemory = DateTime.Now; try { var db = default(DataBox); if (_requestCopy.Format == ImageFormat.PixelData) { db = _finalRT.Device.ImmediateContext.MapSubresource(_finalRT, 0, MapMode.Read, MapFlags.DoNotWait); _finalRTMapped = true; } _queryIssued = false; try { using (var ms = new MemoryStream()) { switch (_requestCopy.Format) { case ImageFormat.Bitmap: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Bmp, ms); break; case ImageFormat.Jpeg: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Jpg, ms); break; case ImageFormat.Png: SharpDX.Direct3D11.Resource.ToStream( _finalRT.Device.ImmediateContext, _finalRT, ImageFileFormat.Png, ms); break; case ImageFormat.PixelData: if (db.DataPointer != IntPtr.Zero) { ProcessCapture(_finalRT.Description.Width, _finalRT.Description.Height, db.RowPitch, PixelFormat.Format32bppArgb, db.DataPointer, _requestCopy); } return; } ms.Position = 0; ProcessCapture(ms, _requestCopy); } } finally { DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory).ToString()); } if (_finalRTMapped) { lock (_lock) { _finalRT.Device.ImmediateContext.UnmapSubresource(_finalRT, 0); _finalRTMapped = false; } } } catch (SharpDXException exc) { // Catch DXGI_ERROR_WAS_STILL_DRAWING and ignore - the data isn't available yet } } }); // Note: it would be possible to capture multiple frames and process them in a background thread } DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime)); DebugMessage("PresentHook: Request End"); } #endregion #region Draw overlay (after screenshot so we don't capture overlay as well) if (Config.ShowOverlay) { // Initialise Overlay Engine if (_swapChainPointer != swapChain.NativePointer || _overlayEngine == null || IsOverlayUpdatePending) { if (_overlayEngine != null) { _overlayEngine.Dispose(); } _overlayEngine = new DXOverlayEngine(); _overlayEngine.Overlays.Add(new Overlay { Elements = OverlayElements }); _overlayEngine.Initialise(swapChain); _swapChainPointer = swapChain.NativePointer; } // Draw Overlay(s) else if (_overlayEngine != null) { foreach (var overlay in _overlayEngine.Overlays) { overlay.Frame(); } _overlayEngine.Draw(); } } #endregion } catch (Exception e) { // If there is an error we do not want to crash the hooked application, so swallow the exception DebugMessage("PresentHook: Exeception: " + e.GetType().FullName + ": " + e); //return unchecked((int)0x8000FFFF); //E_UNEXPECTED } // As always we need to call the original method, note that EasyHook will automatically skip the hook and call the original method // i.e. calling it here will not cause a stack overflow into this function return(DXGISwapChain_PresentHook.Original(swapChainPtr, syncInterval, flags)); }
int Present(IntPtr swapChainPtr, int syncInterval, PresentFlags dwFlags) { SwapChain swapChain = (SwapChain)swapChainPtr; try { if (swapChainPtr != swapChain.NativePointer || _overlay == null) { if (_overlay != null) _overlay.Dispose(); _overlay = new Renderer(); _overlay.Init(swapChain); _swapChainPtr = swapChain.NativePointer; } else if (_overlay != null) { _overlay.Render(); } } catch(Exception ex) { Log.Write("Failed present: {0}", ex.Message); } swapChain.Present(syncInterval, dwFlags); return Result.Ok.Code; }
private int Present(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { SwapChain swapChain = (SharpDX.DXGI.SwapChain)swapChainPtr; swapChain.GetDevice(typeof(SharpDX.Direct3D11.Device).GUID, out IntPtr deviceOut); var device = new SharpDX.Direct3D11.Device(deviceOut); DeviceContext deviceContext = new DeviceContext(device); if (this.isFirst) { isFirst = false; this.srvFront = GetShaderResourceView(device, Brushes.Gold); this.srvback = GetShaderResourceView(device, Brushes.Red); var stencilDesc = new DepthStencilStateDescription() { DepthComparison = Comparison.Less, IsDepthEnabled = true, IsStencilEnabled = true, StencilReadMask = 0xFF, StencilWriteMask = 0xFF, FrontFace = new DepthStencilOperationDescription() { FailOperation = StencilOperation.Keep, DepthFailOperation = StencilOperation.Increment, PassOperation = StencilOperation.Keep, Comparison = Comparison.Always }, BackFace = new DepthStencilOperationDescription() { FailOperation = StencilOperation.Keep, DepthFailOperation = StencilOperation.Decrement, PassOperation = StencilOperation.Keep, Comparison = Comparison.Always } }; stencilDesc.IsDepthEnabled = false; stencilDesc.DepthWriteMask = DepthWriteMask.All; depthStencilStateDisabled = new DepthStencilState(deviceContext.Device, stencilDesc); stencilDesc.IsDepthEnabled = true; stencilDesc.DepthWriteMask = DepthWriteMask.All; stencilDesc.DepthComparison = Comparison.GreaterEqual; stencilDesc.IsStencilEnabled = false; stencilDesc.StencilReadMask = 0xFF; stencilDesc.StencilWriteMask = 0x0; stencilDesc.FrontFace.FailOperation = StencilOperation.Zero; stencilDesc.FrontFace.DepthFailOperation = StencilOperation.Zero; stencilDesc.FrontFace.PassOperation = StencilOperation.Keep; stencilDesc.FrontFace.Comparison = Comparison.Equal; stencilDesc.BackFace.FailOperation = StencilOperation.Zero; stencilDesc.BackFace.DepthFailOperation = StencilOperation.Zero; stencilDesc.BackFace.PassOperation = StencilOperation.Zero; stencilDesc.BackFace.Comparison = Comparison.Never; depthStencilStateReadonly = new DepthStencilState(deviceContext.Device, stencilDesc); } Dx11.DXFont dXFont = new Dx11.DXFont(device, deviceContext); dXFont.Initialize("宋体", 14, FontStyle.Bold, true); DXSprite dXSprite = new DXSprite(device, deviceContext); dXSprite.DrawString(50, 50, "ceshi", 255, 255, 233, 233, dXFont); swapChain.Present(syncInterval, flags); return(SharpDX.Result.Ok.Code); }
/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling /// (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> private int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { Frame(); var swapChain = (SwapChain)swapChainPtr; try { #region Screenshot Request if (Request != null) { try { DebugMessage("PresentHook: Request Start"); var startTime = DateTime.Now; using (var texture = Resource.FromSwapChain <Texture2D>(swapChain, 0)) { #region Determine region to capture var regionToCapture = new Rectangle(0, 0, texture.Description.Width, texture.Description.Height); if (Request.RegionToCapture.Width > 0) { regionToCapture = Request.RegionToCapture; } #endregion var theTexture = texture; // If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture Texture2D textureResolved = null; if (texture.Description.SampleDescription.Count > 1) { DebugMessage("PresentHook: resolving multi-sampled texture"); // texture is multi-sampled, lets resolve it down to single sample textureResolved = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, Format = texture.Description.Format, Height = texture.Description.Height, Usage = ResourceUsage.Default, Width = texture.Description.Width, ArraySize = 1, SampleDescription = new SampleDescription(1, 0), // Ensure single sample BindFlags = BindFlags.None, MipLevels = 1, OptionFlags = texture.Description.OptionFlags }); // Resolve into textureResolved texture.Device.ResolveSubresource(texture, 0, textureResolved, 0, texture.Description.Format); // Make "theTexture" be the resolved texture theTexture = textureResolved; } // Create destination texture var textureDest = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, // CpuAccessFlags.Write | CpuAccessFlags.Read, Format = Format.R8G8B8A8_UNorm, // Supports BMP/PNG Height = regionToCapture.Height, Usage = ResourceUsage.Default, // ResourceUsage.Staging, Width = regionToCapture.Width, ArraySize = 1, //texture.Description.ArraySize, SampleDescription = new SampleDescription(1, 0), // texture.Description.SampleDescription, BindFlags = BindFlags.None, MipLevels = 1, //texture.Description.MipLevels, OptionFlags = texture.Description.OptionFlags }); // Copy the subresource region, we are dealing with a flat 2D texture with no MipMapping, so 0 is the subresource index theTexture.Device.CopySubresourceRegion(theTexture, 0, new ResourceRegion { Top = regionToCapture.Top, Bottom = regionToCapture.Bottom, Left = regionToCapture.Left, Right = regionToCapture.Right, Front = 0, Back = 1 // Must be 1 or only black will be copied }, textureDest, 0, 0, 0, 0); // Note: it would be possible to capture multiple frames and process them in a background thread // Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline var request = Request.Clone(); // this.Request gets set to null, so copy the Request for use in the thread ThreadPool.QueueUserWorkItem(delegate { //FileStream fs = new FileStream(@"c:\temp\temp.bmp", FileMode.Create); //Texture2D.ToStream(testSubResourceCopy, ImageFileFormat.Bmp, fs); var startCopyToSystemMemory = DateTime.Now; using (var ms = new MemoryStream()) { Resource.ToStream(textureDest, ImageFileFormat.Bmp, ms); ms.Position = 0; this.DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory)); var startSendResponse = DateTime.Now; ProcessCapture(ms, request); this.DebugMessage("PresentHook: Send response time: " + (DateTime.Now - startSendResponse)); } // Free the textureDest as we no longer need it. textureDest.Dispose(); textureDest = null; this.DebugMessage("PresentHook: Full Capture time: " + (DateTime.Now - startTime)); }); // Make sure we free up the resolved texture if it was created if (textureResolved != null) { textureResolved.Dispose(); textureResolved = null; } } DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime)); DebugMessage("PresentHook: Request End"); } finally { // Prevent the request from being processed a second time Request = null; } } #endregion #region Example: Draw overlay (after screenshot so we don't capture overlay as well) if (Config.ShowOverlay) { using (var texture = Resource.FromSwapChain <Texture2D>(swapChain, 0)) { if (FPS.GetFPS() >= 1) { var fd = new FontDescription { Height = 16, FaceName = "Arial", Italic = false, Width = 0, MipLevels = 1, CharacterSet = FontCharacterSet.Default, OutputPrecision = FontPrecision.Default, Quality = FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Bold }; // TODO: Font should not be created every frame! using (var font = new Font(texture.Device, fd)) { DrawText(font, new Vector2(5, 5), string.Format("{0:N0} fps", FPS.GetFPS()), new Color4(Color.Red.ToColor3())); if (TextDisplay != null && TextDisplay.Display) { DrawText(font, new Vector2(5, 25), TextDisplay.Text, new Color4(Color.Red.ToColor3(), (Math.Abs(1.0f - TextDisplay.Remaining)))); } } } } } #endregion } catch (Exception e) { // If there is an error we do not want to crash the hooked application, so swallow the exception DebugMessage("PresentHook: Exeception: " + e.GetType().FullName + ": " + e.Message); } // As always we need to call the original method, note that EasyHook has already repatched the original method // so calling it here will not cause an endless recursion to this function swapChain.Present(syncInterval, flags); return(Result.Ok.Code); }
public void Present(int syncInterval, PresentFlags flags) { m_swapchain.Present(syncInterval, flags); }
public Result Present(int syncInterval, PresentFlags flags) { AssertUndisposed(); return _swapChain.Present(syncInterval, flags); }
public void Present(int syncInterval,PresentFlags flags) { this.swapchain.Present(syncInterval,flags); }