![]() |
GraphicsContainer
Zum zeichnen von GDI+ verwende ich im Moment als Container ein einfaches Window.
Das Problem dabei ist das dann nur die CPU ausgelastet wird. Kann man nicht einfach OpenGL in einem Mix mit GDI+ verwenden und höher lastige Zeichnungsoperationen darauf ausführen? In dem Fall würde man auch die GPU in Anspruch nehmen. Oder gibt es eine Möglichkeit beim zeichnen direkt die GPU zu vereinnahmen? Was müsste ich dafür tun? Ich wüsste sonst keine andere Möglichkeit die CPU last herunter zu schrauben. Textzeichnen funktioniert gut auf einen OpenGL Window mit GDI+ siehe TextSuite. Ich habe im Moment bei einer 26,6MB großen mit 120 Frames ausgestatteten APNG eine Auslastung von 25%. Das ist einfach zu viel. gruss |
AW: GraphicsContainer
Zitat:
Denn GDI+ nutzt normalerweise bereits Hardware rendering. Vielleicht wird die Zeit ja auch für das Aufbereiten der Bilder gebraucht. |
AW: GraphicsContainer
Zitat:
Zu den Frameraten kann ich jetzt nichts sagen hab da nichts implementiert. gruss |
AW: GraphicsContainer
Hier mal die Funktion.
Keine Ahnung was da soviel CPU last fabriziert
Delphi-Quellcode:
gruss
function TAnimatePng.DrawPngFrame(PngImage: Cardinal; FrameNum: integer; DC: HDC): integer;
var PngGraphics: Cardinal; PngFrameRect: TGPRectF; FrameWidth: integer; FrameHeight: integer; srcUint: GpUnit; rc: TRect; rw: TRect; TargetRatio: Double; IsRelationship: Double; w, h, X, Y: integer; hTempDC: HDC; hBitmapTemp: HBitmap; hBitmapOld: HBitmap; UseBackColor: ARGB; begin Result := 1; srcUint := UnitPixel; hTempDC := CreateCompatibleDC(DC); If GDIP_GetImageBounds(PngImage, @PngFrameRect, srcUint) = OK then begin GetWindowRect(GraphicContainer, rw); GetClientRect(GraphicContainer, rc); hBitmapTemp := SKAERO_CreateDIBSection(hTempDC, rc.Right, rc.Bottom, 32); hBitmapOld := SelectObject(hTempDC, hBitmapTemp); UseBackColor := MakeColor(32, 0, 100, 128); GDIP_DrawGradientVertical(hTempDC, 1, 1, rc.Right, rc.Bottom, UseBackColor, UseBackColor); if GDIP_CreateFromHDC(hTempDC, PngGraphics) = OK then begin try // Gif Zentrieren if gp.FrameCount = 0 then FrameWidth := round(PngFrameRect.Width) else FrameWidth := round(PngFrameRect.Width) div gp.FrameCount; FrameHeight := round(PngFrameRect.Height); if (FrameWidth > rc.Right) or (FrameHeight > rc.Bottom) then begin IsRelationship := FrameWidth / FrameHeight; TargetRatio := rc.Right / rc.Bottom; if IsRelationship > TargetRatio then begin w := rc.Right; h := rc.Right div round(IsRelationship); end else if IsRelationship < TargetRatio then begin h := rc.Bottom; w := rc.Bottom * round(IsRelationship); end else begin w := rc.Right; h := rc.Bottom; end; end else begin w := FrameWidth; h := FrameHeight; end; X := (rc.Right - w) div 2; Y := (rc.Bottom - h) div 2; // einzelnes Bild auf Graphicsobjekt zeichnen if gp.FrameCount = 0 then GDIP_DrawImageRect(PngGraphics, PngImage, X, Y, w, h) else GDIP_DrawImageRectRectI(PngGraphics, PngImage, X, Y, w, h, w * integer (CurPngPlayInfo.PngFrame) - w, 0, w, h, 2, nil, False, nil); CurPngPlayInfo.PngDelay := TimerInterval; CurPngPlayInfo.PngFrame := FrameNum + 1; CurPngPlayInfo.PngLoop := LoopCount - 1; CurPngPlayInfo.PngLoops := FrameLoopCount; // Ausgabe von Infos ShowPngPlayInfos(CurPngPlayInfo); // Nur Rendern wenn die Classe AnimatePng initialisiert ist if Assigned(AnimatePng) then begin w := 150; h := 60; // String Zentrieren case Length(IntToStr(AnimatePng.TimerInterval)) of 1: X := (rc.Right - w) div 2 + 45; 2: X := (rc.Right - w) div 2 + 30; 3: X := (rc.Right - w) div 2 + 10; end; Y := rc.Bottom - h; rw.Right := w; rw.Bottom := h; rw.Left := X; rw.Top := Y; if not(gp.FrameCount = 0) and (Alpha > 0) then // String zeichnen GDIP_DrawTextToDC(hTempDC, IntToStr(AnimatePng.TimerInterval), rw, MakeColor (Alpha, 3, 123, 250), 'LCDDisplayCapsSSK', 60, FontStyleBold, -1, 0, LCDDisplayCapsSSK); end; BitBlt(DC, rc.Left, 0, rc.Right, rc.Bottom, hTempDC, rc.Left, 0, SRCCOPY); finally // Graphicsobjekt löschen GDIP_DeleteGraphics(PngGraphics); SelectObject(hTempDC, hBitmapOld); DeleteObject(hBitmapTemp); DeleteDC(hTempDC); end; end; end; end; |
AW: GraphicsContainer
Und wie oft wird diese Methode aufgerufen? Nur so oft wie nötig, sprich durch die Framerate vorgegeben, hoffe ich?
Jedenfalls machst du da ja relativ viel. Verglichen mit der Bibliothek, die wir uns angeschaut hatten, deutlich mehr glaube ich. Dort läuft es mit Hardwarebeschleunigung jedenfalls mit der CPU bei unter 5%. Zumindest mit meiner Testanimation. Ziel muss sein möglichst viel vorzubereiten und nicht so viel bei jedem Frames zu machen. Ein Profiling Tool könnte helfen um zu sehen wo wie viel Zeit liegen bleibt. Es kommt natürlich auch auf Betriebssystem und Grafikkartentreiber an, aber ab Windows 7 sollte die Hardware auch bei GDI immer direkt benutzt werden sofern Aero aktiv ist. (Ohne wird das Rendering generell zu einem großen Teil von der CPU übernommen.) Da aber GDI nicht komplett in der Grafikkarte arbeitet, ist es trotzdem deutlich langsamer als Direct2D usw., genauer ist das hier dokumentiert: ![]() Deshalb wird GDI für neue Anwendungen ja auch nicht mehr empfohlen. In aktuellen Delphiversionen gibt es aber einen schnellen TDirect2DCanvas als schnelle Lösung, der natürlich erst ab Windows 7 funktioniert (vorher fehlten in Windows die Grundlagen dafür): ![]() |
AW: GraphicsContainer
Zitat:
Zitat:
Das kann man nur dann behaupten wenn man unter fast gleichen Bedingungen vergleicht. Zitat:
Das sind doch hauptsächlich nur Ermittlungen über die Position des Bildes im Bild und die Position auf dem Container wo gezeichnet wird. Der Container im eigentlichen sinne ein Window macht nichts. Er ist nur zum halten des DC zuständig.. bzw. das hole ich mir von dort. Das Bild wird im Speicher abgelegt und aus dem Speicher heraus gezeichnet. Was CPU lastig ist ist dies hier
Delphi-Quellcode:
macht etwa 1 > 2% aus.// Ausgabe von Infos ShowPngPlayInfos(CurPngPlayInfo); Ich baue mal ne FPS Anzeige ein. gruss |
AW: GraphicsContainer
Zitat:
Zitat:
|
AW: GraphicsContainer
Zitat:
Wie groß ist die denn? MB Zitat:
schließlich müssen diese ja auch irgendwie aufs Papier gebracht werden. Oder zeichnen die sich alleine ? Also mit dem dicken Teil liege ich bei 12 Frames und einer FrameDimensionTime von 30ms (Wie lange ein Frame gezeichnet wird) Irgendwas ist da im argen. Das kann ich nicht so lassen (Aber wie ändern) Denke mal das ist so richtig.. TimerInterval = ms 1000 1 Sekunde 1000 / 60 = 16.666 1 ms = 16
Delphi-Quellcode:
FPScount := GetTickCount + 1000 + (TimerInterval * 16);
Der TimerInterval richtet sich nach der im APNG abgelegten FrameDimensionTime Wie lange ein Frame abgespielt wird. Bei Gif kann jedes Frame eine unterschiedliche länge haben bei APNG sind sie alle gleich. Zitat:
Oder kannst du da im Code etwas erkennen? gruss |
AW: GraphicsContainer
Zitat:
Die ist nur 24 MiB groß. Die enthaltene Grafik ist auch nicht sonderlich aufwendig. Dass das an der Geschwindigkeit beim Zeichnen so viel ändert, vermute ich allerdings nicht. |
AW: GraphicsContainer
Zitat:
Nur mit meinem Format (Programm) wird sie denke ich mal nicht abspielbar sein. Wenn du normale APNG Dateien abspielst hast du kein Standbild sie werden sofort animiert. Ich habe das Format dahingehen modifiziert so das du das APNG als normales Bild anzeigen kannst. Animiert wird es dann nur mit dieser Anwendung wenn du die Datei mit dem Konvertierungs Tool (GIFtoAPNG) in meinen Archiv erstellt hast. Ich habe aber jetzt immer noch das Problem das ich nicht weiß wie man das noch optimieren kann. ;) gruss |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz