Delphi 德尔福;而";当鼠标未移动到FireMonkey应用程序上时,性能会降低
我正在用Delphi+openGL玩一点。因为我很懒,所以我想用FireMonkey为我制作一个表单。Delphi 德尔福;而";当鼠标未移动到FireMonkey应用程序上时,性能会降低,delphi,opengl,firemonkey,onkeydown,Delphi,Opengl,Firemonkey,Onkeydown,我正在用Delphi+openGL玩一点。因为我很懒,所以我想用FireMonkey为我制作一个表单。 所以我制作了一个FireMonkeyHD应用程序,初始化了GL,渲染了一个基本的立方体。。。发现了一些奇怪的行为。当我不移动鼠标时,我的速度大约为10FPS。当我移动鼠标时,性能很容易提高到500FPS甚至更高。那会是什么? *注意:我在主线程中使用onKeyDown事件开始渲染… 为了更好地理解,请看两张图片: 一些代码: unit Unit1; interface uses { .
所以我制作了一个FireMonkeyHD应用程序,初始化了GL,渲染了一个基本的立方体。。。发现了一些奇怪的行为。当我不移动鼠标时,我的速度大约为10FPS。当我移动鼠标时,性能很容易提高到500FPS甚至更高。那会是什么?
*注意:我在主线程中使用onKeyDown事件开始渲染…
为了更好地理解,请看两张图片: 一些代码:
unit Unit1;
interface
uses
{ ... }
;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char;
Shift: TShiftState);
private
degen
: IDeGEn;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormCreate(Sender: TObject);
var
DeGEnFactory
: TDeGEnFactory;
begin
{ ... }
// Load DeGEn
degen := DeGEnFactory.newDeGEn(WindowHandleToPlatform(Form1.Handle).Wnd);
// Initialize
degen.get3D.init(600, 800);
degen.get3D.setOnRender(function : Boolean
var
v3d
: R3DVector;
begin
Result := true;
self.Caption := IntToStr(degen.get3D.getFPS);
v3d.z := 0.01;
degen.get3D.getCamera.move(v3d);
degen.get3D.renderTest;
end);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// Shut down DeGEn
{ ... }
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char;
Shift: TShiftState);
begin
// Start rendering
degen.startRendering;
end;
end.
而
startRendering
看起来是这样的:procedure TDeGEn.startRendering;
var
msg
: TMsg;
begin
if isRendering then
begin
Exit;
end;
isRendering := true;
while GetMessage(msg, 0, 0, 0) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
if not degen3D.render then
begin
Break;
end;
end;
isRendering := false;
end;
正如您可能很容易注意到的,摄影机只是以与FPS相关的速度离开立方体。我还将FPS显示为表单标题。获取消息的
等待消息。
如果不移动鼠标,很少有消息进入消息队列,渲染速度会很慢,因为CPU一直在等待GetMessage返回
当您移动鼠标时,会创建大量消息;消息队列已满,GetMessage几乎立即返回
请注意,自Windows 3.1以来,没有必要这样做messageloop
还要注意,Microsoft警告不要像这样实现messageloop。
发件人:
因为返回值可以是非零、零或-1,所以请避免类似这样的代码
这:
while(GetMessage(lpMsg,hWnd,0,0))…
如果hWnd是一个
无效的参数(例如引用已被删除的窗口)
销毁)意味着此类代码可能导致致命的应用程序错误。
相反,请使用如下代码:
无论如何,没有必要这样做循环。
相反,在表单上放置计时器,并将代码放入OnTimer
事件中
procedure TForm1.Timer1Timer(Sender: TObject);
begin
//DoRendering
end;
如果正常的计时器太慢,就会有很多高分辨率的计时器。JVCL完成了,unDelphiX也完成了。
请参见此处:
或在此:
在CPU密集型循环中处理Windows消息
我们不再使用messageloop了(从Delphi 1.0开始就没有了)。
如果发现由于循环占用所有CPU时间而导致应用程序无响应,请改用Application.ProcessMessages
WM\U计时器消息的优先级较低
如果使用默认计时器,将遇到不可靠性问题。
这是因为Windows将WM_TIMER
消息(TTimer查找的消息)视为低优先级。
如果Windows忙于其他任务,它会将多条等待的WM_TIMER
消息压缩为一条消息,以避免造成计时器消息积压。
它对WM_PAINT
消息执行相同的操作。
见:
避免这种情况的一个技巧是使用高分辨率计时器构造循环(这不取决于消息循环),或者使用带有Application.ProcessMessages
和sleep()
延迟的简单无止境循环 获取消息等待消息。
如果不移动鼠标,很少有消息进入消息队列,渲染速度会很慢,因为CPU一直在等待GetMessage返回
当您移动鼠标时,会创建大量消息;消息队列已满,GetMessage几乎立即返回
请注意,自Windows 3.1以来,没有必要这样做messageloop
还要注意,Microsoft警告不要像这样实现messageloop。
发件人:
因为返回值可以是非零、零或-1,所以请避免类似这样的代码
这:
while(GetMessage(lpMsg,hWnd,0,0))…
如果hWnd是一个
无效的参数(例如引用已被删除的窗口)
销毁)意味着此类代码可能导致致命的应用程序错误。
相反,请使用如下代码:
无论如何,没有必要这样做循环。
相反,在表单上放置计时器,并将代码放入OnTimer
事件中
procedure TForm1.Timer1Timer(Sender: TObject);
begin
//DoRendering
end;
如果正常的计时器太慢,就会有很多高分辨率的计时器。JVCL完成了,unDelphiX也完成了。
请参见此处:
或在此:
在CPU密集型循环中处理Windows消息
我们不再使用messageloop了(从Delphi 1.0开始就没有了)。
如果发现由于循环占用所有CPU时间而导致应用程序无响应,请改用Application.ProcessMessages
WM\U计时器消息的优先级较低
如果使用默认计时器,将遇到不可靠性问题。
这是因为Windows将WM_TIMER
消息(TTimer查找的消息)视为低优先级。
如果Windows忙于其他任务,它会将多条等待的WM_TIMER
消息压缩为一条消息,以避免造成计时器消息积压。
它对WM_PAINT
消息执行相同的操作。
见:
避免这种情况的一个技巧是使用高分辨率计时器构造循环(这不取决于消息循环),或者使用带有Application.ProcessMessages
和sleep()
延迟的简单无止境循环 这是非常旧的Windows应用程序中的常见行为。除非屏幕被标记为“脏”,否则他们不会重新绘制屏幕。将鼠标移到屏幕的某个部分是一种确定的方法,可以将控件标记为脏并强制重新绘制。在您的情况下,这可能不是罪魁祸首,但我怀疑它某种程度上与您的消息泵有关,移动光标会增加您的消息泵中出现绘图所需内容的频率