protected override void Initialize(DemoConfiguration demoConfiguration) { base.Initialize(demoConfiguration); // Initialize the Font FontDescription fontDescription = new FontDescription() { Height = 72, Italic = false, CharacterSet = FontCharacterSet.Ansi, FaceName = "Arial", MipLevels = 0, OutputPrecision = FontPrecision.TrueType, PitchAndFamily = FontPitchAndFamily.Default, Quality = FontQuality.ClearType, Weight = FontWeight.Bold }; font = new Font(Device, fontDescription); // Measure the text to display fontDimension = font.MeasureText(null, DisplayText, new Rectangle(0, 0, 800, 600), FontDrawFlags.Center | FontDrawFlags.VerticalCenter); xDir = 1; yDir = 1; }
/// <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> /// Initializes a new instance of the <see cref="Font"/> class. /// </summary> /// <param name="device">The device.</param> /// <param name="fontDescription">The font description.</param> public Font(Device device, FontDescription fontDescription) : base(IntPtr.Zero) { D3DX10.CreateFontIndirect(device, ref fontDescription, this); }
/// <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) { this.Frame(); SwapChain swapChain = (SharpDX.DXGI.SwapChain)swapChainPtr; try { #region Screenshot Request //if (this.Request != null) //{ // try // { // this.DebugMessage("PresentHook: Request Start"); // DateTime startTime = DateTime.Now; // using (Texture2D texture = Texture2D.FromSwapChain<SharpDX.Direct3D10.Texture2D>(swapChain, 0)) // { // #region Determine region to capture // System.Drawing.Rectangle regionToCapture = new System.Drawing.Rectangle(0, 0, texture.Description.Width, texture.Description.Height); // if (this.Request.RegionToCapture.Width > 0) // { // regionToCapture = this.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) // { // this.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 SharpDX.DXGI.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 // Texture2D textureDest = new Texture2D(texture.Device, new Texture2DDescription() // { // CpuAccessFlags = CpuAccessFlags.None,// CpuAccessFlags.Write | CpuAccessFlags.Read, // Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm, // Supports BMP/PNG // Height = regionToCapture.Height, // Usage = ResourceUsage.Default,// ResourceUsage.Staging, // Width = regionToCapture.Width, // ArraySize = 1,//texture.Description.ArraySize, // SampleDescription = new SharpDX.DXGI.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 // Guid requestId = this.Request.RequestId; // this.Request gets set to null, so copy the RequestId for use in the thread // ThreadPool.QueueUserWorkItem(delegate // { // //FileStream fs = new FileStream(@"c:\temp\temp.bmp", FileMode.Create); // //Texture2D.ToStream(testSubResourceCopy, ImageFileFormat.Bmp, fs); // DateTime startCopyToSystemMemory = DateTime.Now; // using (MemoryStream ms = new MemoryStream()) // { // Texture2D.ToStream(textureDest, ImageFileFormat.Bmp, ms); // ms.Position = 0; // this.DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory).ToString()); // DateTime startSendResponse = DateTime.Now; // ProcessCapture(ms, requestId); // this.DebugMessage("PresentHook: Send response time: " + (DateTime.Now - startSendResponse).ToString()); // } // // Free the textureDest as we no longer need it. // textureDest.Dispose(); // textureDest = null; // this.DebugMessage("PresentHook: Full Capture time: " + (DateTime.Now - startTime).ToString()); // }); // // Make sure we free up the resolved texture if it was created // if (textureResolved != null) // { // textureResolved.Dispose(); // textureResolved = null; // } // } // this.DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime).ToString()); // this.DebugMessage("PresentHook: Request End"); // } // finally // { // // Prevent the request from being processed a second time // this.Request = null; // } //} #endregion #region Example: Draw overlay (after screenshot so we don't capture overlay as well) if (this.Config.ShowOverlay) { using (Texture2D texture = Texture2D.FromSwapChain <SharpDX.Direct3D10.Texture2D>(swapChain, 0)) { if (FPS.GetFPS() >= 1) { FontDescription fd = new SharpDX.Direct3D10.FontDescription() { Height = 16, FaceName = "Arial", Italic = false, Width = 0, MipLevels = 1, CharacterSet = SharpDX.Direct3D10.FontCharacterSet.Default, OutputPrecision = SharpDX.Direct3D10.FontPrecision.Default, Quality = SharpDX.Direct3D10.FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Bold }; // TODO: Font should not be created every frame! using (Font font = new Font(texture.Device, fd)) { DrawText(font, new Vector2(5, 5), String.Format("{0:N0} fps", FPS.GetFPS()), new Color4(SharpDX.Color.Red.ToColor3())); if (this.TextDisplay != null && this.TextDisplay.Display) { DrawText(font, new Vector2(5, 25), this.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 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); }