SDL image tearing / stuttering - c++

First of all, let me make some things clear:
My monitor is at 60 hertz
I cap my FPS to 60, and it seems to be working correctly
I have the double buffering flag active
I made a backbuffer myself, and made sure to draw to it, and afterwards to the screen
This problem happens both in fullscreen and windowed mode
This is my main function (it contains all the code):
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface * backbuffer = NULL;
SDL_Surface * screen = NULL;
SDL_Surface * box = NULL;
SDL_Surface * background = NULL;
SDL_Rect * rect = new SDL_Rect();
double FPS = 60;
double next_time;
bool drawn = false;
rect->x = 0;
rect->y = 0;
screen = SDL_SetVideoMode(1920, 1080, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
if(screen == NULL) {
return 0;
}
background = SDL_LoadBMP("background.bmp");
box = SDL_LoadBMP("box.bmp");
if((background == NULL) || (box == NULL)) {
return 0;
}
background = SDL_DisplayFormat(background);
box = SDL_DisplayFormat(box);
backbuffer = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN,
1920,
1080,
32,
0,
0,
0,
0);
if(backbuffer == NULL) {
return 0;
}
next_time = (double)SDL_GetTicks() + (1000.0 / FPS);
while(true) {
if(!drawn) {
SDL_BlitSurface(background, NULL, backbuffer, NULL);
SDL_BlitSurface(box, NULL, backbuffer, rect);
rect->x += 3;
drawn = true;
}
if((Uint32)next_time <= SDL_GetTicks()) {
SDL_BlitSurface(backbuffer, NULL, screen, NULL);
SDL_Flip(screen);
next_time += 1000.0 / FPS;
drawn = false;
}
}
SDL_FreeSurface(backbuffer);
SDL_FreeSurface(background);
SDL_FreeSurface(box);
SDL_FreeSurface(screen);
SDL_Quit();
return 0;
I know this code isn't looking great, it was just a test to see why this happens to me whenever I write anything in SDL.
Please ignore the ugly code, and let me know if you have any idea of what might be causing the image of the moving white square over the black background to have weird artifacts and to seem to be tearing / stuttering.
If you need any more information let me know, and I'll update what's needed.
EDIT:
If I don't cap my FPS, it runs at 200-400 fps, which probably means SDL_Flip isn't waiting for the screen refresh.
I don't know if the flags I write, are actually used.
I checked my flags, and it seems like I can't get the SDL_HWSURFACE and SDL_DOUBLEBUF flags. It might cause the problem?

SDL Double buffering on HW_SURFACE
This is the solution to my problem.
All I had to do was add this line:
SDL_putenv("SDL_VIDEODRIVER=directx");
Thanks for the comments, they helped me find the solution. :D
I guess I should check SDL 2.0 out too...

Related

How to move a bitmap slowly on the window by Direct2D?

I am making a game by Direct2D and I need some help. In this game, I need to move a bitmap on the window slowly and rotates. However, when I ran the code, the bitmap didn't show on the window, if I wait a moment, it shows. I don't know how to deal with the problem because if it sleeps after it moves, the game suspended animation. And this is the following code:
VOID Rotate()
{
ID2D1BitmapBrush* pBitmapBrush = NULL;
g_pRenderTarget->CreateBitmapBrush(g_pMainRole, &pBitmapBrush);
pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_CLAMP);
pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_CLAMP);
PAINTSTRUCT ps = { 0 };
HDC hdc = BeginPaint(g_hGameWnd, &ps);
g_pRenderTarget->BeginDraw();
DOUBLE dCurrentX = 0;
UINT uCurrentAngle = 0;
RECT rc = { 0 };
GetClientRect(g_hGameWnd, &rc);
while (dCurrentX <= rc.right - 128)
{
pBitmapBrush->SetTransform(
D2D1::Matrix3x2F::Rotation(uCurrentAngle % 360, D2D1::Point2F(64, 64)) *
D2D1::Matrix3x2F::Translation(D2D1::SizeF(dCurrentX, 60))
);
g_pRenderTarget->DrawBitmap(g_pBgBitmap, D2D1::RectF(0, 0,
g_pRenderTarget->GetSize().width, g_pRenderTarget->GetSize().height));
D2D1_RECT_F rc = D2D1::RectF(350, 150, 1200, 700);
g_pRenderTarget->DrawRoundedRectangle(D2D1::RoundedRect(rc, 10, 10), g_pBrush, 10.0F);
if (pBitmapBrush != NULL)
{
g_pRenderTarget->FillRectangle(D2D1::RectF(dCurrentX, 60, 1920, 1080), pBitmapBrush);
}
pBitmapBrush->SetTransform(D2D1::Matrix3x2F::Identity());
dCurrentX += 0.1;
uCurrentAngle++;
// Sleep(10);
// This code makes my game suspend animation.
}
g_pRenderTarget->EndDraw();
EndPaint(g_hGameWnd, &ps);
SafeRelease(pBitmapBrush); // This is my inline function
// It calls pBitmapBrush->Release() if pBitmapBrush is not null.
}
Thanks.

