| 
| Autor | Beitrag |  
| Symbroson 
          Beiträge: 382
 Erhaltene Danke: 67
 
 Raspbian, Ubuntu, Win10
 C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
 
 | 
Verfasst: Mo 06.11.17 23:34 
 
Hallo EE
 Nachdem ich es endlich geschafft habe, mir die Delphi Starter-Edition zu holen, hab ich die von jaenicke empfohlene Direct2DCanvas ausprobieren wollen.
 	  |  jaenicke hat folgendes geschrieben  : |  	  | In neueren Delphiversionen, dazu zählt auch die kostenlose Starter Edition, ist die Hardwarebeschleunigung bereits direkt verfügbar. Einerseits mit Firemonkey, andererseits mit einem Direct2D-Canvas, der hier beschrieben ist: docwiki.embarcadero.com/RADStudio/Tokyo/de/Die_Direct2D-Zeichenfläche
 
 Beides ist sehr viel einfacher als direkt mit der OpenGL oder DirectX API zu arbeiten. Es gibt alternativ natürlich auch noch 2D Grafikengines, aber auch das ist etwas komplizierter als die direkt in Delphi verfügbaren Varianten.
 | 
 Leider bin ich ehrlich gesagt etwas enttäuscht, da mein doch relativ simpel gehaltenes Beispielprogramm nur etwa 10 fps erreicht.
 Außerdem mag Delphi die Resize-Funktion nicht:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 
 | procedure TForm1.WMSize(var Message: TWMSize);begin
 if Assigned(FCanvas) then
 ID2D1HwndRenderTarget(FCanvas.RenderTarget).Resize(D2D1SizeU(ClientWidth, ClientHeight));
 
 inherited;
 end;
 |  Die Grundlage bot mir diese Seite: docwiki.embarcadero...._the_Direct2D_Canvas Ich hab hier einen Thread dazu gefunden:
stackoverflow.com/qu...oing-something-wrong Davon habe ich FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);  ausprobiert, hat aber nichts gebracht.
 Zu guter letzt scheint es bei der Canvas und Formgröße einen Fehler zu geben. Ist auch gut im Beispiel zu sehen, wenn man die Form vergrößert bzw verkleinert. Die Canvasgröße wächst schneller als die Form, wodurch mein Ball verzerrt wird, und ggf das Fenster verlässt.
 Ich hoffe, jemand kann mir bei den drei Problemchen helfen    LG,
 Symbroson
 PS: mir ist außerdem aufgefallen, dass die exe Dateien der Starter-Edition viel größer als die von Delphi7 sind - hat das irgendeinen speziellen Grund? Zum Vergleich: AlgoSort.exe kompiliert mit Delphi7 war ca 500KB groß, dieses Beispielbrogramm aus der Starter ganze 2.16MB! Dabei ist es vom Umpfang her viel kleiner. (wie groß die importierten Units am Ende sind, kann ich nicht bewerten)
Einloggen, um Attachments anzusehen!
 
_________________ most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
 |  |  |  
| Symbroson  
          Beiträge: 382
 Erhaltene Danke: 67
 
 Raspbian, Ubuntu, Win10
 C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
 
 | 
Verfasst: Di 07.11.17 12:32 
 
Ok nach diesem msdn.microsoft.com/e...372260(v=vs.85).aspx  Arikel soll man zusätzlich Bitmaps benutzen. Ist das der richtige Ansatz? Klingt zumindest Vernünftig. Nur warum können die das auf der anderen Seite von der ich den Code als Grundlage genutzt habe nicht auch gleich so machen? Sehr Einsteigerfreundlich..._________________ most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
 |  |  |  
| Symbroson  
          Beiträge: 382
 Erhaltene Danke: 67
 
 Raspbian, Ubuntu, Win10
 C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
 
 | 
Verfasst: Di 07.11.17 15:33 
 
