Как я могу избежать того, что моя частота кадров застревает в окне узкого места?
- У меня есть одно окно, которое работает со скоростью 10 кадров в секунду, когда отображается один.
- У меня есть другое окнос частотой 60 кадров в секунду при одном отображении.
Моя проблема в том, что я получаю 10 кадров в секунду при отображении двух окон вместе.
Я ожидал, что быстрое окно будетбыстрее, чем медленное окно, но оба окна получают одинаковую медленную скорость FPS при рисовании одновременно.
Я ожидал получить около 5 кадров в секунду для медленного и 30 кадров в секунду для быстрого окна.
Попробуйте использовать функцию timeSetEvent () вместо SetTimer (), и оно будет рисовать только медленное окно, если оно установлено с крошечным временем.
Попробуйте пользовательское сообщение рисования с помощью timeSetEvent (TIME_ONESHOT), которое даету меня такой же медленный результат, как и у WM_TIMER.
Добавлены кнопки включения / выключения, чтобы легко видеть, что делает FPS без изменения кода.
Как я понимаю, быстрое окно - это ожиданиеВ поисках медленного окна, чтобы закончить свою краску.Очень большое спасибо за вашу помощь ...
Здесь полный код main.c
#include <stdio.h>
#include <string.h>
#include <windows.h>
#define TIMER_WND0 0
#define TIMER_WND1 1
#define OFF_ON_WND0 0
#define OFF_ON_WND1 1
LRESULT CALLBACK procWndMain(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK procWnd0(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK procWnd1(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst = NULL;
HWND hWndMain = NULL;
HWND hWnd0 = NULL;
HWND hWnd1 = NULL;
int offOnWnd0 = 1;
int offOnWnd1 = 1;
void uint2str(char *buf, unsigned int x) {
sprintf(buf, "%u", x);
}
double millitimeTick(void) {
return GetTickCount()/1000.0;
}
int randInt(int a, int b) {
return rand()%(b-a) +a;
}
void createWindowClass(HINSTANCE hInstance, WNDPROC wndProc, LPCSTR lpszClassName, int bg, unsigned int style) {
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = style;
wc.lpfnWndProc = wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszClassName;
if(bg) { wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); }
else{ wc.hbrBackground = NULL; }
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, lpszClassName, "Error RegisterClassEx", MB_OK);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszArg, int nCmdShow) {
(void)hPrevInst;
(void)lpszArg;
MSG message = {0};
hInst = hInstance;
createWindowClass(hInstance, procWndMain, "procWndMain", 1, CS_HREDRAW|CS_VREDRAW);
hWndMain = CreateWindowEx(
WS_EX_CONTROLPARENT,
"procWndMain",
"multiWndPaint",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
(int)CW_USEDEFAULT, (int)CW_USEDEFAULT,
950, 370,
HWND_DESKTOP,
NULL,
hInstance,
NULL
);
ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);
while(GetMessage(&message, NULL, 0, 0)) {
TranslateMessage(&message);
DispatchMessage(&message);
}
UnregisterClass("procWndMain", hInst);
return (int)message.wParam;
}
LRESULT CALLBACK procWndMain(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE: {
createWindowClass(hInst, procWnd0, "procWnd0", 1, 0);
hWnd0 = CreateWindowEx(
0,
"procWnd0",
"",
WS_CHILD | WS_VISIBLE | WS_DLGFRAME,
20, 22,
440, 300,
hwnd,
NULL,
NULL,
NULL
);
ShowWindow(hWnd0, SW_SHOW);
createWindowClass(hInst, procWnd1, "procWnd1", 1, 0);
hWnd1 = CreateWindowEx(
0,
"procWnd1",
"",
WS_CHILD | WS_VISIBLE | WS_DLGFRAME,
480, 22,
440, 300,
hwnd,
NULL,
NULL,
NULL
);
ShowWindow(hWnd1, SW_SHOW);
HWND btnWnd0 = CreateWindowEx(0, "BUTTON", "Off/On Wnd0",
WS_CHILD | WS_VISIBLE,
20, 0, 104, 24,
hwnd,
(HMENU)OFF_ON_WND0,
NULL, NULL
);
ShowWindow(btnWnd0, SW_SHOW);
HWND btnWnd1 = CreateWindowEx(0, "BUTTON", "Off/On Wnd1",
WS_CHILD | WS_VISIBLE,
480, 0, 104, 24,
hwnd,
(HMENU)OFF_ON_WND1,
NULL, NULL
);
ShowWindow(btnWnd1, SW_SHOW);
break;
}
case WM_COMMAND: {
if(LOWORD(wParam) == OFF_ON_WND0) {
if(offOnWnd0) {
KillTimer(hWnd0, TIMER_WND0);
offOnWnd0 = 0;
}
else{
SetTimer(hWnd0, TIMER_WND0, 1, NULL);
offOnWnd0 = 1;
}
}
else if(LOWORD(wParam) == OFF_ON_WND1) {
if(offOnWnd1) {
KillTimer(hWnd1, TIMER_WND1);
offOnWnd1 = 0;
}
else{
SetTimer(hWnd1, TIMER_WND1, 1, NULL);
offOnWnd1 = 1;
}
}
break;
}
case WM_DESTROY: {
KillTimer(hWnd0, TIMER_WND0);
KillTimer(hWnd1, TIMER_WND1);
UnregisterClass("procWnd0", hInst);
UnregisterClass("procWnd1", hInst);
PostQuitMessage(0);
break;
}
default: {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
return 0;
}
void wndInfo(HDC *hdcMem, char *name, unsigned int frame, unsigned int frameRate, unsigned int frameMax) {
char buf64[24];
char textInfo[256];
RECT rect = {0};
strcpy(textInfo, name);
strcat(textInfo, "\n");
uint2str(buf64, frame);
strcat(textInfo, "Frame : ");
strcat(textInfo, buf64);
uint2str(buf64, frameRate);
strcat(textInfo, "\nFPS : ");
strcat(textInfo, buf64);
uint2str(buf64, frameMax);
strcat(textInfo, "\nMax : ");
strcat(textInfo, buf64);
HBRUSH brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
rect.right = 100;
rect.bottom = 70;
FillRect(*hdcMem, &rect, brush);
rect.left = 4;
rect.top = 2;
rect.right = 100;
rect.bottom = 70;
SetTextColor(*hdcMem, RGB(0,0,255));
DrawText(*hdcMem, textInfo, -1, &rect, DT_NOCLIP|DT_NOPREFIX);
DeleteObject(brush);
}
LRESULT CALLBACK procWnd0(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static double timestamp = 0;
static unsigned int frame = 0;
static unsigned int frameRate = 0;
static unsigned int frameMax = 0;
switch(msg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect = {0};
GetClientRect(hwnd, &rect);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP bmpMem = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
HBITMAP bmpMemOld = SelectObject(hdcMem, bmpMem);
SetBkMode(hdcMem, TRANSPARENT);
SetTextColor(hdcMem, RGB(255,255,255));
HBRUSH brush = (HBRUSH)GetStockObject(GRAY_BRUSH);
FillRect(hdcMem, &rect, brush);
POINT point = {0};
size_t i = 0;
size_t len = 99999;
while(i < len) {
point.x = randInt(-rect.right*8, rect.right*8);
point.y = randInt(-rect.bottom*8, rect.bottom*8);
TextOut(hdcMem, point.x, point.y, "foobar", 6);
i++;
}
frame++;
double timestampCur = millitimeTick();
if(timestampCur > timestamp+1.0) {
timestamp = timestampCur;
frameRate = frame;
if(frame > frameMax) { frameMax = frame; }
frame = 0;
}
wndInfo(&hdcMem, "Wnd0", frame, frameRate, frameMax);
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
DeleteObject(brush);
SelectObject(hdcMem, bmpMemOld);
DeleteDC(hdcMem);
DeleteObject(bmpMem);
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND: {
break;
}
case WM_TIMER: {
if(wParam == TIMER_WND0) {
InvalidateRect(hwnd, NULL, TRUE);
}
break;
}
case WM_CREATE: {
SetTimer(hwnd, TIMER_WND0, 1, NULL);
break;
}
default: {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
return 0;
}
LRESULT CALLBACK procWnd1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static double timestamp = 0;
static unsigned int frame = 0;
static unsigned int frameRate = 0;
static unsigned int frameMax = 0;
switch(msg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect = {0};
GetClientRect(hwnd, &rect);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP bmpMem = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
HBITMAP bmpMemOld = SelectObject(hdcMem, bmpMem);
SetBkMode(hdcMem, TRANSPARENT);
SetTextColor(hdcMem, RGB(255,255,255));
HBRUSH brush = (HBRUSH)GetStockObject(GRAY_BRUSH);
FillRect(hdcMem, &rect, brush);
POINT point = {0};
size_t i = 0;
size_t len = 999;
while(i < len) {
point.x = randInt(-rect.right*8, rect.right*8);
point.y = randInt(-rect.bottom*8, rect.bottom*8);
TextOut(hdcMem, point.x, point.y, "foobar", 6);
i++;
}
frame++;
double timestampCur = millitimeTick();
if(timestampCur > timestamp+1.0) {
timestamp = timestampCur;
frameRate = frame;
if(frame > frameMax) { frameMax = frame; }
frame = 0;
}
wndInfo(&hdcMem, "Wnd1", frame, frameRate, frameMax);
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
DeleteObject(brush);
SelectObject(hdcMem, bmpMemOld);
DeleteDC(hdcMem);
DeleteObject(bmpMem);
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND: {
break;
}
case WM_TIMER: {
if(wParam == TIMER_WND1) {
InvalidateRect(hwnd, NULL, TRUE);
}
break;
}
case WM_CREATE: {
SetTimer(hwnd, TIMER_WND1, 1, NULL);
break;
}
default: {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
return 0;
}