SDL2 resize a surface

We want to create an SDL surface by loading an image with SDL_Image and if the dimensions exceed a limit resize the surface.
The reason we need to do this is on Raspbian SDL throws an error creating a texture from the surface ('Texture dimensions are limited to 2048x2048'). Whilst that's a very large image we don't want users to be concerned about image size, we want to resize it for them. Although we haven't encountered this limit on Windows, we're trying to develop the solution on windows and having issues resizing the texture.
Looking for a solution there have been similar questions...:
2008 not SDL2 custom blitting
2010 use SDL_gfx
2008 can't be done use SDL_gfx, 2015 use SDL_BlitScaled, 2015 use SDL_RenderCopyEx
Is a custom blitter or SDL_gfx necessary with current SDL2 (those answers pre-date SDL2's 2013 release)? SDLRenderCopyEx doesn't help as you need to generate the texture which is where our problem occurs.
So we tried some of the available blitting functions like SDL_BlitScaled, below is a simple program to render a 2500x2500 PNG with no scaling:
#include <SDL.h>
#include <SDL_image.h>
#include <sstream>
#include <string>
SDL_Texture * get_texture(
SDL_Renderer * pRenderer,
std::string image_filename) {
SDL_Texture * result = NULL;
SDL_Surface * pSurface = IMG_Load(image_filename.c_str());
if (pSurface == NULL) {
printf("Error image load: %s\n", IMG_GetError());
}
else {
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
if (pTexture == NULL) {
printf("Error image load: %s\n", SDL_GetError());
}
else {
SDL_SetTextureBlendMode(
pTexture,
SDL_BLENDMODE_BLEND);
result = pTexture;
}
SDL_FreeSurface(pSurface);
pSurface = NULL;
}
return result;
}
int main(int argc, char* args[]) {
SDL_Window * pWindow = NULL;
SDL_Renderer * pRenderer = NULL;
// set up
SDL_Init(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_Rect screenDimensions;
screenDimensions.x = 0;
screenDimensions.y = 0;
screenDimensions.w = 640;
screenDimensions.h = 480;
pWindow = SDL_CreateWindow("Resize Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
screenDimensions.w,
screenDimensions.h,
SDL_WINDOW_SHOWN);
pRenderer = SDL_CreateRenderer(pWindow,
-1,
SDL_RENDERER_ACCELERATED);
IMG_Init(IMG_INIT_PNG);
// render
SDL_SetRenderDrawColor(
pRenderer,
0,
0,
0,
0);
SDL_RenderClear(pRenderer);
SDL_Texture * pTexture = get_texture(
pRenderer,
"2500x2500.png");
if (pTexture != NULL) {
SDL_RenderCopy(
pRenderer,
pTexture,
NULL,
&screenDimensions);
SDL_DestroyTexture(pTexture);
pTexture = NULL;
}
SDL_RenderPresent(pRenderer);
// wait for quit
bool quit = false;
while (!quit)
{
// poll input for quit
SDL_Event inputEvent;
while (SDL_PollEvent(&inputEvent) != 0) {
if ((inputEvent.type == SDL_KEYDOWN) &&
(inputEvent.key.keysym.sym == 113)) {
quit = true;
}
}
}
IMG_Quit();
SDL_DestroyRenderer(pRenderer);
pRenderer = NULL;
SDL_DestroyWindow(pWindow);
pWindow = NULL;
return 0;
}
Changing the get_texture function so it identifies a limit and tries to create a new surface:
SDL_Texture * get_texture(
SDL_Renderer * pRenderer,
std::string image_filename) {
SDL_Texture * result = NULL;
SDL_Surface * pSurface = IMG_Load(image_filename.c_str());
if (pSurface == NULL) {
printf("Error image load: %s\n", IMG_GetError());
}
else {
const int limit = 1024;
int width = pSurface->w;
int height = pSurface->h;
if ((width > limit) ||
(height > limit)) {
SDL_Rect sourceDimensions;
sourceDimensions.x = 0;
sourceDimensions.y = 0;
sourceDimensions.w = width;
sourceDimensions.h = height;
float scale = (float)limit / (float)width;
float scaleH = (float)limit / (float)height;
if (scaleH < scale) {
scale = scaleH;
}
SDL_Rect targetDimensions;
targetDimensions.x = 0;
targetDimensions.y = 0;
targetDimensions.w = (int)(width * scale);
targetDimensions.h = (int)(height * scale);
SDL_Surface *pScaleSurface = SDL_CreateRGBSurface(
pSurface->flags,
targetDimensions.w,
targetDimensions.h,
pSurface->format->BitsPerPixel,
pSurface->format->Rmask,
pSurface->format->Gmask,
pSurface->format->Bmask,
pSurface->format->Amask);
if (SDL_BlitScaled(pSurface, NULL, pScaleSurface, &targetDimensions) < 0) {
printf("Error did not scale surface: %s\n", SDL_GetError());
SDL_FreeSurface(pScaleSurface);
pScaleSurface = NULL;
}
else {
SDL_FreeSurface(pSurface);
pSurface = pScaleSurface;
width = pSurface->w;
height = pSurface->h;
}
}
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
if (pTexture == NULL) {
printf("Error image load: %s\n", SDL_GetError());
}
else {
SDL_SetTextureBlendMode(
pTexture,
SDL_BLENDMODE_BLEND);
result = pTexture;
}
SDL_FreeSurface(pSurface);
pSurface = NULL;
}
return result;
}
SDL_BlitScaled fails with an error 'Blit combination not supported' other variations have a similar error:
SDL_BlitScaled(pSurface, NULL, pScaleSurface, NULL)
SDL_BlitScaled(pSurface, &sourceDimensions, pScaleSurface, &targetDimensions)
SDL_LowerBlitScaled(pSurface, &sourceDimensions, pScaleSurface, &targetDimensions) // from the wiki this is the call SDL_BlitScaled makes internally
Then we tried a non-scaled blit... which didn't throw an error but just shows white (not the clear colour or a colour in the image).
SDL_BlitSurface(pSurface, &targetDimensions, pScaleSurface, &targetDimensions)
With that blitting function not working we then tried it with the same image as a bitmap (just exporting the .png as .bmp), still loading the file with SDL_Image and both those functions work with SDL_BlitScaled scaling as expected 😐
Not sure what's going wrong here (we expect and need support for major image file formats like .png) or if this is the recommended approach, any help appreciated!
TL;DR The comment from #kelter pointed me in the right direction and another stack overflow question gave me a solution: it works if you first Blit to a 32bpp surface and then BlitScaled to another 32bpp surface. That worked for 8 and 24 bit depth pngs, 32 bit were invisible again another stack overflow question suggested first filling the surface before blitting.
An updated get_texture function:
SDL_Texture * get_texture(
SDL_Renderer * pRenderer,
std::string image_filename) {
SDL_Texture * result = NULL;
SDL_Surface * pSurface = IMG_Load(image_filename.c_str());
if (pSurface == NULL) {
printf("Error image load: %s\n", IMG_GetError());
}
else {
const int limit = 1024;
int width = pSurface->w;
int height = pSurface->h;
if ((width > limit) ||
(height > limit)) {
SDL_Rect sourceDimensions;
sourceDimensions.x = 0;
sourceDimensions.y = 0;
sourceDimensions.w = width;
sourceDimensions.h = height;
float scale = (float)limit / (float)width;
float scaleH = (float)limit / (float)height;
if (scaleH < scale) {
scale = scaleH;
}
SDL_Rect targetDimensions;
targetDimensions.x = 0;
targetDimensions.y = 0;
targetDimensions.w = (int)(width * scale);
targetDimensions.h = (int)(height * scale);
// create a 32 bits per pixel surface to Blit the image to first, before BlitScaled
// https://stackoverflow.com/questions/33850453/sdl2-blit-scaled-from-a-palettized-8bpp-surface-gives-error-blit-combination/33944312
SDL_Surface *p32BPPSurface = SDL_CreateRGBSurface(
pSurface->flags,
sourceDimensions.w,
sourceDimensions.h,
32,
pSurface->format->Rmask,
pSurface->format->Gmask,
pSurface->format->Bmask,
pSurface->format->Amask);
if (SDL_BlitSurface(pSurface, NULL, p32BPPSurface, NULL) < 0) {
printf("Error did not blit surface: %s\n", SDL_GetError());
}
else {
// create another 32 bits per pixel surface are the desired scale
SDL_Surface *pScaleSurface = SDL_CreateRGBSurface(
p32BPPSurface->flags,
targetDimensions.w,
targetDimensions.h,
p32BPPSurface->format->BitsPerPixel,
p32BPPSurface->format->Rmask,
p32BPPSurface->format->Gmask,
p32BPPSurface->format->Bmask,
p32BPPSurface->format->Amask);
// 32 bit per pixel surfaces (loaded from the original file) won't scale down with BlitScaled, suggestion to first fill the surface
// 8 and 24 bit depth pngs did not require this
// https://stackoverflow.com/questions/20587999/sdl-blitscaled-doesnt-work
SDL_FillRect(pScaleSurface, &targetDimensions, SDL_MapRGBA(pScaleSurface->format, 255, 0, 0, 255));
if (SDL_BlitScaled(p32BPPSurface, NULL, pScaleSurface, NULL) < 0) {
printf("Error did not scale surface: %s\n", SDL_GetError());
SDL_FreeSurface(pScaleSurface);
pScaleSurface = NULL;
}
else {
SDL_FreeSurface(pSurface);
pSurface = pScaleSurface;
width = pSurface->w;
height = pSurface->h;
}
}
SDL_FreeSurface(p32BPPSurface);
p32BPPSurface = NULL;
}
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
if (pTexture == NULL) {
printf("Error image load: %s\n", SDL_GetError());
}
else {
SDL_SetTextureBlendMode(
pTexture,
SDL_BLENDMODE_BLEND);
result = pTexture;
}
SDL_FreeSurface(pSurface);
pSurface = NULL;
}
return result;
}
The comment from #kelter had me look more closely at the surface pixel formats, bitmaps were working at 24bpp, pngs were being loaded at 8bpp and not working. Tried changing the target surface to 24 or 32 bpp but that didn't help. We had generated the png with auto-detected bit depth, setting it to 8 or 24 and performing the BlitScaled on a surface with the same bits-per-pixel worked although it didn't work for 32. Googling the blit conversion error lead to the question and answer from #Petruza.
Update Was a bit quick writing up this answer, the original solution handled bmp and 8 and 24 bit pngs but 32 bit pngs weren't rendering. #Retired Ninja answer to another question about Blit_Scaled suggested filling the surface before calling the function and that sorts it, there's another question related to setting alpha on new surfaces that may be relevant to this (particularily if you needed transparency) but filling with a solid colour is enough for me... for now.

Can't open a window with SDL/C++

i stuck in a big bug with my code which i can't open the first window of my game after running it! it just open blank for a few secondes and then it closes automatically. I doon't know what wrong with my code beacause i'm following series of tutorials and my code seems like the code in the tutorials. here's my code:
#include "stdafx.h"
#include "FirstClass.h"
FirstClass::FirstClass(void){
bool quit = false;
window = NULL;
window = SDL_CreateWindow("Snaykie v1.0",350, 150, 800, 500, SDL_WINDOW_SHOWN);
if (window == NULL){
std::cout << "Can not open the game!" << std::endl;
}
renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
evt = new SDL_Event();
//background image
txt = NULL;
txt = IMG_LoadTexture(renderer, "mainview.bmp");
rct.x = 0 ;
rct.y = 0;
rct.h = 500;
rct.w = 800;
//button start
sbutt = NULL;
sbutt = IMG_LoadTexture(renderer, "startbutton.bmp");
startrct.x = 0 ;
startrct.y = 0;
startrct.h = 100;
startrct.w = 100;
}
FirstClass::~FirstClass(void)
{
SDL_DestroyTexture(txt);
SDL_DestroyTexture(sbutt);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete evt;
}
//the code below is the loops that let the window stucks forever to keep opened
void FirstClass :: GameStart(void){
while (!quit && evt->type != SDL_QUIT){
SDL_PollEvent(evt);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, txt, NULL, &rct);
SDL_RenderCopy(renderer, sbutt, NULL, &startrct);
SDL_RenderPresent(renderer);
}
}
Please help me and thanks i'm really in a big problem.
You are handling the evt variable in a bad way. It is allocated but not initialized, and you compare the uninitialized value to SDL_QUIT. You should reorder the code inside FirstClass::GameStart and preferably use a local variable (since there is no actual need to use a dynamically allocated one) and remove the allocation and deletion of the existing evt from constructor and destructor. Here is a better version of FirstClass::GameStart:
void FirstClass::GameStart(void){
SDL_Event evt;
while (SDL_PollEvent(&evt)){
if (evt.type == SDL_QUIT) {
// a user requested termination has been received, exit the loop
break;
}
else {
// filter the event?
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, txt, NULL, &rct);
SDL_RenderCopy(renderer, sbutt, NULL, &startrct);
SDL_RenderPresent(renderer);
}
}
}
Also ensure that you are actually invoking the FirstClass::GameStart funcion from main, maybe you are simply not running the event loop at all.

