Thank You!
Yes, it explains. But is it possible to reduce CPU usage? Additional SDL_Delay reduces CPU usage, bot not to 0 and application becomes not so responsive. Solution with wait/signal a condition variable requires additional initialized thread which will listen for events actually by the same manner like in the main loop, so it seems like I will get 1-2% CPU usage, not from main thread but from a background thread. I noticed I nice functions SDL_AddEventWatch/SDL_SetEventFilter but seems like they are called from the same thread (at least if the following code does not contain a critical error):
#include <stdio.h>
#include <SDL2/SDL.h>
#define WIN_H 300
#define WIN_W 400
enum error {
EINIT = 1,
EWINDOW,
ERENDER,
EMUTEX,
ECOND,
};
typedef struct {
SDL_mutex* mutex;
SDL_cond* cond;
} condition_t;
int onevent(void* userdata, SDL_Event* event) {
condition_t* c = (condition_t*)userdata;
if (c) {
printf("[%ld] %s\n", SDL_ThreadID(), "signaling event ...");
SDL_LockMutex(c->mutex);
SDL_CondSignal(c->cond);
SDL_UnlockMutex(c->mutex);
printf("[%ld] %s\n", SDL_ThreadID(), "signaling event ok");
}
return 1;
}
void render(SDL_Renderer* renderer, SDL_Surface* screen) {
SDL_Texture* scene = SDL_CreateTextureFromSurface(renderer, screen);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, scene, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_DestroyTexture(scene);
}
int main(int argc, char* argv[]) {
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Surface* screen = NULL;
SDL_mutex* mutex = NULL;
SDL_cond* cond = NULL;
int status = 0;
do {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
status = EINIT;
break;
}
window = SDL_CreateWindow(
"Demo EventLoop",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WIN_W,
WIN_H,
SDL_WINDOW_RESIZABLE);
if (!window) {
status = EWINDOW;
break;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
status = ERENDER;
break;
}
screen = SDL_CreateRGBSurface(0, WIN_W, WIN_H, 32, 0, 0, 0, 0);
if (!screen) {
break;
}
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
mutex = SDL_CreateMutex();
if (!mutex) {
status = EMUTEX;
break;
}
cond = SDL_CreateCond();
if (!cond) {
status = ECOND;
break;
}
condition_t c = { .mutex = mutex, cond = cond };
// SDL_SetEventFilter(onevent, &c);
SDL_AddEventWatch(onevent, &c);
SDL_LockMutex(mutex);
render(renderer, screen);
while (1) {
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
break;
}
} else {
printf("[%ld] %s\n", SDL_ThreadID(), "waiting for event ...");
SDL_CondWaitTimeout(cond, mutex, 100);
printf("[%ld] %s\n", SDL_ThreadID(), "waiting for event ok");
}
render(renderer, screen);
}
SDL_UnlockMutex(mutex);
// SDL_Event e;
// while (SDL_WaitEvent(&e)) {
// if (e.type == SDL_QUIT) {
// break;
// }
// SDL_Delay(50);
// }
} while (0);
if (cond) {
SDL_DestroyCond(cond);
}
if (mutex) {
SDL_DestroyMutex(mutex);
}
if (screen) {
SDL_FreeSurface(screen);
}
if (renderer) {
SDL_DestroyRenderer(renderer);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
return status;
}