Probleme mit BitBlt
-
Hallo Leute, ich habe folgendes Problem. Das Programm läuft noch mit ca. 3 Frames pro Sekunde. Was soll denn das? Wenn ich die Funktion "BitBlt" auskommentiere, dann habe ich gegen 800'000 Frames pro Sekunde! Was noch eigenartiger ist: Wenn ich gewisse Zeichenoperationen wie Rectangle, Ellipse usw. anwende, steigt die Framerate wieder auf ca. 500 Frames pro Sekunde. Dies habe ich auf mehreren Computern mit demselben Resultat getestet...
Hat jemand von euch eine Ahnung, was das soll? Ich währe euch echt Dankbar!!!// ***************************** include the needed header - files **************************** // -------------------------------------------------------------------------------------------- #include <windows.h> // WinApi #include <math.h> // arithmetic functions // -------------------------------------------------------------------------------------------- // ******************************************************************************************** // ******************************** pre - compiler instructions ******************************* // -------------------------------------------------------------------------------------------- #define WIN32_LEAN_AND_MEAN // ******************************************************************************************** // ***************** define programm - parameters as pre - compiler constants ***************** // ------------------------------------ window - parameters ----------------------------------- #define CLS_NAME "Kyrobreak2D" // name of the class #define WND_NAME "Kyrobreak2D (C) 2004 Kyrosoft" // name of the window #define WND_STYLE WS_BORDER|WS_SYSMENU|WS_VISIBLE // style of the window #define DEFAULT CW_USEDEFAULT // default // -------------------------------------------------------------------------------------------- // ******************************************************************************************** // ********************************** the window - functions ********************************** // --------------------- the callback - function for all window - messages -------------------- long __stdcall WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){ // a switch for separating the different window - messages switch(uMsg){ case WM_PAINT: // validate the entire rect to avoid endless paint - messages ValidateRect(hWnd,0x00); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: // return the default window - procedure return DefWindowProc(hWnd,uMsg,wParam,lParam); } } // -------------------------------------------------------------------------------------------- // ------------------- the main - function and entry - point of the programm ------------------ int __stdcall WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd){ // WinApi - variables MSG msg = {0}; HWND hWnd = 0; RECT aeClient = {0}; // variables for creating a backbuffer - system HDC hDcFrontBuf,hDcBackBuf; HBITMAP hBmpBackBuf; // define the behaviour of the window WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); wc.lpszClassName = CLS_NAME; wc.hInstance = hInst; wc.style = CS_OWNDC; //wc.hIcon = wc.hIconSm = LoadIcon(hInst,MAKEINTRESOURCE(IDC_KYROBREAK2D)); wc.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)); wc.hCursor = LoadCursor(0,IDC_ARROW); wc.lpfnWndProc = &WndProc; RegisterClassEx(&wc); // create, messure and show a new window hWnd = CreateWindowEx(0,CLS_NAME,WND_NAME,WND_STYLE,DEFAULT,DEFAULT,640,480,0,0,hInst,0x00); GetClientRect(hWnd,&aeClient); ShowWindow(hWnd,nShowCmd); UpdateWindow(hWnd); // create a backbuffer for drawing to avoid flackering hDcFrontBuf = GetDC(hWnd); hDcBackBuf = CreateCompatibleDC(hDcFrontBuf); hBmpBackBuf = CreateCompatibleBitmap(hDcFrontBuf,aeClient.right,aeClient.bottom); SelectObject(hDcBackBuf,hBmpBackBuf); // start a message - loop while(true){ // check if there is a window - message wich has to be processed if(PeekMessage(&msg,0,0,0,PM_REMOVE)){ // escape the message - loop if the message was WM_QUIT if(msg.message == WM_QUIT) break; // translate and dispatch the message TranslateMessage(&msg); DispatchMessage(&msg); } // otherwise there is time to calculate the next scene else{ // erase the content of the backbuffer by filling with black BitBlt(hDcBackBuf,0,0,aeClient.right,aeClient.bottom,0,0,0,BLACKNESS); // some draw operations // swap the content of the backbuffer to the front - buffer BitBlt(hDcFrontBuf,0,0,aeClient.right,aeClient.bottom,hDcBackBuf,0,0,SRCCOPY); } } // delete the bitmap - surface, the backbuffer and release the acquired front - buffer DeleteObject(hBmpBackBuf); DeleteDC(hDcBackBuf); ReleaseDC(hWnd,hDcFrontBuf); // relay the return - value to the environment - system return msg.wParam; } // -------------------------------------------------------------------------------------------- // ********************************************************************************************
-
Um so größer die Bitmap um so langsamer wird BitBlt und um so öffter groß geblittet wird, wird es noch langsamer.
Um den Backbuffer zu löschen benutze mal FillRect()
-
Mit ist schon klar, dass das blitten von grossen Bitmaps langsamer dauert als das blitten von kleineren Bitmaps. Doch wieso steigt die Framerate wieder, nachdem ich einige zusätzliche Zeichenoperationen durchgeführt habe???
-
Jetzt habe ich das erstmal Verstanden :p
Diesen Effeckt konnte ich schon oft beobachten und das Verhalten kann ich auch nur Vermuten durch meine Beobachtungen.
Vermutung:
Ich habe eine Farbtiefe von 32Bit, also ist das Fenster entsprechend so gezeichnet, wenn ich nun eine große Bitmap mit einer Tiefe von Vermutlich 24Bit auf dieses Fenster Blitte, welche nur aus Nullen besteht, also jedes Byte 0 ist, muß BitBlt erst Feststellen ob es 24Bit und nicht 32Bit ist damit es nach den größen Angaben passt, wurde aber auf die Bitmap gezeichnet, so weiß BitBlt das dieser DeviceContex jene Größe und Farbtiefe hat und muß dieses nicht erst identifizieren.
Würdest du z.B. nicht komplet auf einmal blitten sondern das unterteilen in 8x6 Kacheln, so würde es schneller sein da bei der ersten kachel schneller eine Identifizierung durchgeführt wird und bei den nächsten nicht mehr.
Oder anders gesagt, BitBlt hat Probleme um so mehr 0én vorhanden sind.
Deswegen empfehle ich FillRect() da dabei mit einem HBrush gezeichnet wird und somit die Bitmap eindeutig ist, BitBlt blittet einfach nur 0én rein.Ob das nun tatsächlich in diesem Zusammenhang steht oder nicht, kann ich nicht sagen, aber eins ist Gewiss, je mehr 0én, bzw. um so größer ein "leeres" Bild um so langsamer wird es (46-48ms bei mir) lade ich eine "bunte" Bitmap und blitte diese ständig, als zu löschen, dauert es nur paar Millisekunden.