SDL text rendering access violation

I'm using SDL 2.0 with C++ for 2D graphics, compressed image format loading, sound playback and so on. Consider the following code:
int main(int argc, char *args[])
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *pWindow = SDL_CreateWindow("Access Violation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1920, 1080, SDL_WINDOW_FULLSCREEN);
SDL_Renderer *pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
Mix_Init(0);
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
Mix_Music *pMusic = Mix_LoadMUS("music.wav");
TTF_Init();
TTF_Font *pFont = TTF_OpenFont("font.ttf", 28);
bool quit = false;
SDL_Event ev;
while(!quit)
{
while(SDL_PollEvent(&ev) != 0)
{
switch(ev.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
SDL_RenderClear(pRenderer);
for(int i = 0; i < 864; i++)
{
SDL_Color clr = { 0, 0, 0 };
SDL_Surface *pSurface = TTF_RenderText_Solid(pFont, "Hey!", clr);
SDL_Texture *pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
SDL_Rect dstrect = { (int)(i/27) * 60, (i%27)*40, pSurface->w, pSurface->h };
SDL_RenderCopy(pRenderer, pTexture, 0, &dstrect);
SDL_DestroyTexture(pTexture);
SDL_FreeSurface(pSurface);
}
SDL_RenderPresent(pRenderer);
}
TTF_CloseFont(pFont);
Mix_FreeMusic(pMusic);
SDL_DestroyRenderer(pRenderer);
SDL_DestroyWindow(pWindow);
Mix_CloseAudio();
Mix_Quit();
IMG_Quit();
TTF_Quit();
SDL_Quit();
return 0;
}
What this basically does is that it just initializes SDL, loads a music, loads a font, and fills continuously the whole screen with text. Fine.
But!
If I add this line
...
SDL_Event ev;
Mix_PlayMusic(pMusic, 0);
while(!quit)
...
right here, text redrawing in the cycle
for(int i = 0; i < 864; i++)
{
...
}
starts to behave unpredictably. One of the SDL's function will shoot an access violation, after some time - between 1 and 30 seconds after start. On the other hand, would I omit text redrawing, music is playing fine.
Any ideas? Of course, all return values are checked. I've omitted checks because of the clarity of the code.
EDIT: Typos.

SDL video overlay flickers with SDL_Flip

I use SDL and libav in C++ to draw a video on the screen in Linux. Most of my code for video opening is based on this tutorial, but I changed some functions that were deprecated. I initialize SDL like this:
SDL_Init(SDL_INIT_EVERYTHING);
const SDL_VideoInfo * info = SDL_GetVideoInfo();
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN);
I am not going to post the whole code since it is pretty big, but the following shows how I try to display a video overlay. Note that some variables are classmembers from my Video class, like formatCtx and packet.
void Video::GetOverlay(SDL_Overlay * overlay) {
int frameFinished;
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
avcodec_decode_video2(codecCtx, frame, &frameFinished, &packet);
if (frameFinished) {
SDL_LockYUVOverlay(overlay);
AVPicture pict;
pict.data[0] = overlay->pixels[0];
pict.data[1] = overlay->pixels[2];
pict.data[2] = overlay->pixels[1];
pict.linesize[0] = overlay->pitches[0];
pict.linesize[1] = overlay->pitches[2];
pict.linesize[2] = overlay->pitches[1];
SwsContext * ctx = sws_getContext (codecCtx->width, codecCtx->height, codecCtx->pix_fmt,
codecCtx->width, codecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(ctx, frame->data, frame->linesize, 0, codecCtx->height, pict.data, pict.linesize);
sws_freeContext(ctx);
SDL_UnlockYUVOverlay(overlay);
++frameIndex;
return;
}
}
av_free_packet(&packet);
}
}
And then in my mainloop:
SDL_Overlay * overlay = SDL_CreateYUVOverlay(video->GetWidth(), video->GetHeight(), SDL_YV12_OVERLAY, screen);
while (true) {
video->GetOverlay(overlay);
SDL_Rect rect = { 400, 200, video->GetWidth(), video->GetHeight() };
SDL_DisplayYUVOverlay(overlay, &rect);
SDL_Flip(screen);
}
This works, the video plays but it flickers a lot. Like it tries to draw an image on the same place each frame. When I remove the call to SDL_Flip(screen) the video plays fine. Too fast, I haven't worked videotiming out yet, but when I add a temporary SDL_Delay(10) it looks pretty good.
But when I remove SDL_Flip to show my video, I can't draw anything else on the screen. Both SDL_BlitSurface and SDL_FillRect fail to draw anything on the screen. I already tried to add SDL_DOUBLEBUF to the flags, but this did not change the situation.
I can provide more code if that is needed, but I think the problem is somewhere in the code that I have posted, since everything else is working fine (drawing images, or displaying a video without SDL_Flip).
What am I doing wrong?
Since you're using a SWSURFACE don't use SDL_Flip(screen) use SDL_UpdateRect. You don't need to set SDL_DOUBLEBUF
http://sdl.beuc.net/sdl.wiki/SDL_UpdateRect
That's what I do and I don't get flicker.
I set my screen like this
screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
In my main loop I call
SDL_UpdateRect(screen, 0, 0, 0, 0);
You should use double buffering to prevent flickering.
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);
I still think this isn't the best solution, but I found something that works!
The command SDL_UpdateRect(screen, 0, 0, 0, 0); will update the whole screen. If I only update the parts of the screen where no video is drawn, the video won't flicker anymore. I think it might have something to do with SDL_Overlays being handled differently than normal surfaces.