Framerate drops, tearing appears when making SDL window resizable - c

I just moved from SDL 1.2 to SDL 2.0 and I initially enjoyed similar performance (65+ FPS), then added Vsync in the renderer options and enjoyed a smooth 60 FPS with no tearing, then I added the flag SDL_WINDOW_RESIZABLE and the framerate dropped a lot (40 FPS without Vsync, 30 FPS with) and tearing appeared even with Vsync and side-scrolling became quite jittery. Whether or not I do anything to handle the resize event doesn't change anything. What am I doing wrong?
I'm using SDL 2.0.3 on VS2010 compiling in 64 bits. Here's the relevant code:
// This creates the window and everything associated with it
void graphics_init(srgb_t **sfb)
{
static int init=1;
if (init)
{
init = 0;
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_AUDIO);
}
window = SDL_CreateWindow ( VERSION, // window title
SDL_WINDOWPOS_UNDEFINED, // initial x position
SDL_WINDOWPOS_UNDEFINED, // initial y position
0, // width, in pixels
0, // height, in pixels
SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED); // flags
SDL_GetWindowSize(window, &kW, &kH);
if (window == NULL)
{
fprintf(stderr, "Could not create window: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, kW, kH);
*sfb = calloc (kW*kH, sizeof(srgb_t));
}
int main()
{
graphics_init(&sfb);
while (exit_flag==0)
{
... // main loop stuff that fills my buffer sfb
// Blits sfb buffer to screen
SDL_UpdateTexture(texture, NULL, sfb, kW * sizeof(srgb_t));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

Related

How do I use a software SDL_Renderer correctly while resizing the window?

I'm not sure how to use a software SDL_Renderer to render to a window while resizing that window. For example, I expect the following code to constantly display a fully black window even as the uses resizes the window. Instead, when the user resizes the window, it's not filled with black, you get kind of "streaks" of black against a transparent background.
I'm sure I could cobble something together with catching resize events, maybe using SDL_RenderFilleRect() instead of SDL_RenderClear(), but fundamentally I just don't know what I should be doing at all. Should I be freeing the SDL_Surface and getting an entirely new surface and renderer every time the window resizes? Should I be calling SDL_RenderSetViewport()?
#include <SDL.h>
int main()
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow(
"Main Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
600,
600,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
SDL_Surface *window_surface = SDL_GetWindowSurface(window);
SDL_Renderer *renderer = SDL_CreateSoftwareRenderer(window_surface);
SDL_Event event;
bool quit = false;
while (!quit)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(window);
SDL_Delay(1000 / 60);
}
SDL_Quit();
return 0;
}

Why is SDL2 window fading out?

I want a quick fix to this issue:
I wrote a simple program to play around with the SDL2 libraries. A cyan box moves along a blue background from left to right. Then the window closes.
The problem is that the window's color "fades out" while the program is running. The contrast decreases significantly and it's annoying. Sometimes it happens when the box is in the middle of the window. Sometimes it happens when the box reaches the right side of the window. Sometimes it doesn't happen at all. This fading of colors seems to be sporadic and random. It is a run time issue. Theoretically, I do not see any issue with the code. What is wrong?
#include "SDL.h"
#include <stdio.h>
#ifdef __cplusplus
extern "C"
#endif
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
window = SDL_CreateWindow("Boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Rect myBox = { 200, 150, 50, 50 };
int go = 0;
while (go <= 590) {
myBox.x = go;
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
SDL_RenderFillRect(renderer, &myBox);
SDL_RenderPresent(renderer);
if (go == 0)
SDL_Delay(2000);
SDL_Delay(100);
go += 10;
}
SDL_Delay(2000);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return EXIT_SUCCESS;
}
That's a classical SDL mistake.
You're not handling events that your window receives, and because of that your OS assumes that your program has hung up.
Inside of your while loop, add following:
SDL_Event e;
while (SDL_PollEvent(&e))
if (e.type == SDL_QUIT)
return 0;

SDL clears the window screen when clicking on the window of another software in Linux

My program is about drawing the Mandelbrot set. I discovered that when I click another window in the operating system (eg. Chrome, or text editor ...) my program clears the screen to black but continues drawing where it finished. It is during drawing. If the drawing is finished and I click another window then nothing clearing happens.
Is there a solution to fix this (eg. switching something on or off in SDL) without tracking all the pixels onto the screen and print the entire pixel matrix all the times?
Minimal code:
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
enum {WIDTH = 1700, HEIGHT = 950};
int main(){
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("Minimal", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_Event event;
bool exit_ = false;
while (! exit_){
for (int i = 1; i < WIDTH; i++){
for (int j = 1; j < HEIGHT; j++){
SDL_RenderDrawPoint(renderer, i, j);
}
SDL_RenderPresent(renderer);
}
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT) exit_ = true;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
(Note: I haven't got any window event handling in the program.)
I think you need to put SDL_RenderClear(Renderer) at the top of the while loop.
If you do like that, window will be never cleared after rendering.
For example if you don't clear the window, a moving dot will leave his traces..
I work woth SDL too, and i always do this

SDL2 window size is bigger than it should be

I'm trying to create a window, let's say 400x400:
SDL_Init(SDL_INIT_VIDEO);
Uint32 mode = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
SDL_Window* window;
SDL_Renderer* renderer;
if (SDL_CreateWindowAndRenderer(400, 400, mode, &window, &renderer))
return 2;
if (!window || !renderer)
return 2;
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Event event;
int quit = 0;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = 1;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
I see a window filled with black pixels. However, the window's size is 500x500 withouth borders, and 502x540 with them, but why?
On Windows, the OS may stretch your window in the case when you are using a high DPI monitor. You can disable this stretching using:
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1")

Drawing a rectangle with SDL2

I just started using SDL2 and I already have a problem.
I want to create a window and paint it in red.
But it remains white, and I don't understand why.
Here is the code :
int main (int argc, char** argv) {
SDL_Window* pWindow = NULL;
pWindow = SDL_CreateWindow("Jeu de la vie", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
SDL_Surface* pSurface = NULL;
pSurface = SDL_GetWindowSurface(pWindow);
SDL_FillRect(pSurface, NULL, SDL_MapRGB(pSurface->format, 255, 0, 0));
while(1);
SDL_FreeSurface(pSurface);
SDL_DestroyWindow(pWindow);
SDL_Quit();
return EXIT_SUCCESS;
}
There are several issues with your code, I'll try to address most of them.
Initialize SDL
SDL and SDL2 needs to be initialized before you can use it. The way to initialize SDL is the following function.
int SDL_Init(Uint32 flags)
Where flags can be a different value for different subsystems. Use SDL_INIT_EVERYTHING, to initialize everything.
int SDL_Init(SDL_INIT_EVERYTHING)
Read more about it here..
Initialize SDL_Window and SDL_Renderer
SDL_Renderer and SDL_Window needs to be set up before you can use them. You already create your window properly, so I won't cover that. Here's how to set up an SDL_Renderer
SDL_Renderer* SDL_CreateRenderer(SDL_Window* window,
int index,
Uint32 flags)
index defines what driver to use. Set it to -1 to use the first driver that supports the other arguments.
flags are used to make the rendering optimized, software rendiring, prevent vsync, etc.. Set it to SDL_RENDERER_ACCELERATED.
Read more about SDL_CreateRenderer here.
Mixing SDL and SDL2
SDL_Surface is primarily something used in SDL, not SDL2. SDL2_image, SDL2_ttf etc still used SDL_Surface, but they are converted into an SDL_Texture before they can be used.
SDL_FillRect(...); is also mostly a SDL thing. But as stated above, the SDL_Surface can be used, but you need to convert it to an SDL_Texture first :
SDL_Texture* SDL_CreateTextureFromSurface(SDL_Renderer* renderer,
SDL_Surface* surface)
Read more here.
And use
int SDL_RenderCopy(SDL_Renderer* renderer,
SDL_Texture* texture,
const SDL_Rect* srcrect,
const SDL_Rect* dstrect)
To render it, read more here.
Infinite loop ( while(1); )
You REALLY shouldn't do this, it'll just loop forever. Use SDL_Delay( 5000 ); to pause for 5000msec or 5 seconds.
A simpler way
You can use
int SDL_RenderDrawRect(SDL_Renderer* renderer,
const SDL_Rect* rect)
To draw a rect.
You should use
int SDL_SetRenderDrawColor(SDL_Renderer* renderer,
Uint8 r,
Uint8 g,
Uint8 b,
Uint8 a)
To set the color of what you are drawing, use
int SDL_RenderClear(SDL_Renderer* renderer)
After which you call your SDL_RenderDrawRect()
Up until this point, everything has been drawn "behind the scenes." To render it to the screen, use
void SDL_RenderPresent(SDL_Renderer* renderer)
Example
#include <SDL2/SDL.h>
int main (int argc, char** argv)
{
SDL_Window* window = NULL;
window = SDL_CreateWindow
(
"Jeu de la vie", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN
);
// Setup renderer
SDL_Renderer* renderer = NULL;
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
// Set render color to red ( background will be rendered in this color )
SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );
// Clear winow
SDL_RenderClear( renderer );
// Creat a rect at pos ( 50, 50 ) that's 50 pixels wide and 50 pixels high.
SDL_Rect r;
r.x = 50;
r.y = 50;
r.w = 50;
r.h = 50;
// Set render color to blue ( rect will be rendered in this color )
SDL_SetRenderDrawColor( renderer, 0, 0, 255, 255 );
// Render rect
SDL_RenderFillRect( renderer, &r );
// Render the rect to the screen
SDL_RenderPresent(renderer);
// Wait for 5 sec
SDL_Delay( 5000 );
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
Result
You can read more about SDL2 on my blog.

Resources