Nein, auch die Graphics.TBitmap bringt keinen Geschwindigkeitsschub. Irgendwas hab ich noch mit nem RenderTarget gelesen, aber so kompliziert kann es doch nicht sein...
Das wäre dann ja schwieriger als OpenGL, dabei sollte das Gegenteil gelten
 
 Wenn ich nur TBitmap nehme und die auf Form1.Canvas bzw auf eine TPaintBox Zeichne bekomme ich ca 500 fps. Komischerweise erreicht hier auch OpenGL diese Bildrate.
 
 Edit: ich hab mal 1000 rechtecke zeichnen lassen, TBitmap/TCanvas ist dann bei ca 30, OpenGL bei 60 fps. Das bei Direct2D auszuprobieren halte ich derzeit für nicht sinnvoll.
 _________________ most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
 |  |  |  
| Symbroson  
          Beiträge: 382
 Erhaltene Danke: 67
 
 Raspbian, Ubuntu, Win10
 C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
 
 | 
Verfasst: Di 07.11.17 17:44 
 
Entschuldigung, mit der Bildrate bei Direct2D habe ich mich vermutlich vertan - Selbst 1000 rechtecke sehen sehr flüssig aus. Gilt bei D2D die Funktion QueryPerformance[Counter/Freqiency] nicht mehr?
 Dennoch besteht noch das Problem der skalierung, sodass die Punkte das Fenster ständig verlassen. Die D2D Canvas scheint größer zu sein als die Form; und die Resize funktion natürlich
 Ich hab mal alle Versionen in den Anhang gepackt.
 Auch der Größenunterschied der exe Dateien ist hier gut zu sehen.
 LG,
 Symbroson
 Edit: Ich glaube ich hab jetzt alle Probleme Gelöst. Geholfen hat mir ein Beispielprogramm aus diesem Post: www.delphipraxis.net/1251889-post8.html Aufgrund dieses eher einseitigen Monologes kann der Thread meinetwegen wieder gelöscht werden...
Einloggen, um Attachments anzusehen!
 
_________________ most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
 |  |  |  
| TiGü Hält's aus hier
 Beiträge: 9
 Erhaltene Danke: 1
 
 
 
 
 | 
Verfasst: Do 09.11.17 16:06 
 
