C# 如何在处理slimdx时降低cpu影响
我正在制作一个覆盖其他d3d游戏的应用程序,C# 如何在处理slimdx时降低cpu影响,c#,directx-9,slimdx,C#,Directx 9,Slimdx,我正在制作一个覆盖其他d3d游戏的应用程序, 除了对cpu的性能有巨大影响外,该应用程序工作正常 仅渲染一行时占用21.4%的cpu! 我正在c#上使用slimdx库,这是我的完整代码 OverLay.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using Sy
除了对cpu的性能有巨大影响外,该应用程序工作正常
仅渲染一行时占用21.4%的cpu! 我正在c#上使用slimdx库,这是我的完整代码 OverLay.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SlimDX.Direct3D11;
using SlimDX.Windows;
using System.Runtime.InteropServices;
using System.Security;
using SlimDX;
using SlimDX.DXGI;
using Device = SlimDX.Direct3D9.Device;
using Resource = SlimDX.Direct3D9.Resource;
using System.Threading;
using D3D = SlimDX.Direct3D9;
namespace OverlayForm
{
public partial class OverLay : RenderForm
{
RenderForm form;
Device device;
// D3D.Sprite sprite;
public OverLay()
{
InitializeComponent();
Paint += OverLay_Paint;
FormBorderStyle = FormBorderStyle.None;
ShowIcon = false;
ShowInTaskbar = false;
TopMost = true;
WindowState = FormWindowState.Maximized;
//Make the window's border completely transparant
//SetWindowLong(Handle , GWL_EXSTYLE , (IntPtr)(GetWindowLong(Handle , GWL_EXSTYLE) ^ WS_EX_LAYERED ^ WS_EX_TRANSPARENT));
SetWindowLong(Handle , GWL_EXSTYLE , (IntPtr)(GetWindowLong(Handle , GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT));
//Set the Alpha on the Whole Window to 255 (solid)
SetLayeredWindowAttributes(Handle , 0 , 255 , LWA_ALPHA);
form = this;
form.FormClosing += Form_FormClosing;
//Init DirectX
//This initializes the DirectX device. It needs to be done once.
//The alpha channel in the backbuffer is critical.
D3D.PresentParameters presentParameters = new D3D.PresentParameters();
presentParameters.Windowed = true;
presentParameters.SwapEffect = D3D.SwapEffect.Discard;
presentParameters.BackBufferFormat = D3D.Format.A8R8G8B8;
device = new Device(new D3D.Direct3D() , 0 , D3D.DeviceType.Hardware , Handle ,
D3D.CreateFlags.HardwareVertexProcessing , presentParameters);
//sprite = new D3D.Sprite(device);
font = new D3D.Font(device , new Font("Arial" , 9 , FontStyle.Regular));
line = new D3D.Line(this.device);
MessagePump.Run(form , new MainLoop(dxThread));
}
private void Form_FormClosing(object sender , FormClosingEventArgs e)
{
device.Dispose();
}
int centerx = Screen.PrimaryScreen.WorkingArea.Width / 2;
int centery = Screen.PrimaryScreen.WorkingArea.Height / 2;
private void OverLay_Paint(object sender , PaintEventArgs e)
{
//Create a margin (the whole form)
marg.Left = 0;
marg.Top = 0;
marg.Right = Width;
marg.Bottom = Height;
//Expand the Aero Glass Effect Border to the WHOLE form.
// since we have already had the border invisible we now
// have a completely invisible window - apart from the DirectX
// renders NOT in black.
DwmExtendFrameIntoClientArea(Handle , ref marg);
}
private static D3D.Font font;
private static D3D.Line line;
private void dxThread()
{
form.TopMost = true;
device.SetRenderState(D3D.RenderState.ZEnable , false);
device.SetRenderState(D3D.RenderState.Lighting , false);
device.SetRenderState(D3D.RenderState.CullMode , D3D.Cull.None);
device.SetTransform(D3D.TransformState.Projection , Matrix.OrthoOffCenterLH(0 , Width , Height , 0 , 0 , 1));
device.BeginScene();
//DrawFilledBox(0 , 0 , 100 , 100 , Color.White);
//font.DrawString( null, "Swag" , 10, 10 , new Color4(Color.White));
//DrawBox(0 , 0 , 10 , 10 , 1 , Color.Green);
DrawLine(0 , 0 , Screen.PrimaryScreen.Bounds.Width , Screen.PrimaryScreen.Bounds.Height , 2 , Color.Pink);
device.EndScene();
device.Present();
}
public static void DrawFilledBox(float x , float y , float w , float h , Color Color)
{
Vector2[] vLine = new Vector2[2];
line.GLLines = true;
line.Antialias = false;
line.Width = w;
vLine[0].X = x + w / 2;
vLine[0].Y = y;
vLine[1].X = x + w / 2;
vLine[1].Y = y + h;
line.Begin();
line.Draw(vLine , new Color4(Color));
line.End();
}
public static void DrawLine(float x1 , float y1 , float x2 , float y2 , float w , Color Color)
{
Vector2[] vLine = new Vector2[2] { new Vector2(x1 , y1) , new Vector2(x2 , y2) };
line.GLLines = true;
line.Antialias = false;
line.Width = w;
line.Begin();
line.Draw(vLine , new Color4(Color));
line.End();
}
public static void DrawBox(float x , float y , float w , float h , float px , System.Drawing.Color Color)
{
DrawFilledBox(x , y + h , w , px , Color);
DrawFilledBox(x - px , y , px , h , Color);
DrawFilledBox(x , y - px , w , px , Color);
DrawFilledBox(x + w , y , px , h , Color);
}
#region Extras
private Margins marg;
//this is used to specify the boundaries of the transparent area
internal struct Margins
{
public int Left, Right, Top, Bottom;
}
[DllImport("user32.dll" , SetLastError = true)]
private static extern UInt32 GetWindowLong(IntPtr hWnd , int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd , int nIndex , IntPtr dwNewLong);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd , uint crKey , byte bAlpha , uint dwFlags);
public const int GWL_EXSTYLE = -20;
public const int WS_EX_LAYERED = 0x80000;
public const int WS_EX_TRANSPARENT = 0x20;
public const int LWA_ALPHA = 0x2;
public const int LWA_COLORKEY = 0x1;
[DllImport("dwmapi.dll")]
static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd , ref Margins pMargins);
#endregion
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace OverlayForm
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
using (OverLay x = new OverLay())
{
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间覆盖形式
{
静态类程序
{
///
///应用程序的主要入口点。
///
静态void Main()
{
使用(覆盖x=新覆盖())
{
}
}
}
}
请注意:我已经看到了:
但我使用的是
MessagePump.Run
,不知道如何应用答案。问题是,即使在不渲染时,我也在使用cpu的全部功能,因此添加
Thread.Sleep(50)代码>
在dxThread方法结束时,将其降低到
问题是,即使在不渲染时,我也在使用cpu的全部功能,因此添加
Thread.Sleep(50)代码>
在dxThread方法结束时,将其降低到
CPU高的原因是SlimDX使用的是PeekMessage
,而不是大多数Windows应用程序使用的更常见的GetMessage
。前者与后者不同,前者不等待消息泵中出现消息。换句话说,GetMessage()
将阻止当前线程可能会减少CPU负载,这正是您希望性能良好的Windows桌面应用程序所要做的
MSDN:
从调用线程的消息队列检索消息。该函数将发送传入的消息,直到已发布的消息可供检索为止。
与GetMessage
不同,PeekMessage
函数在返回之前不会等待消息被发布
现在,典型的优雅Windows消息泵如下所示:
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
…然而SlimDX使用了一些人所说的动作游戏循环:
static bool AppStillIdle
{
get
{
Message msg;
return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}
}
public void MainLoop()
{
// hook the application's idle event
Application.Idle += new EventHandler(OnApplicationIdle);
Application.Run(form);
}
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
}
}
没有任何东西可以画,你将体验到一个非常紧密的PeekMessage
循环,其间没有等待
我的建议是,您可以使用MessagePump.Run
overloads for idle,或者按照以下步骤添加睡眠:
更改此项:
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
}
}
……为此:
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
Thread.Sleep(0); // <------------- be graceful
}
}
applicationidle上的void(对象发送方,事件参数e)
{
while(AppStillIdle)
{
//在空闲时间渲染帧(没有消息等待)
RenderFrame();
Thread.Sleep(0);//CPU高的原因是SlimDX使用的是PeekMessage
,而不是大多数Windows应用程序使用的更常见的GetMessage
。前者不会等待消息出现在消息泵中,而不像后者。换句话说,GetMessage()
将阻止当前线程可能会减少CPU负载,而这正是您希望性能良好的Windows桌面应用程序所做的
MSDN:
从调用线程的消息队列中检索消息。该函数将分派传入的已发送消息,直到已发布的消息可供检索为止。
与GetMessage
不同,PeekMessage
函数在返回之前不会等待消息被发布
现在,典型的优雅Windows消息泵如下所示:
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
…然而SlimDX使用了一些人所说的动作游戏循环:
static bool AppStillIdle
{
get
{
Message msg;
return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}
}
public void MainLoop()
{
// hook the application's idle event
Application.Idle += new EventHandler(OnApplicationIdle);
Application.Run(form);
}
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
}
}
没有任何东西可以画,你将体验到一个非常紧密的PeekMessage
循环,其间没有等待
我的建议是,您可以使用MessagePump.Run
overloads for idle,或者按照以下步骤添加睡眠:
更改此项:
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
}
}
……为此:
void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
RenderFrame();
Thread.Sleep(0); // <------------- be graceful
}
}
applicationidle上的void(对象发送方,事件参数e)
{
while(AppStillIdle)
{
//在空闲时间渲染帧(没有消息等待)
RenderFrame();
线程睡眠(0);//这可能是因为您正在使用C#托管代码试图拦截高性能本机游戏创建的帧。如果您注释掉所有绘图,CPU负载会是多少?@MickyD完全相同。@ChuckWalbourn CPU使用率很高,即使不打开游戏链接也可能不相关。这可能是因为您正在使用C#托管代码试图截取高性能本机游戏创建的帧的代码。如果注释掉所有绘图,CPU负载是多少?@MickyD完全相同。@ChuckWalbourn CPU使用率很高,即使不打开游戏链接,该链接也可能不相关。我不需要非常活跃的渲染机制,因为我只使用它来显示来自m的覆盖Y音乐播放器关于当前的歌曲播放、下一首歌曲等……这并不能证明什么。过度睡眠从来不是一个很好的策略来减少CPU负载。当你认为一帧需要16.6毫秒时,你的50毫秒的睡眠时间是每秒60帧渲染3帧的等效时间。我在这页上的建议是在不牺牲帧的情况下减少约20%的CPU负载。我不需要一个非常活跃的渲染机制,因为我只会用它来显示我的音乐播放器中关于当前歌曲播放、下一首歌曲等的覆盖图。这并不能证明什么。过度睡眠从来都不是一个好的策略当你认为一帧需要16.6毫秒时,每秒60帧的3帧的渲染时间是每秒60帧的等效时间。这相当于5%的性能损失。我在这个页面上的建议将在不牺牲帧的情况下减少~(20%)CPU负载。measurably@bigworld12我很怀疑你为什么不你为自己而努力?@bigworld12我很怀疑你为什么不为自己而努力呢?