FillRect() und BitBlt() - flackern?
-
Moin,
gibt es eine bessere Methode als FillRect und BitBlt für DoubleBufferung?
Hintergrund:
1. Ich habe eine DIBSection in der ich via WM_TIMER ein Fraktal zeichne, diese schiebe ich dann in WM_PAINT mit BitBlt() in den DC des Fensters. Soweit das DoubleBuffering.2. Jetzt muss ich den zuvor gezeichnetet Bereich löschen (schwarz machen), dies mach ich mit FillRect(). Funktioniert alles klasse, solange das Fraktal nicht mehr als 40-50% des Bildschirms einnimmt - ab dann fängst an zu flackern!
Ich vermute, dass die BitBlt() Routine ab einer bestimmten Größe nicht schnell genug ist. Immerhin werden auf meinem Laptop bis zu 3,6MB (1200 HR x 800 VR x 4 Bytes Pix.) pro Durchgang geblittet, zuvor noch ein FilleRect() in den Buffer! Wer weiß, vielleicht daher?
Folgendes funktioniert bis auf das Flackern ganz gut! Gibt es andere Lösungsvorschläge?
case WM_TIMER: switch (wParam) { case IDT_TIMER1: // maximale Ausdehnung holen xmin = ifs_st->xmin; xmax = ifs_st->xmax; ymin = ifs_st->ymin; ymax = ifs_st->ymax //////////////////////////////////////////// // Alles was zuvor gezeichnet wurde löschen // if (xmin <= xmax && ymin <= ymax) { rect.left = xmin; rect.top = ymin; rect.right = xmax + 1; rect.bottom = ymax + 1; FillRect(myBackBuffer, &rect, hbrBlack); //<------- löschen des zuvor gez. Bereichs ifs_st->xmin = ifs_st->width + 1; ifs_st->xmax = ifs_st->ymax = -1; ifs_st->ymin = ifs_st->height + 1; } ////////////////////////////////////////////////////// // Punkte des aktuellen Frames berechnen und zeichnen // memset(ifs_st->board, 0, ifs_st->widthb * ifs_st->height * sizeof(*ifs_st->board)); if (ifs_st->recurse) { recurse(ifs_st, ifs_st->width << 7, ifs_st->height << 7, ifs_st->length); } else { iterate(ifs_st, (int)(pow((float)ifs_st->lensnum, ifs_st->length))); } if (ifs_st->npoints) { drawpoints(ifs_st); } // WM_PAINT aufrufen InvalidateRect(hWnd, &rect, false); for(int i = 0; i < ifs_st->lensnum; i++){ mutate(ifs_st, &ifs_st->lenses[i]); } return 0; (... Schnipp Timer2 und Timer3 ...) }; case WM_PAINT: myDevCon = BeginPaint(hWnd, &ps); BitBlt( myDevCon, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1, myBackBuffer, xmin, ymin, SRCCOPY); EndPaint(hWnd, &ps); return 0; case WM_ERASEBKGND: return true;
-
DirectX
-
OpenGL
-
Oder das
.
-
BOOL BitBlt(
HDC hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
HDC hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
DWORD dwRop // raster operation code
);Probiere mal folgendes:
Setze nXDest, nXDest, nXSrc, nYSrc auf 0. Mach deinen BackBuffer genauso gross wie den ScreenDC.
Hatte mal das selbe Problem. BitBlt wurde langsam, als ich mit offsets rumhantiert habe.MFG
NickHappy
-
Rhombicosidodecahedron schrieb:
OpenGL
Das werde ich (irgendwann) mal versuchen! Dummerweise zeichne ich grade viel mit einzelnen Pixeln (Fraktale), daher schien mir OpenGL eigentlich kein guter Ansatz zu sein (ein Lehrbuch dazu habe ich aber schon).
Hier, hab deine Brüder und deine Schwestern gefunden gefunden:
http://thesaurus.maths.org/mmkb/gallery.html?folder=live3D
-
NickHappy schrieb:
Probiere mal folgendes:
Setze nXDest, nXDest, nXSrc, nYSrc auf 0. Mach deinen BackBuffer genauso gross wie den ScreenDC.
Hatte mal das selbe Problem. BitBlt wurde langsam, als ich mit offsets rumhantiert habe.Das hat leider nichts gebracht, flackert wie ehedem - und dann auch, wenn das Fraktal klein ist (nur nicht so auffällig unser Auge scheint da verwirrt zu sein).

-
Hast du das mal konkret überprüft ob es wirklich die BitBlt()-Funktion ist die da bremst ?
Wenn Du ne DIB benutzt, könntest du dir evtl. noch DrawDib() angucken...
Hinter InvalidateRect() würde ich sicherheitshalber noch ein UpdateWindow() packen...
-
Hast du das mal konkret überprüft ob es wirklich die BitBlt()-Funktion ist die da bremst
Ich hab bevor meine Direct3D-Zeiten begonnen haben, angefangen ein RPG zu programmieren; und zwar komplett mit BitBlt + Doublebuffering...
Die Geschwindigkeit von BitBlt() war dabei schon ein Problem ...weil es echt "radikal" geflacktert hat...
Kann echt nur DirectX bzw. OpenGL...oder eine andere GrafikLib empfehlen...
Aber....:
Ich hatte damals 1024x768 als Bildschirmauflösung und hab das Flackern "bekämpft" in dem ich den Bildschirm in Bereiche unterteilt und einzeln abgearbeitet habe...
Dadurch wurde das Programm/BitBlt schneller...Was zwar irgendwie ein Widerspruch ist aber trotzdem funktioniert hat...MfG Kuldren
-
Also, da mir DirectDraw schon immer zu hoch war, hab ich in den letzten Jahren meine Spiele und andere Grafikprogramme mit SetDIBitsToDevice sichtbar gemacht.
Egal wie viele fps du einstellst und wie langsam der Computer ist, da flackert nichts.
-
Ich meine die WM_TIMER UND WM_PAINT Nachrichten sind beides Messages die nicht an das Ende der Message-Queue gepackt werden sondern bevorzugt verarbeitet werden.
Nun könnte es sein, je nachdem wieviele Timer und mit welchem Timeout die Timer laufen, dass die WM_TIMER-Messages die WM_PAINT-Messages quasi verzögern. Ein UpdateWindow() hinter InvalidateRect() würde zumindest sicherstellen, dass WM_PAINT direkt verarbeitet wird.
-
Nanyuki schrieb:
Also, da mir DirectDraw schon immer zu hoch war, hab ich in den letzten Jahren meine Spiele und andere Grafikprogramme mit SetDIBitsToDevice sichtbar gemacht.
To repeatedly redraw a bitmap in a window, however, the application should use the BitBlt function. For example, a multimedia application that combines animated graphics with sound would benefit from calling the BitBlt function because it executes faster than SetDIBitsToDevice.
Naja, ich hab bisher eigentlich auch SetDIBitsToDevice() für schneller gehalten

Müsste man mal benchen
-
geeky schrieb:
Ich meine die WM_TIMER UND WM_PAINT Nachrichten sind beides Messages die nicht an das Ende der Message-Queue gepackt werden sondern bevorzugt verarbeitet werden.
Nun könnte es sein, je nachdem wieviele Timer und mit welchem Timeout die Timer laufen, dass die WM_TIMER-Messages die WM_PAINT-Messages quasi verzögern. Ein UpdateWindow() hinter InvalidateRect() würde zumindest sicherstellen, dass WM_PAINT direkt verarbeitet wird.Mmh, ja in diese Richtung hatte ich auch schon gedacht, aber ich stoppe den betreffenden Timer, führe meine Berechnungen aus (die in eine DIBSection Bildpunkte schreiben) und und rufe dann mit UpdateWindow() WM_PAINT auf wo ich dann als einzige Zeichenoperation eien BitBlt mache.
case WM_TIMER: switch (wParam) { case IDT_TIMER1: KillTimer(hWnd, IDT_TIMER1); // maximale Ausdehnung holen (.. schnipp ..) // Alles was zuvor gezeichnet wurde löschen (.. schnipp ..) // Punkte des aktuellen Frames berechnen und zeichnen (.. schnipp ..) //WM_PAINT aufrufen InvalidateRect(hWnd, &rect, false); UpdateWindow(hWnd); (.. schnipp ..) SetTimer(hWnd, IDT_TIMER1, delay_IDT1, NULL); return 0; (.. ganz viel Schnipp ..) case WM_PAINT: GdiFlush(); myDevCon = BeginPaint(hWnd, &ps); BitBlt( myDevCon, xmin, ymin, xmax+1, ymax+1, myBackBuffer, xmin,ymin, SRCCOPY); EndPaint(hWnd, &ps); return 0;Wenn ich das richtig verstehe, läuft der Timer doch erst wieder an, nach dem UpdateWindow() durchgeführt ist, das Programm also aus WM_PAINT zurückkehrt? Oder, wie?
Ich verstehe wirklich nicht warum das flackert? Herrjeh!
-
Wie lange braucht BitBlt() denn bei dir ?
-
geeky schrieb:
Wie lange braucht BitBlt() denn bei dir ?
Keine Ahnung! Ich habe einmal vorher GetTickCount() und einmal hinterher aufgerufen, die Differenz war IMMER 0, daher gehe ich davon aus, dass BitBlt < 1.0 ms arbeitet. Das dürfte keinesfall flackern!
Mannomann, woher kommt das dann?

Wer möchte kann ja mal selbst gucken: http://ticore.de/share/ifs.zip
Es fängt immer an zu flackern, wenn das Fraktal größer als etwa 60-70% des Bildschirms einnimmt.
-
Dein Bildschirmschoner stürzt ab bevor man etwas sieht.
-
Mit welcher Meldung?
-
Mit Problembericht senden.

-
Bei mir läufts flüssig

-
Hast Du in der WNDCLASS-Struktur bei Erzeugung der Fensterklasse einen "background brush" angegeben? Falls ja: in diesem Fall füllt das System vor jedem WM_PAINT den ungültigen Fensterbereich mit der Hintergrundfarbe, was natürlich "Flackern" bewirkt.
-
Einige kleine Änderungen:
- Nicht immer neu
SetTimer und Killtimerverwenden
- Vielleicht feste Fensterbreite einbauen
- Etwas noch an der WindowPRoc ändern
case WM_TIMER: /* Irgendetwas */ //break /* Kein Break sonst flimmer */ // Damit man keine Nachricht senden muss case WM_PAINT: /* Irgendetwas */ break; case WM_ERASEBKGND: return false; // Wichtig ! - Sonst flimmer!- Fertige "dingse"-Anzeiger gibt's doch wie Sand am Bodensee
So, ach ja:
timmix schrieb:
Rhombicosidodecahedron schrieb:
OpenGL
Das werde ich (irgendwann) mal versuchen! Dummerweise zeichne ich grade viel mit einzelnen Pixeln (Fraktale), daher schien mir OpenGL eigentlich kein guter Ansatz zu sein (ein Lehrbuch dazu habe ich aber schon).
Hier, hab deine Brüder und deine Schwestern gefunden gefunden:
http://thesaurus.maths.org/mmkb/gallery.html?folder=live3D
Ohhhh, wie schön meine ganze Familie ... so groß ... ich könnte heulen ... *heul* * heul* ... ah - da der alte Tedraeder - immer noch da ... und ...
Mit freundlichen Grüßen und nicht ganz (garnicht) ehrich gewesend
Rhombicosidodecahedron