Versuchs mal so, da komme ich auf 2 - 3 ms pro Frame oder 333 bis 500 FPS.
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 74:
 75:
 76:
 77:
 78:
 79:
 80:
 81:
 82:
 83:
 84:
 85:
 86:
 87:
 88:
 89:
 90:
 91:
 92:
 93:
 94:
 95:
 96:
 97:
 98:
 99:
 100:
 101:
 102:
 103:
 104:
 105:
 106:
 107:
 108:
 109:
 110:
 111:
 112:
 113:
 114:
 115:
 116:
 117:
 118:
 119:
 120:
 121:
 122:
 123:
 124:
 125:
 126:
 127:
 128:
 129:
 130:
 131:
 132:
 133:
 134:
 135:
 136:
 137:
 138:
 139:
 140:
 141:
 142:
 143:
 144:
 145:
 146:
 147:
 148:
 149:
 150:
 151:
 152:
 153:
 154:
 155:
 156:
 157:
 158:
 159:
 160:
 161:
 162:
 163:
 164:
 165:
 166:
 167:
 168:
 169:
 170:
 171:
 172:
 173:
 174:
 175:
 176:
 177:
 178:
 179:
 180:
 181:
 182:
 183:
 184:
 185:
 
 | unit Unit1;
 interface
 
 uses
 Winapi.Windows, Winapi.Messages, Vcl.Forms, Direct2D, D2D1,
 Vcl.Controls, SysUtils, System.Classes;
 
 type
 TBall = record
 x, y, dx, dy, r: integer;
 end;
 
 TGameThread = class(TThread)
 strict private
 FTThreadProcedure: TThreadProcedure;
 protected
 procedure Execute; override;
 public
 constructor Create(const AMethod: TThreadProcedure);
 end;
 
 TForm1 = class(TForm)
 procedure FormDestroy(Sender: TObject);
 private
 FRectColor: D3DCOLORVALUE;
 FBkgColor: D3DCOLORVALUE;
 public
 FGameThread: TGameThread;
 FCanvas: TDirect2DCanvas;
 FBalls: array of TBall;
 FMaxNumber: integer;
 
 property Canvas: TDirect2DCanvas read FCanvas;
 
 procedure CreateWnd; override;
 procedure WMSize(var Message: TWMSize); message WM_SIZE;
 procedure StartRender;
 procedure Render;
 end;
 
 var
 Form1: TForm1;
 
 implementation
 
 uses
 Diagnostics;
 
 {$R *.dfm}
 
 
 constructor TGameThread.Create(const AMethod: TThreadProcedure);
 begin
 inherited Create(False);
 FTThreadProcedure := AMethod;
 end;
 
 procedure TGameThread.Execute;
 begin
 if Assigned(FTThreadProcedure) then
 begin
 while not Terminated do
 Synchronize(FTThreadProcedure);
 end;
 end;
 
 procedure TForm1.StartRender;
 var
 fps: int64;
 PaintStruct: TPaintStruct;
 Watch: TStopWatch;
 begin
 BeginPaint(Handle, PaintStruct);
 try
 FCanvas.BeginDraw;
 try
 Watch := TStopWatch.StartNew;
 Render;
 Watch.Stop;
 fps := 1000 div Watch.ElapsedMilliseconds;
 FCanvas.TextOut(0, 40, IntToStr(fps) + 'fps');
 finally
 FCanvas.EndDraw;
 Application.ProcessMessages;
 end;
 finally
 EndPaint(Handle, PaintStruct);
 end;
 end;
 
 procedure TForm1.CreateWnd;
 var
 I: integer;
 LClientRect: TRect;
 LClientWidth, LClientHeight: integer;
 begin
 inherited;
 FCanvas := TDirect2DCanvas.Create(Handle);
 
 randomize;
 FMaxNumber := 1000;
 SetLength(FBalls, FMaxNumber);
 
 Winapi.Windows.GetClientRect(Self.Handle, LClientRect);
 LClientWidth := LClientRect.Width;
 LClientHeight := LClientRect.Height;
 
 for I := 1 to FMaxNumber - 1 do
 begin
 with FBalls[I] do
 begin
 r := random(10) + 1;
 x := random(LClientWidth - r - r) + r;
 y := random(LClientHeight - r - r) + r;
 dx := random(10) + 1;
 dy := random(10) + 1;
 end;
 end;
 
 FRectColor := D2D1ColorF(1, 1, 1, 1);
 FBkgColor := D2D1ColorF(0, 0, 0, 0);
 FGameThread := TGameThread.Create(Self.StartRender);
 end;
 
 procedure TForm1.FormDestroy(Sender: TObject);
 begin
 FGameThread.Free;
 end;
 
 procedure TForm1.Render;
 var
 I: integer;
 BallRect: TD2D1RectF;
 CanvasRenderTarget: ID2D1RenderTarget;
 tmpX, tmpY: integer;
 LClientRect: TRect;
 LClientWidth, LClientHeight: integer;
 begin
 CanvasRenderTarget := FCanvas.RenderTarget;
 CanvasRenderTarget.Clear(FBkgColor);
 
 ID2D1SolidColorBrush(FCanvas.Brush.Handle).SetColor(FRectColor);
 
 Winapi.Windows.GetClientRect(Self.Handle, LClientRect);
 LClientWidth := LClientRect.Width;
 LClientHeight := LClientRect.Height;
 
 for I := 0 to Length(FBalls) - 1 do
 begin
 with FBalls[I] do
 begin
 tmpX := x + dx;
 if ((tmpX + r) >= LClientWidth) or ((tmpX - r) <= 0) then
 dx := random(4) - 2 - dx;
 
 tmpY := y + dy;
 if ((tmpY + r) >= LClientHeight) or ((tmpY - r) <= 0) then
 dy := random(4) - 2 - dy;
 
 x := x + dx;
 y := y + dy;
 
 BallRect := D2D1RectF(x - r + 0.5, y - r + 0.5, x + r - 0.5, y + r - 0.5);
 CanvasRenderTarget.FillRectangle(BallRect, FCanvas.Brush.Handle);
 CanvasRenderTarget.DrawRectangle(BallRect, FCanvas.Pen.Brush.Handle, FCanvas.Pen.Width, FCanvas.Pen.StrokeStyle);
 end;
 end;
 end;
 
 procedure TForm1.WMSize(var Message: TWMSize);
 var
 NewSize: TD2D1SizeU;
 begin
 NewSize := D2D1SizeU(ClientWidth, ClientHeight);
 if Assigned(FCanvas) then
 ID2D1HwndRenderTarget(FCanvas.RenderTarget).Resize(NewSize);
 inherited;
 end;
 
 end.
 |  Für diesen Beitrag haben gedankt: Symbroson
 |  |  |  
| Symbroson  
          Beiträge: 382
 Erhaltene Danke: 67
 
 Raspbian, Ubuntu, Win10
 C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
 
 | 
Verfasst: Do 09.11.17 22:49 
 
Vielen Dank TiGü!     Die Geschwindigkeit hob sich deutlich, wie vorrausgesagt.     Allerdings vertraue ich QueryPerformance mehr als dem TStopWatch - der hat mir teilweise 1000 fps angezeigt und sprang oft zwischen verschiedenen Werten hin und her, was eigentlich garnicht sein kann; QP dagegen relativ konstant 60 fps. Nur ein kleiner Mangel, der ja eig. nichts mit der Grafik zu tun hat    Danke auf jeden Fall für den bearbeiteten Code  _________________ most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
 |  |  |  
| TiGü Hält's aus hier
 Beiträge: 9
 Erhaltene Danke: 1
 
 
 
 
 | 
Verfasst: Fr 10.11.17 11:48 
 
Hinter TStopWatch stecken auch QueryPerformanceCounter und QueryPerformanceFrequency, einfach mal in die Implementierung gucken.
 Der "Fehler" liegt eher daran, weil ich nur den Aufruf von Render  gestoppt habe, aber es richtigerweise vor BeginDraw  und nach EndDraw  gehört.
 So komme ich dann auch auf rund 60 FPS. Das geht aber noch schneller bis hin zu 255-260 FPS bei mir.
 Das Problem ist, das beim Erzeugen des Rendertargets die entsprechende Option nicht gesetzt wird. 
 In TDirect2DCanvas.CreateRenderTarget  wird D2DFactory.CreateHwndRenderTarget(...)  aufgerufen. 
 Da drin als kleine Helper-Funktion D2D1HwndRenderTargetProperties(...) .
 Hier wird die TD2D1PresentOptions  leider nur auf D2D1_PRESENT_OPTIONS_NONE  gesetzt, anstatt auf D2D1_PRESENT_OPTIONS_IMMEDIATELY .
 Mit einer Interposer-Klasse kann man das Problem aber umgehen. Wenn du willst, kann ich das später mal zeigen, falls du es nicht selber rausknobelst.    Ansonsten hier meine angepasste und genauere FPS-Anzeige mit MIN und MAX (wird alle 100 Frames zurückgesetzt):
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 74:
 75:
 76:
 77:
 78:
 79:
 80:
 81:
 82:
 83:
 84:
 85:
 86:
 87:
 88:
 89:
 90:
 91:
 92:
 93:
 94:
 95:
 96:
 97:
 98:
 99:
 100:
 101:
 102:
 103:
 104:
 105:
 106:
 107:
 108:
 109:
 110:
 111:
 112:
 113:
 114:
 115:
 116:
 117:
 118:
 119:
 120:
 121:
 122:
 123:
 124:
 125:
 126:
 127:
 128:
 129:
 130:
 131:
 132:
 133:
 134:
 135:
 136:
 137:
 138:
 139:
 140:
 141:
 142:
 143:
 144:
 145:
 146:
 147:
 148:
 149:
 150:
 151:
 152:
 153:
 154:
 155:
 156:
 157:
 158:
 159:
 160:
 161:
 162:
 163:
 164:
 165:
 166:
 167:
 168:
 169:
 170:
 171:
 172:
 173:
 174:
 175:
 176:
 177:
 178:
 179:
 180:
 181:
 182:
 183:
 184:
 185:
 186:
 187:
 188:
 189:
 190:
 191:
 192:
 193:
 194:
 195:
 196:
 197:
 198:
 199:
 200:
 201:
 202:
 203:
 204:
 205:
 206:
 207:
 208:
 209:
 210:
 211:
 212:
 213:
 214:
 215:
 216:
 217:
 218:
 219:
 220:
 221:
 222:
 223:
 224:
 225:
 226:
 227:
 228:
 229:
 230:
 231:
 232:
 233:
 234:
 235:
 236:
 237:
 238:
 239:
 240:
 241:
 242:
 243:
 244:
 245:
 246:
 247:
 248:
 249:
 250:
 
 | unit Unit1;
 interface
 
 uses
 Winapi.Windows, Winapi.Messages, Vcl.Forms, Direct2D, D2D1,
 Vcl.Controls, SysUtils, System.Classes;
 
 type
 TBall = record
 x, y, dx, dy, r: integer;
 end;
 
 TGameThread = class(TThread)
 strict private
 FTThreadProcedure: TThreadProcedure;
 protected
 procedure Execute; override;
 public
 constructor Create(const AMethod: TThreadProcedure);
 end;
 
 TForm1 = class(TForm)
 procedure FormDestroy(Sender: TObject);
 private
 FRectColor: D3DCOLORVALUE;
 FBkgColor: D3DCOLORVALUE;
 FTextFormat: IDWriteTextFormat;
 FCounter: integer;
 FFPSDisplay: string;
 procedure ResetValues;
 procedure DrawTextOut(x, y: integer; const AText: string);
 procedure GenerateFPSDisplay(WatchElapsedTicks: Int64);
 public
 FGameThread: TGameThread;
 FCanvas: TDirect2DCanvas;
 FBalls: array of TBall;
 FMaxNumber: integer;
 FMaxFPS: Double;
 FMinFPS: Double;
 
 property Canvas: TDirect2DCanvas read FCanvas;
 
 procedure CreateWnd; override;
 procedure WMSize(var Message: TWMSize); message WM_SIZE;
 procedure StartRender;
 procedure Render;
 end;
 
 var
 Form1: TForm1;
 
 implementation
 
 uses
 Diagnostics;
 
 {$R *.dfm}
 
 
 constructor TGameThread.Create(const AMethod: TThreadProcedure);
 begin
 inherited Create(False);
 FTThreadProcedure := AMethod;
 end;
 
 procedure TGameThread.Execute;
 begin
 if Assigned(FTThreadProcedure) then
 begin
 while not Terminated do
 Synchronize(FTThreadProcedure);
 end;
 end;
 
 procedure TForm1.DrawTextOut(x, y: integer; const AText: string);
 var
 LayoutRect: D2D1_RECT_F;
 TextLen: integer;
 begin
 TextLen := Length(AText);
 LayoutRect := D2D1RectF(
 x + 0.5,
 y + 0.5,
 (x + TextLen * 5) - 0.5,
 (y + TextLen) - 0.5);
 
 if not Assigned(FTextFormat) then
 begin
 FTextFormat := FCanvas.Font.Handle;
 end;
 
 FCanvas.RenderTarget.DrawText(PWideChar(AText), TextLen, FTextFormat, LayoutRect, FCanvas.Brush.Handle);
 end;
 
 procedure TForm1.StartRender;
 var
 PaintStruct: TPaintStruct;
 Watch: TStopWatch;
 WatchElapsedTicks: Int64;
 begin
 BeginPaint(Handle, PaintStruct);
 try
 Watch := TStopWatch.StartNew;
 FCanvas.BeginDraw;
 try
 Render;
 
 DrawTextOut(0, 40, FFPSDisplay);
 finally
 FCanvas.EndDraw;
 Watch.Stop;
 WatchElapsedTicks := Watch.ElapsedTicks;
 GenerateFPSDisplay(WatchElapsedTicks);
 
 Application.ProcessMessages;
 end;
 finally
 EndPaint(Handle, PaintStruct);
 end;
 end;
 
 procedure TForm1.CreateWnd;
 var
 I: integer;
 LClientRect: TRect;
 LClientWidth, LClientHeight: integer;
 begin
 inherited;
 FCanvas := TDirect2DCanvas.Create(Handle);
 ResetValues;
 
 randomize;
 FMaxNumber := 1000;
 SetLength(FBalls, FMaxNumber);
 
 Winapi.Windows.GetClientRect(Self.Handle, LClientRect);
 LClientWidth := LClientRect.Width;
 LClientHeight := LClientRect.Height;
 
 for I := 1 to FMaxNumber - 1 do
 begin
 with FBalls[I] do
 begin
 r := random(10) + 1;
 x := random(LClientWidth - r - r) + r;
 y := random(LClientHeight - r - r) + r;
 dx := random(10) + 1;
 dy := random(10) + 1;
 end;
 end;
 
 FRectColor := D2D1ColorF(1, 1, 1, 1);
 FBkgColor := D2D1ColorF(0, 0, 0, 0);
 FGameThread := TGameThread.Create(Self.StartRender);
 end;
 
 procedure TForm1.FormDestroy(Sender: TObject);
 begin
 FGameThread.Free;
 end;
 
 procedure TForm1.Render;
 var
 I: integer;
 BallRect: TD2D1RectF;
 CanvasRenderTarget: ID2D1RenderTarget;
 tmpX, tmpY: integer;
 LClientRect: TRect;
 LClientWidth, LClientHeight: integer;
 begin
 CanvasRenderTarget := FCanvas.RenderTarget;
 CanvasRenderTarget.Clear(FBkgColor);
 
 ID2D1SolidColorBrush(FCanvas.Brush.Handle).SetColor(FRectColor);
 
 Winapi.Windows.GetClientRect(Self.Handle, LClientRect);
 LClientWidth := LClientRect.Width;
 LClientHeight := LClientRect.Height;
 
 for I := 0 to Length(FBalls) - 1 do
 begin
 with FBalls[I] do
 begin
 tmpX := x + dx;
 if ((tmpX + r) >= LClientWidth) or ((tmpX - r) <= 0) then
 dx := random(4) - 2 - dx;
 
 tmpY := y + dy;
 if ((tmpY + r) >= LClientHeight) or ((tmpY - r) <= 0) then
 dy := random(4) - 2 - dy;
 
 x := x + dx;
 y := y + dy;
 
 BallRect := D2D1RectF(x - r + 0.5, y - r + 0.5, x + r - 0.5, y + r - 0.5);
 CanvasRenderTarget.FillRectangle(BallRect, FCanvas.Brush.Handle);
 CanvasRenderTarget.DrawRectangle(BallRect, FCanvas.Pen.Brush.Handle, FCanvas.Pen.Width, FCanvas.Pen.StrokeStyle);
 end;
 end;
 end;
 
 procedure TForm1.GenerateFPSDisplay(WatchElapsedTicks: Int64);
 var
 TickFreq: Double;
 RealElapsedMilliseconds: Double;
 fps: Double;
 begin
 TickFreq := 10000000.0 / TStopWatch.Frequency;
 RealElapsedMilliseconds := (WatchElapsedTicks * TickFreq) / 10000;
 fps := (1000 / RealElapsedMilliseconds);
 
 if FCounter = 100 then
 begin
 ResetValues;
 end;
 
 Inc(FCounter);
 
 if fps > FMaxFPS then
 FMaxFPS := fps;
 
 if fps < FMinFPS then
 FMinFPS := fps;
 
 FFPSDisplay := Format('Current FPS: %4.3f' + sLineBreak + 'Max: %4.3f ' + sLineBreak + 'Min: %4.3f', [fps, FMaxFPS, FMinFPS]);
 end;
 
 procedure TForm1.ResetValues;
 begin
 FMaxFPS := 0;
 FMinFPS := 10000;
 FCounter := 0;
 end;
 
 procedure TForm1.WMSize(var Message: TWMSize);
 var
 NewSize: TD2D1SizeU;
 begin
 NewSize := D2D1SizeU(ClientWidth, ClientHeight);
 if Assigned(FCanvas) then
 ID2D1HwndRenderTarget(FCanvas.RenderTarget).Resize(NewSize);
 inherited;
 end;
 
 end.
 |  |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Fr 10.11.17 12:20 
 
So viele fps machen aber auch nicht unbedingt Sinn. D2D1_PRESENT_OPTIONS_IMMEDIATELY bedeutet, dass der Frame aktualisiert wird, egal ob der letzte überhaupt schon angezeigt wurde oder nicht. Man sieht den größten Teil der Frames also nicht einmal mehr.
 Im Standard wird immer erst der nächste Frame angezeigt, wenn der letzte im Display in der Anzeige ist. Da 60 Hz für einen Standardmonitor normal sind, kommt man analog auf 60 fps.
 |  |  |  |