#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; const int r_shift = 16; const int g_shift = 8; const int b_shift = 0; class UIWin { public: UIWin(const string _name, const int _x, const int _y, const int _w, const int _h); ~UIWin(); const string & get_name() const { return name; }; void present(const bool _output_debug); void fill(const int _colour, const bool _output_debug); private: unsigned int window_id; SDL_Window *window; SDL_Renderer *renderer; SDL_Texture *texture; SDL_Surface *surface; int x, y, w, h; string name; }; UIWin::UIWin(const string _name, const int _x, const int _y, const int _w, const int _h) { name = _name; x = _x; y = _y; w = _w; h = _h; window = NULL; renderer = NULL; texture = NULL; surface = NULL; fprintf(stderr, "========\nCreate window '%s', size = %d x %d\n", name.c_str(), w, h); window = SDL_CreateWindow( name.c_str(), x, y, w, h, 0 //SDL_WINDOW_SHOWN - NOT needed, as this is only for SDL_Get_WindowFlags ); if ( ! window ) { fprintf(stderr, "UIWin constructor failed to SDL_CreateWindow (%s), size = %d x %d\n", SDL_GetError(), w, h); return; } window_id = SDL_GetWindowID(window); fprintf(stderr, "Create renderer\n"); renderer = SDL_CreateRenderer( window, -1, // Possibly don't need the SDL_RENDERER_ACCELERATED flag as it's probably implicit, // but set it for good measure anyway. SDL_RENDERER_ACCELERATED ); if ( ! renderer ) { fprintf(stderr, "UIWin constructor failed to SDL_CreateRenderer (%s)\n", SDL_GetError()); return; } // We only want simple copying for the window texture renderer. SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); fprintf(stderr, "Create texture\n"); texture = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h ); if ( ! texture ) { fprintf(stderr, "UIWin constructor failed to SDL_CreateTexture (%s), size = %d x %d\n", SDL_GetError(), w, h); return; } fprintf(stderr, "Create surface\n"); surface = SDL_CreateRGBSurface( 0, //SDL_SWSURFACE w, h, 32, 0xff << r_shift, 0xff << g_shift, 0xff << b_shift, 0 ); if ( ! surface ) { fprintf(stderr, "UIWin constructor failed to SDL_CreateRGBSurface (%s), size = %d x %d\n", SDL_GetError(), w, h); return; } } UIWin::~UIWin() { fprintf(stderr, "UIWin destructor '%s'", name.c_str()); if (surface) { fprintf(stderr, "freeing surface %p\n", surface); SDL_FreeSurface(surface); fprintf(stderr, "surface freed\n"); } if (texture) { fprintf(stderr, "freeing texture %p\n", texture); SDL_DestroyTexture(texture); fprintf(stderr, "texture freed\n"); } if (renderer) { fprintf(stderr, "freeing renderer %p\n", renderer); SDL_DestroyRenderer(renderer); fprintf(stderr, "renderer freed\n"); } if (window) { fprintf(stderr, "freeing window %p\n", window); SDL_DestroyWindow(window); fprintf(stderr, "window freed\n"); } } void UIWin::present(const bool _output_debug) { // Handle the surface not existing in case there was a problem. if ( ! renderer || ! texture || ! surface ) return; int r; if (_output_debug) fprintf(stderr, "Update '%s'\n", name.c_str()); r = SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); if (r) fprintf(stderr, "Update error '%s' %d '%s'", name.c_str(), r, SDL_GetError()); // Reset render blend mode to simple copy and clip rectangle to none in case // something else rendered after the main surface last frame and didn't reset it. r = SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); if (r) fprintf(stderr, "Blend Mode error '%s' %d '%s'", name.c_str(), r, SDL_GetError()); r = SDL_RenderSetClipRect(renderer, NULL); if (r) fprintf(stderr, "Clip rect error '%s' %d '%s'", name.c_str(), r, SDL_GetError()); if (_output_debug) fprintf(stderr, "Clear '%s'\n", name.c_str()); r = SDL_RenderClear(renderer); if (r) fprintf(stderr, "Clear error '%s' %d '%s'", name.c_str(), r, SDL_GetError()); if (_output_debug) fprintf(stderr, "Copy '%s'\n", name.c_str()); r = SDL_RenderCopy(renderer, texture, NULL, NULL); if (r) fprintf(stderr, "Copy error '%s' %d '%s'", name.c_str(), r, SDL_GetError()); if (_output_debug) fprintf(stderr, "Present '%s'\n", name.c_str()); SDL_RenderPresent(renderer); } void UIWin::fill(const int _colour, const bool _output_debug = true) { if ( ! surface ) return; SDL_RendererInfo info; SDL_GetRendererInfo(renderer, &info); if (_output_debug) fprintf(stderr, "%s: Fill %s, size = %d x %d\n", info.name, name.c_str(), w, h); SDL_FillRect(surface, NULL, _colour); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // CLI: If the first argument starts with 's' then it uses the // software renderer and so the problem goes away. int main(int argc, char **argv) // Need this for link to work for SDL_main { if (argc >= 2) SDL_SetHint(SDL_HINT_RENDER_DRIVER, argv[1]); if (SDL_Init(SDL_INIT_EVERYTHING ) != 0) { fprintf(stderr, "Could not initialise SDL (%s)\n", SDL_GetError()); exit(1); } // We want this on for this test as coming out of it illustrates the problem. SDL_EnableScreenSaver(); UIWin *main_window = new UIWin("Main window", 400,200, 800,600); main_window->fill(0x4080ff, true); main_window->present(true); SDL_Event sdl_event; bool quit = false; timeval last_time; gettimeofday(&last_time, NULL); while ( ! quit ) { if (SDL_PollEvent(&sdl_event)) { switch (sdl_event.type) { case SDL_QUIT: quit = true; break; case SDL_KEYDOWN: if (sdl_event.key.keysym.sym == 32) SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, 2); default: break; } } int cr = rand() & 0xff; int cg = rand() & 0xff; int cb = rand() & 0xff; main_window->fill((cr << r_shift) | (cg << g_shift) | (cb << b_shift), true); main_window->present(false); timeval t; gettimeofday(&t, NULL); int time_ms = (t.tv_sec - last_time.tv_sec) * 1000 + (t.tv_usec - last_time.tv_usec) / 1000; fprintf(stderr, "======== Loop time %d\n", time_ms); last_time = t; } delete main_window; SDL_Quit(); }