gpt4 book ai didi

delphi - 当鼠标不在FireMonkey应用程序上移动时,Delphi“虽然”性能下降

转载 作者:行者123 更新时间:2023-12-03 19:15:56 30 4
gpt4 key购买 nike

我在玩Delphi + openGL。因为我很懒,所以我想用FireMonkey为我做一个表格。
因此,我制作了一个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显示为表格标题。

最佳答案

GetMessage等待消息。
如果不移动鼠标,则几乎没有消息进入消息队列,并且渲染会很慢,这是因为CPU卡住了,等待GetMessage返回。

当您移动鼠标时,会创建许多消息。消息队列已满,GetMessage几乎立即返回。

请注意,自Windows 3.1开始,就没有必要执行这样的消息循环。

还要注意,Microsoft警告不要实现像这样的消息循环。
发件人:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936%28v=vs.85%29.aspx


由于返回值可以为非零,零或-1,因此请避免使用类似
这个:

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

如果hWnd是一个整数,则返回值为-1的可能性
无效的参数(例如,引用已经存在的窗口
销毁)表示此类代码可能导致致命的应用程序错误。
而是使用如下代码:


BOOL bRet;`

while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0) {
if (bRet == -1)` ` {
// handle the error and possibly exit
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


无论如何,没有必要像这样循环。
而是在窗体上放置一个计时器,然后将代码放在 OnTimer事件中。

procedure TForm1.Timer1Timer(Sender: TObject);
begin
//DoRendering
end;


如果普通计时器太慢,那么那里有很多高分辨率计时器。 JVCL已经完成,unDelphiX也已经完成了。
看到这里: http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm
或此处: http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvTimer

在CPU密集型循环中处理Windows消息
我们不再为messageloop烦恼了(自从Delphi 1.0起就没有了)。
如果发现由于循环占用所有CPU时间而导致应用程序无响应,请使用 Application.ProcessMessages

WM_TIMER消息的优先级较低
如果使用默认计时器,则会遇到不可靠性问题。
这是因为Windows将 WM_TIMER消息(TTimer查找的消息)视为低优先级。
如果Windows忙于其他任务,它将把多个等待的 WM_TIMER消息压缩为一个,以避免创建计时器消息的积压。
它对 WM_PAINT消息执行相同的操作。
参见: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644902%28v=vs.85%29.aspx

避免这种情况的一种技巧是使用高分辨率计时器(不依赖于消息循环)来构造循环,或者使用具有 Application.ProcessMessagessleep()延迟的简单无限循环。

关于delphi - 当鼠标不在FireMonkey应用程序上移动时,Delphi“虽然”性能下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19328722/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com