protected void Blit(D3D9.Device d3d9Device, HardwarePixelBuffer rsrc, BasicBox srcBox, BasicBox dstBox, BufferResources srcBufferResources, BufferResources dstBufferResources) { if (dstBufferResources.Surface != null && srcBufferResources.Surface != null) { // Surface-to-surface var dsrcRect = ToD3DRectangle(srcBox); var ddestRect = ToD3DRectangle(dstBox); var srcDesc = srcBufferResources.Surface.Description; // If we're blitting from a RTT, try GetRenderTargetData // if we're going to try to use GetRenderTargetData, need to use system mem pool // romeoxbm: not used even in Ogre //var tryGetRenderTargetData = false; if ((srcDesc.Usage & D3D9.Usage.RenderTarget) != 0 && srcDesc.MultiSampleType == D3D9.MultisampleType.None) { // Temp texture var tmptex = new D3D9.Texture(d3d9Device, srcDesc.Width, srcDesc.Height, 1, // 1 mip level ie topmost, generate no mipmaps 0, srcDesc.Format, D3D9.Pool.SystemMemory); var tmpsurface = tmptex.GetSurfaceLevel(0); d3d9Device.GetRenderTargetData(srcBufferResources.Surface, tmpsurface); D3D9.Surface.FromSurface(dstBufferResources.Surface, tmpsurface, D3D9.Filter.Default, 0, dsrcRect, ddestRect); tmpsurface.SafeDispose(); tmptex.SafeDispose(); return; } // Otherwise, try the normal method D3D9.Surface.FromSurface(dstBufferResources.Surface, srcBufferResources.Surface, D3D9.Filter.Default, 0, dsrcRect, ddestRect); } else if (dstBufferResources.Volume != null && srcBufferResources.Volume != null) { // Volume-to-volume var dsrcBox = ToD3DBox(srcBox); var ddestBox = ToD3DBox(dstBox); D3D9.Volume.FromVolume(dstBufferResources.Volume, srcBufferResources.Volume, D3D9.Filter.Default, 0, dsrcBox, ddestBox); } else { // Software fallback base.Blit(rsrc, srcBox, dstBox); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> void DoCaptureRenderTarget(Device device, string hook) { this.Frame(); try { #region Screenshot Request // If we have issued the command to copy data to our render target, check if it is complete bool qryResult; if (_queryIssued && _requestCopy != null && _query.GetData(out qryResult, false)) { // The GPU has finished copying data to _renderTargetCopy, we can now lock // the data and access it on another thread. _queryIssued = false; // Lock the render target SharpDX.Rectangle rect; SharpDX.DataRectangle lockedRect = LockRenderTarget(_renderTargetCopy, out rect); _renderTargetCopyLocked = true; // Copy the data from the render target System.Threading.Tasks.Task.Factory.StartNew(() => { lock (_lockRenderTarget) { ProcessCapture(rect.Width, rect.Height, lockedRect.Pitch, _renderTargetCopy.Description.Format.ToPixelFormat(), lockedRect.DataPointer, _requestCopy); } }); } // Single frame capture request if (this.Request != null) { DateTime start = DateTime.Now; try { using (Surface renderTarget = device.GetRenderTarget(0)) { int width, height; // If resizing of the captured image, determine correct dimensions if (Request.Resize != null && (renderTarget.Description.Width > Request.Resize.Value.Width || renderTarget.Description.Height > Request.Resize.Value.Height)) { if (renderTarget.Description.Width > Request.Resize.Value.Width) { width = Request.Resize.Value.Width; height = (int)Math.Round((renderTarget.Description.Height * ((double)Request.Resize.Value.Width / (double)renderTarget.Description.Width))); } else { height = Request.Resize.Value.Height; width = (int)Math.Round((renderTarget.Description.Width * ((double)Request.Resize.Value.Height / (double)renderTarget.Description.Height))); } } else { width = renderTarget.Description.Width; height = renderTarget.Description.Height; } // If existing _renderTargetCopy, ensure that it is the correct size and format if (_renderTargetCopy != null && (_renderTargetCopy.Description.Width != width || _renderTargetCopy.Description.Height != height || _renderTargetCopy.Description.Format != renderTarget.Description.Format)) { // Cleanup resources Cleanup(); } // Ensure that we have something to put the render target data into if (!_resourcesInitialised || _renderTargetCopy == null) { CreateResources(device, width, height, renderTarget.Description.Format); } // Resize from render target Surface to resolvedSurface (also deals with resolving multi-sampling) device.StretchRectangle(renderTarget, _resolvedTarget, TextureFilter.None); } // If the render target is locked from a previous request unlock it if (_renderTargetCopyLocked) { // Wait for the the ProcessCapture thread to finish with it lock (_lockRenderTarget) { if (_renderTargetCopyLocked) { _renderTargetCopy.UnlockRectangle(); _renderTargetCopyLocked = false; } } } // Copy data from resolved target to our render target copy device.GetRenderTargetData(_resolvedTarget, _renderTargetCopy); _requestCopy = Request.Clone(); _query.Issue(Issue.End); _queryIssued = true; } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } DateTime end = DateTime.Now; this.DebugMessage(hook + ": Capture time: " + (end - start).ToString()); } #endregion if (this.Config.ShowOverlay) { #region Draw Overlay // Check if overlay needs to be initialised if (_overlayEngine == null || _overlayEngine.Device.NativePointer != device.NativePointer) { // Cleanup if necessary if (_overlayEngine != null) RemoveAndDispose(ref _overlayEngine); _overlayEngine = ToDispose(new DX9.DXOverlayEngine()); // Create Overlay _overlayEngine.Overlays.Add(new Capture.Hook.Common.Overlay { Elements = { // Add frame rate new Capture.Hook.Common.FramesPerSecond(new System.Drawing.Font("Arial", 14, FontStyle.Bold)) { Location = new System.Drawing.Point(5,5), Color = System.Drawing.Color.Red, AntiAliased = true }/*, new Capture.Hook.Common.TextElement(new System.Drawing.Font("Arial", 16, FontStyle.Bold)) { Location = new Point(20, 50), Color = Color.Yellow, Text = "Test" }*/ // Example of adding an image to overlay (can implement semi transparency with Tint, e.g. Ting = Color.FromArgb(127, 255, 255, 255)) //new Capture.Hook.Common.ImageElement(@"C:\Temp\test.bmp") { Location = new System.Drawing.Point(20, 20) } } }); _overlayEngine.Initialise(device); } // Draw Overlay(s) else if (_overlayEngine != null) { foreach (var overlay in _overlayEngine.Overlays) overlay.Frame(); _overlayEngine.Draw(); } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> private void DoCaptureRenderTarget(Device device, string hook) { Frame(); try { #region Screenshot Request // If we have issued the command to copy data to our render target, check if it is complete bool qryResult; if (_queryIssued && _requestCopy != null && _query.GetData(out qryResult, false)) { // The GPU has finished copying data to _renderTargetCopy, we can now lock // the data and access it on another thread. _queryIssued = false; // Lock the render target Rectangle rect; var lockedRect = LockRenderTarget(_renderTargetCopy, out rect); _renderTargetCopyLocked = true; // Copy the data from the render target Task.Factory.StartNew(() => { lock (_lockRenderTarget) { ProcessCapture(rect.Width, rect.Height, lockedRect.Pitch, _renderTargetCopy.Description.Format.ToPixelFormat(), lockedRect.DataPointer, _requestCopy); } }); } // Single frame capture request if (Request != null) { var start = DateTime.Now; try { using (var renderTarget = device.GetRenderTarget(0)) { int width, height; // If resizing of the captured image, determine correct dimensions if (Request.Resize != null && (renderTarget.Description.Width > Request.Resize.Value.Width || renderTarget.Description.Height > Request.Resize.Value.Height)) { if (renderTarget.Description.Width > Request.Resize.Value.Width) { width = Request.Resize.Value.Width; height = (int) Math.Round((renderTarget.Description.Height* (Request.Resize.Value.Width/ (double) renderTarget.Description.Width))); } else { height = Request.Resize.Value.Height; width = (int) Math.Round((renderTarget.Description.Width* (Request.Resize.Value.Height/ (double) renderTarget.Description.Height))); } } else { width = renderTarget.Description.Width; height = renderTarget.Description.Height; } // If existing _renderTargetCopy, ensure that it is the correct size and format if (_renderTargetCopy != null && (_renderTargetCopy.Description.Width != width || _renderTargetCopy.Description.Height != height || _renderTargetCopy.Description.Format != renderTarget.Description.Format)) { // Cleanup resources Cleanup(); } // Ensure that we have something to put the render target data into if (!_resourcesInitialised || _renderTargetCopy == null) { CreateResources(device, width, height, renderTarget.Description.Format); } // Resize from render target Surface to resolvedSurface (also deals with resolving multi-sampling) device.StretchRectangle(renderTarget, _resolvedTarget, TextureFilter.None); } // If the render target is locked from a previous request unlock it if (_renderTargetCopyLocked) { // Wait for the the ProcessCapture thread to finish with it lock (_lockRenderTarget) { if (_renderTargetCopyLocked) { _renderTargetCopy.UnlockRectangle(); _renderTargetCopyLocked = false; } } } // Copy data from resolved target to our render target copy device.GetRenderTargetData(_resolvedTarget, _renderTargetCopy); _requestCopy = Request.Clone(); _query.Issue(Issue.End); _queryIssued = true; } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } var end = DateTime.Now; DebugMessage(hook + ": Capture time: " + (end - start)); } #endregion if (Config.ShowOverlay) { #region Draw Overlay // Check if overlay needs to be initialised if (_overlayEngine == null || _overlayEngine.Device.NativePointer != device.NativePointer || IsOverlayUpdatePending) { // Cleanup if necessary if (_overlayEngine != null) _overlayEngine.Dispose(); _overlayEngine = ToDispose(new DXOverlayEngine()); // Create Overlay _overlayEngine.Overlays.Add(new Overlay { Elements = OverlayElements }); _overlayEngine.Initialise(device); IsOverlayUpdatePending = false; } // Draw Overlay(s) else if (_overlayEngine != null) { foreach (var overlay in _overlayEngine.Overlays) overlay.Frame(); _overlayEngine.Draw(); } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
private void HandleCaptureRequest(Device device) { try { for (int i = 0; i < BUFFERS; i++) { bool tmp; if (this.issuedQueries[i] && this.queries[i].GetData(out tmp, false)) { this.issuedQueries[i] = false; try { var lockedRect = this.surfaces[i].LockRectangle(LockFlags.ReadOnly); this.surfaceDataPointer = lockedRect.DataPointer; this.currentSurface = i; this.surfaceLocked[i] = true; } catch (Exception ex) { DebugMessage(ex.ToString()); } } } if (previousRequestId != null || lastRequestId != null) { this.previousRequestId = null; int nextCapture = (curCapture == BUFFERS - 1) ? 0 : (curCapture + 1); var sourceTexture = copySurfaces[curCapture]; try { using (var backbuffer = device.GetBackBuffer(0, 0)) { device.StretchRectangle(backbuffer, sourceTexture, TextureFilter.None); } if (copyWait < BUFFERS - 1) { copyWait++; } else { var prevSourceTexture = copySurfaces[nextCapture]; var targetTexture = surfaces[nextCapture]; if (this.surfaceLocked[nextCapture]) { lock (this.surfaceLocks[nextCapture]) { this.surfaces[nextCapture].UnlockRectangle(); this.surfaceLocked[nextCapture] = false; } } try { device.GetRenderTargetData(prevSourceTexture, targetTexture); } catch (Exception ex) { DebugMessage(ex.ToString()); } this.queries[nextCapture].Issue(Issue.End); this.issuedQueries[nextCapture] = true; } } catch (Exception ex) { this.DebugMessage(ex.ToString()); } curCapture = nextCapture; } } catch (Exception e) { this.DebugMessage(e.ToString()); } }
protected void BlitToMemory(BasicBox srcBox, PixelBox dst, BufferResources srcBufferResources, D3D9.Device d3d9Device) { // Decide on pixel format of temp surface PixelFormat tmpFormat = Format; if (D3D9Helper.ConvertEnum(dst.Format) != D3D9.Format.Unknown) { tmpFormat = dst.Format; } if (srcBufferResources.Surface != null) { Debug.Assert(srcBox.Depth == 1 && dst.Depth == 1); var srcDesc = srcBufferResources.Surface.Description; var temppool = D3D9.Pool.Scratch; // if we're going to try to use GetRenderTargetData, need to use system mem pool var tryGetRenderTargetData = false; if (((srcDesc.Usage & D3D9.Usage.RenderTarget) != 0) && (srcBox.Width == dst.Width) && (srcBox.Height == dst.Height) && (srcBox.Width == Width) && (srcBox.Height == Height) && (Format == tmpFormat)) { tryGetRenderTargetData = true; temppool = D3D9.Pool.SystemMemory; } // Create temp texture var tmp = new D3D9.Texture(d3d9Device, dst.Width, dst.Height, 1, // 1 mip level ie topmost, generate no mipmaps 0, D3D9Helper.ConvertEnum(tmpFormat), temppool); var surface = tmp.GetSurfaceLevel(0); // Copy texture to this temp surface var srcRect = ToD3DRectangle(srcBox); var destRect = ToD3DRectangle(dst); // Get the real temp surface format var dstDesc = surface.Description; tmpFormat = D3D9Helper.ConvertEnum(dstDesc.Format); // Use fast GetRenderTargetData if we are in its usage conditions var fastLoadSuccess = false; if (tryGetRenderTargetData) { var result = d3d9Device.GetRenderTargetData(srcBufferResources.Surface, surface); fastLoadSuccess = result.Success; } if (!fastLoadSuccess) { var res = D3D9.Surface.FromSurface(surface, srcBufferResources.Surface, D3D9.Filter.Default, 0, srcRect, destRect); if (res.Failure) { surface.SafeDispose(); tmp.SafeDispose(); throw new AxiomException("D3D9.Surface.FromSurface failed in D3D9HardwarePixelBuffer.BlitToMemory"); } } // Lock temp surface and copy it to memory var lrect = surface.LockRectangle(D3D9.LockFlags.ReadOnly); // Copy it var locked = new PixelBox(dst.Width, dst.Height, dst.Depth, tmpFormat); FromD3DLock(locked, lrect); PixelConverter.BulkPixelConversion(locked, dst); surface.UnlockRectangle(); // Release temporary surface and texture surface.SafeDispose(); tmp.SafeDispose(); } else if (srcBufferResources.Volume != null) { // Create temp texture var tmp = new D3D9.VolumeTexture(d3d9Device, dst.Width, dst.Height, dst.Depth, 0, 0, D3D9Helper.ConvertEnum(tmpFormat), D3D9.Pool.Scratch); var surface = tmp.GetVolumeLevel(0); // Volume var ddestBox = ToD3DBoxExtent(dst); var dsrcBox = ToD3DBox(srcBox); var res = D3D9.Volume.FromVolume(surface, srcBufferResources.Volume, D3D9.Filter.Default, 0, dsrcBox, ddestBox); if (res.Failure) { surface.SafeDispose(); tmp.SafeDispose(); throw new AxiomException("D3D9.Surface.FromVolume failed in D3D9HardwarePixelBuffer.BlitToMemory"); } // Lock temp surface and copy it to memory var lbox = surface.LockBox(D3D9.LockFlags.ReadOnly); // Filled in by D3D // Copy it var locked = new PixelBox(dst.Width, dst.Height, dst.Depth, tmpFormat); FromD3DLock(locked, lbox); PixelConverter.BulkPixelConversion(locked, dst); surface.UnlockBox(); // Release temporary surface and texture surface.SafeDispose(); tmp.SafeDispose(); } }
private void HandleCaptureRequest(Device device) { try { bool tmp; if (this.queryIssued && this.query.GetData(out tmp, false)) { this.queryIssued = false; var lockedRect = this.surface.LockRectangle(LockFlags.ReadOnly); this.surfaceDataPointer = lockedRect.DataPointer; this.surfaceLocked = true; this.copyEvent.Set(); } using (var backbuffer = device.GetBackBuffer(0, 0)) { device.StretchRectangle(backbuffer, this.renderTarget, TextureFilter.None); } if (this.surfaceLocked) { lock (this.renderTargetLock) { if (this.surfaceLocked) { this.surface.UnlockRectangle(); this.surfaceLocked = false; } } } try { var cooplevel = device.TestCooperativeLevel(); if (cooplevel.Code == ResultCode.Success.Code) { device.GetRenderTargetData(this.renderTarget, this.surface); this.query.Issue(Issue.End); this.queryIssued = true; } else { this.DebugMessage(string.Format("DirectX Error: TestCooperativeLevel = {0}", cooplevel.Code)); } } catch (Exception ex) { this.DebugMessage(ex.ToString()); } } catch (Exception e) { this.DebugMessage(e.ToString()); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> void DoCaptureRenderTarget(Device device, string hook) { this.Frame(); try { #region Screenshot Request // Single frame capture request if (this.Request != null) { DateTime start = DateTime.Now; try { using (Surface renderTargetTemp = device.GetRenderTarget(0)) { int width, height; // TODO: If resizing the captured image is required it can be adjusted here //if (renderTargetTemp.Description.Width > 1280) //{ // width = 1280; // height = (int)Math.Round((renderTargetTemp.Description.Height * (1280.0 / renderTargetTemp.Description.Width))); //} //else { width = renderTargetTemp.Description.Width; height = renderTargetTemp.Description.Height; } // First ensure we have a Surface to the render target data into if (_renderTarget == null) { // Create offscreen surface to use as copy of render target data using (SwapChain sc = device.GetSwapChain(0)) { _renderTarget = Surface.CreateOffscreenPlain(device, width, height, sc.PresentParameters.BackBufferFormat, Pool.SystemMemory); } } // Create our resolved surface (resizing if necessary and to resolve any multi-sampling) using (Surface resolvedSurface = Surface.CreateRenderTarget(device, width, height, renderTargetTemp.Description.Format, MultisampleType.None, 0, false)) { // Resize from Render Surface to resolvedSurface device.StretchRectangle(renderTargetTemp, resolvedSurface, TextureFilter.None); // Get Render Data device.GetRenderTargetData(resolvedSurface, _renderTarget); } } if (Request != null) ProcessRequest(); } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } DateTime end = DateTime.Now; this.DebugMessage(hook + ": Capture time: " + (end - start).ToString()); } #endregion if (this.Config.ShowOverlay) { #region Draw frame rate // TODO: font needs to be created and then reused, not created each frame! using (SharpDX.Direct3D9.Font font = new SharpDX.Direct3D9.Font(device, 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 })) { if (this.FPS.GetFPS() >= 1) { font.DrawText(null, String.Format("{0:N0} fps", this.FPS.GetFPS()), 5, 5, SharpDX.Color.Red); } if (this.TextDisplay != null && this.TextDisplay.Display) { font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); } } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
private void HandleCaptureRequest(Device device) { if (Request == null) { return; } try { bool tmp; if (queryIssued && query.GetData(out tmp, false)) { queryIssued = false; var lockedRect = surface.LockRectangle(LockFlags.ReadOnly); surfaceDataPointer = lockedRect.DataPointer; surfaceLocked = true; new Thread(HandleCaptureRequestThread).Start(); } using (var backbuffer = device.GetBackBuffer(0, 0)) { device.StretchRectangle(backbuffer, renderTarget, TextureFilter.None); } if (surfaceLocked) { lock (renderTargetLock) { if (!this.surfaceLocked) { return; } this.surface.UnlockRectangle(); this.surfaceLocked = false; } } try { device.GetRenderTargetData(renderTarget, surface); query.Issue(Issue.End); queryIssued = true; } catch (Exception ex) { DebugMessage(ex.ToString()); } } catch (Exception e) { DebugMessage(e.ToString()); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> void DoCaptureRenderTarget(Device device, string hook) { this.Frame(); try { #region Screenshot Request // If we have issued the command to copy data to our render target, check if it is complete bool qryResult; if (_queryIssued && _requestCopy != null && _query.GetData(out qryResult, false)) { // The GPU has finished copying data to _renderTargetCopy, we can now lock // the data and access it on another thread. _queryIssued = false; // Lock the render target SharpDX.Rectangle rect; SharpDX.DataRectangle lockedRect = LockRenderTarget(_renderTargetCopy, out rect); _renderTargetCopyLocked = true; // Copy the data from the render target System.Threading.Tasks.Task.Factory.StartNew(() => { lock (_lockRenderTarget) { ProcessCapture(rect.Width, rect.Height, lockedRect.Pitch, _renderTargetCopy.Description.Format.ToPixelFormat(), lockedRect.DataPointer, _requestCopy); } }); } // Single frame capture request if (this.Request != null) { DateTime start = DateTime.Now; try { using (Surface renderTarget = device.GetRenderTarget(0)) { int width, height; // If resizing of the captured image, determine correct dimensions if (Request.Resize != null && (renderTarget.Description.Width > Request.Resize.Value.Width || renderTarget.Description.Height > Request.Resize.Value.Height)) { if (renderTarget.Description.Width > Request.Resize.Value.Width) { width = Request.Resize.Value.Width; height = (int)Math.Round((renderTarget.Description.Height * ((double)Request.Resize.Value.Width / (double)renderTarget.Description.Width))); } else { height = Request.Resize.Value.Height; width = (int)Math.Round((renderTarget.Description.Width * ((double)Request.Resize.Value.Height / (double)renderTarget.Description.Height))); } } else { width = renderTarget.Description.Width; height = renderTarget.Description.Height; } // If existing _renderTargetCopy, ensure that it is the correct size and format if (_renderTargetCopy != null && (_renderTargetCopy.Description.Width != width || _renderTargetCopy.Description.Height != height || _renderTargetCopy.Description.Format != renderTarget.Description.Format)) { // Cleanup resources Cleanup(); } // Ensure that we have something to put the render target data into if (!_resourcesInitialised || _renderTargetCopy == null) { CreateResources(device, width, height, renderTarget.Description.Format); } // Resize from render target Surface to resolvedSurface (also deals with resolving multi-sampling) device.StretchRectangle(renderTarget, _resolvedTarget, TextureFilter.None); } // If the render target is locked from a previous request unlock it if (_renderTargetCopyLocked) { // Wait for the the ProcessCapture thread to finish with it lock (_lockRenderTarget) { if (_renderTargetCopyLocked) { _renderTargetCopy.UnlockRectangle(); _renderTargetCopyLocked = false; } } } // Copy data from resolved target to our render target copy device.GetRenderTargetData(_resolvedTarget, _renderTargetCopy); _requestCopy = Request.Clone(); _query.Issue(Issue.End); _queryIssued = true; } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } DateTime end = DateTime.Now; this.DebugMessage(hook + ": Capture time: " + (end - start).ToString()); } #endregion if (this.Config.ShowOverlay) { #region Draw frame rate if (_font == null || _font.Device.NativePointer != device.NativePointer) CreateFont(device); if (this.FPS.GetFPS() >= 1) { _font.DrawText(null, String.Format("{0:N0} fps", this.FPS.GetFPS()), 5, 5, SharpDX.Color.Red); } if (this.TextDisplay != null && this.TextDisplay.Display) { _font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
private void HandleCaptureRequest(Device device) { try { if (_killThread) { return; } for (var i = 0; i < BUFFERS; i++) { bool tmp; if (_issuedQueries[i] && _queries[i].GetData(out tmp, false)) { _issuedQueries[i] = false; var lockedRect = _surfaces[i].LockRectangle(LockFlags.ReadOnly); _surfaceDataPointer = lockedRect.DataPointer; _currentSurface = i; _surfaceLocked[i] = true; _copyReadySignal.Set(); } } if (_captureWaitHandle.WaitOne(0) || _copyWait < BUFFERS - 1) { var nextCapture = (_curCapture == BUFFERS - 1) ? 0 : (_curCapture + 1); try { using (var backbuffer = device.GetBackBuffer(0, 0)) { var sourceTexture = _copySurfaces[_curCapture]; device.StretchRectangle(backbuffer, sourceTexture, TextureFilter.None); } if (_copyWait < BUFFERS - 1) { _copyWait++; } else { var prevSourceTexture = _copySurfaces[nextCapture]; var targetTexture = _surfaces[nextCapture]; if (_surfaceLocked[nextCapture]) { lock (_surfaceLocks[nextCapture]) { _surfaces[nextCapture].UnlockRectangle(); _surfaceLocked[nextCapture] = false; } } try { device.GetRenderTargetData(prevSourceTexture, targetTexture); } catch (Exception ex) { DebugMessage(ex.ToString()); } _queries[nextCapture].Issue(Issue.End); _issuedQueries[nextCapture] = true; } } catch (Exception ex) { DebugMessage(ex.ToString()); } finally { _captureWaitHandle.Reset(); _curCapture = nextCapture; } } } catch (Exception e) { DebugMessage(e.ToString()); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> void DoCaptureRenderTarget(Device device, string hook) { try { #region Screenshot Request // Single frame capture request if (this.Request != null) { DateTime start = DateTime.Now; try { using (Surface renderTargetTemp = device.GetRenderTarget(0)) { int width, height; // TODO: If resizing the captured image is required it can be adjusted here //if (renderTargetTemp.Description.Width > 1280) //{ // width = 1280; // height = (int)Math.Round((renderTargetTemp.Description.Height * (1280.0 / renderTargetTemp.Description.Width))); //} //else { width = renderTargetTemp.Description.Width; height = renderTargetTemp.Description.Height; } // First ensure we have a Surface to the render target data into if (_renderTarget == null) { // Create offscreen surface to use as copy of render target data using (SwapChain sc = device.GetSwapChain(0)) { _renderTarget = Surface.CreateOffscreenPlain(device, width, height, sc.PresentParameters.BackBufferFormat, Pool.SystemMemory); } } // Create our resolved surface (resizing if necessary and to resolve any multi-sampling) using ( Surface resolvedSurface = Surface.CreateRenderTarget(device, width, height, renderTargetTemp.Description.Format, MultisampleType.None, 0, false)) { // Resize from Render Surface to resolvedSurface device.StretchRectangle(renderTargetTemp, resolvedSurface, TextureFilter.None); // Get Render Data device.GetRenderTargetData(resolvedSurface, _renderTarget); } } if (Request != null) { ProcessRequest(); } } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } DateTime end = DateTime.Now; this.DebugMessage(hook + ": Capture time: " + (end - start).ToString()); } #endregion if (this.Config.ShowOverlay) { // SHIT this.Frame(); #region Draw frame rate // TODO: font needs to be created and then reused, not created each frame! using (var font = new SharpDX.Direct3D9.Font(device, new FontDescription() { Height = 26, FaceName = "Quartz MS", Italic = false, Width = 0, MipLevels = 1, CharacterSet = FontCharacterSet.Default, OutputPrecision = FontPrecision.Default, Quality = FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Normal })) { // Make a Texture from a file... using (FileStream myFileStream = new FileStream(@"baronbutton.png", System.IO.FileMode.Open)) { mytexStream = SharpDX.Direct3D9.Texture.FromStream(device, myFileStream); } Sprite spritezor = new SharpDX.Direct3D9.Sprite(device); spritezor.Begin(SharpDX.Direct3D9.SpriteFlags.None); var baronPos = new Vector3(1476, 812, 0); spritezor.Draw(mytexStream, new ColorBGRA(0xffffffff), null, null, baronPos); // Display always... if (this.Config.TestThisShit != 0) { // Draw sprite... spritezor.End(); spritezor.Dispose(); // Oritinal Text before sprites worked... //font.DrawText(null, "Timer 1", 5, 10, SharpDX.Color.Lime); } // Display on Timer... if (this.TextDisplay != null && this.TextDisplay.Display) { font.DrawText(null, this.TextDisplay.Text, 1477, 870, new SharpDX.ColorBGRA(255, 0, 0, 255)); // Alternate font for timers pulsed with alpha fading between ticks... // font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); } /* DXHookD3D9 Original statements to draw the FPS... * if (this.FPS.GetFPS() >= 1) * { * font.DrawText(null, String.Format("{0:N0} fps", this.FPS.GetFPS()), 5, 5, SharpDX.Color.Red); * } * if (this.TextDisplay != null && this.TextDisplay.Display) * { * font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); * } */ } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
/// <summary> /// Implementation of capturing from the render target of the Direct3D9 Device (or DeviceEx) /// </summary> /// <param name="device"></param> void DoCaptureRenderTarget(Device device, string hook) { try { #region Screenshot Request // Single frame capture request if (this.Request != null) { DateTime start = DateTime.Now; try { using (Surface renderTargetTemp = device.GetRenderTarget(0)) { int width, height; // TODO: If resizing the captured image is required it can be adjusted here //if (renderTargetTemp.Description.Width > 1280) //{ // width = 1280; // height = (int)Math.Round((renderTargetTemp.Description.Height * (1280.0 / renderTargetTemp.Description.Width))); //} //else { width = renderTargetTemp.Description.Width; height = renderTargetTemp.Description.Height; } // First ensure we have a Surface to the render target data into if (_renderTarget == null) { // Create offscreen surface to use as copy of render target data using (SwapChain sc = device.GetSwapChain(0)) { _renderTarget = Surface.CreateOffscreenPlain(device, width, height, sc.PresentParameters.BackBufferFormat, Pool.SystemMemory); } } // Create our resolved surface (resizing if necessary and to resolve any multi-sampling) using ( Surface resolvedSurface = Surface.CreateRenderTarget(device, width, height, renderTargetTemp.Description.Format, MultisampleType.None, 0, false)) { // Resize from Render Surface to resolvedSurface device.StretchRectangle(renderTargetTemp, resolvedSurface, TextureFilter.None); // Get Render Data device.GetRenderTargetData(resolvedSurface, _renderTarget); } } if (Request != null) ProcessRequest(); } finally { // We have completed the request - mark it as null so we do not continue to try to capture the same request // Note: If you are after high frame rates, consider implementing buffers here to capture more frequently // and send back to the host application as needed. The IPC overhead significantly slows down // the whole process if sending frame by frame. Request = null; } DateTime end = DateTime.Now; this.DebugMessage(hook + ": Capture time: " + (end - start).ToString()); } #endregion if (this.Config.ShowOverlay) { // SHIT this.Frame(); #region Draw frame rate // TODO: font needs to be created and then reused, not created each frame! using (var font = new SharpDX.Direct3D9.Font(device, new FontDescription() { Height = 26, FaceName = "Quartz MS", Italic = false, Width = 0, MipLevels = 1, CharacterSet = FontCharacterSet.Default, OutputPrecision = FontPrecision.Default, Quality = FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Normal })) { // Make a Texture from a file... using (FileStream myFileStream = new FileStream(@"baronbutton.png", System.IO.FileMode.Open)) { mytexStream = SharpDX.Direct3D9.Texture.FromStream(device, myFileStream); } Sprite spritezor = new SharpDX.Direct3D9.Sprite(device); spritezor.Begin(SharpDX.Direct3D9.SpriteFlags.None); var baronPos = new Vector3(1476, 812, 0); spritezor.Draw(mytexStream, new ColorBGRA(0xffffffff), null, null, baronPos); // Display always... if (this.Config.TestThisShit != 0) { // Draw sprite... spritezor.End(); spritezor.Dispose(); // Oritinal Text before sprites worked... //font.DrawText(null, "Timer 1", 5, 10, SharpDX.Color.Lime); } // Display on Timer... if (this.TextDisplay != null && this.TextDisplay.Display) { font.DrawText(null, this.TextDisplay.Text, 1477, 870, new SharpDX.ColorBGRA(255, 0, 0, 255)); // Alternate font for timers pulsed with alpha fading between ticks... // font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); } /* DXHookD3D9 Original statements to draw the FPS... if (this.FPS.GetFPS() >= 1) { font.DrawText(null, String.Format("{0:N0} fps", this.FPS.GetFPS()), 5, 5, SharpDX.Color.Red); } if (this.TextDisplay != null && this.TextDisplay.Display) { font.DrawText(null, this.TextDisplay.Text, 5, 25, new SharpDX.ColorBGRA(255, 0, 0, (byte)Math.Round((Math.Abs(1.0f - TextDisplay.Remaining) * 255f)))); } */ } #endregion } } catch (Exception e) { DebugMessage(e.ToString()); } }
private void DoCaptureRenderTarget(Device device, string hook) { try { if (isCapturing && signalEnd.WaitOne(0)) { ClearD3D9Data(); isCapturing = false; stopRequested = true; } if (!isCapturing) { return; } if (!bHasTextures) { using (Surface backbuffer = device.GetRenderTarget(0)) { copyData.format = (int)backbuffer.Description.Format; copyData.width = backbuffer.Description.Width; copyData.height = backbuffer.Description.Height; } DoD3DHooks(device); } if (!bHasTextures) { return; } long timeVal = DateTime.Now.Ticks; long frameTime = 1000000 / targetFps; // lock at 30 fps if (frameTime != 0) { for (var i = 0; i < NUM_BUFFERS; i++) { if (issuedQueries[i]) { bool tmp; if (queries[i].GetData(out tmp, false)) { issuedQueries[i] = false; Surface targetTexture = textures[i]; try { var lockedRect = targetTexture.LockRectangle(LockFlags.ReadOnly); pCopyData = lockedRect.DataPointer; curCPUTexture = i; lockedTextures[i] = true; hCopyEvent.Set(); } catch (Exception ex) { DebugMessage(ex.ToString()); } } } } long timeElapsed = timeVal - lastTime; if (timeElapsed >= frameTime) { lastTime += frameTime; if (timeElapsed > frameTime * 2) { lastTime = timeVal; } var nextCapture = (curCapture == NUM_BUFFERS - 1) ? 0 : (curCapture + 1); Surface sourceTexture = copyD3D9Textures[curCapture]; using (var backbuffer = device.GetBackBuffer(0, 0)) { device.StretchRectangle(backbuffer, sourceTexture, TextureFilter.None); } if (copyWait < (NUM_BUFFERS - 1)) { copyWait++; } else { Surface prevSourceTexture = copyD3D9Textures[nextCapture]; Surface targetTexture = textures[nextCapture]; if (lockedTextures[nextCapture]) { Monitor.Enter(dataMutexes[nextCapture]); targetTexture.UnlockRectangle(); lockedTextures[nextCapture] = false; Monitor.Exit(dataMutexes[nextCapture]); } try { device.GetRenderTargetData(prevSourceTexture, targetTexture); } catch (Exception ex) { DebugMessage(ex.ToString()); } queries[nextCapture].Issue(Issue.End); issuedQueries[nextCapture] = true; } curCapture = nextCapture; } } } catch (Exception e) { DebugMessage("Error in PresentHook: " + e); } }