How to enable Vsync with Software Rendering in SDL [SOLVED]. 如何在SDL2下实现垂直同步

发布时间 2023-05-24 13:10:52作者: zxddesk
How to enable Vsync with Software Rendering in SDL [SOLVED].

Hi, I just figured out the dirty way to enable vsync with software rendering on SDL.

This was bothering me for a week now & I've seen many questions on the net without answer. But I finally figured it out and it's plain and stupid but it works.

It basically uses the Accelerated Renderer only to provide vsync'ed delay for software renderer. So I'm not certain if this will also work on machines with absolutely no acceleration (I have some OpenGl context enabled on my laptop, allthough I have no proper graphics card - have no idea how it works ). But It's worth a try. If the accelerated renderer won't crash your app (it does not have to display anything - just work in the background) - this should work for you.

This is how :

  1. The INIT section:

You create your main Window & then create a accelerated renderer with vsync enabled:

Main_Window = SDL_CreateWindow ("hello void",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED, w, h,SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS);

renderer = SDL_CreateRenderer(Main_Window,-1,SDL_RENDERER_ACCELERATED|

SDL_RENDERER_PRESENTVSYNC);

Then, as you do in software rendering, you assign a surface from your main window:

SDL Surface * window = SDL_GetWindowSurface(Main_Window);

This surface is your main rendering target for software rendering. You may further create a proper software renderer (if you want to use SDL rendering functions) like this:

SDL_Renderer* soft_renderer = SDL_CreateSoftwareRenderer(window);

Or you can directly access the window surface pixel data, f.ex. for pixel by pixel fast software editing, blitting surfaces, or your invented rendering functions.

Then you create a tiny empty texture (1 pix by 1pix) to update to accelerated renderer:

texture = SDL_CreateTexture(renderer, window->format->format, SDL_TEXTUREACCESS_STREAMING, 1, 1);

Then you create a tiny 1 pix SDL_Rect structure like this:

SDL_Rect onepix_rect;

onepix_rect.h=1;

onepix_rect.w=1;

onepix_rect.x=0;

onepix_rect.y=0;

2. Then what you do in the PICTURE UPDATE loop:

Normally for software rendering you would use

SDL_UpdateWindowSurface(Main_Window);

 

Now - to get it to Vsync you put it right after SDL_RenderPresent(renderer) :

SDL_RenderCopy(renderer, texture, NULL, &onepix_rect);

SDL_RenderPresent(renderer);

SDL_UpdateWindowSurface(Main_Window);

In this way accelerated renderer provides a delay for the update loop & prevents picture tearing.

I guess how it works is the Acc_Renderer triggers on vsync but after it finishes uptade of 1 tiny texture there is still enough time for the UpdateWindow function to fit in the VBlank period of the screen.

You no longer have to put any framerate caps on the update loop.

If you want to further halve the number of frames (from the usual 60fps to 30fps),

You add another line like this which provides another delay:

SDL_RenderCopy(renderer, texture, NULL, &onepix_rect);

SDL_RenderPresent(renderer);

SDL_RenderPresent(renderer);

SDL_UpdateWindowSurface(Main_Window);

Or you can simply add any chosen delay in the loop.

If you manage to squeeze anything else in the picture update loop below 11ms or so, you will always reach 60 fps. Any more delay in the loop will simply lower your frame rate but won't ever cause picture tearing.

I know it's stupid and dirty hack, but it works and it enables you to edit surface pixels & update them to the window without conversion to textures - without picture tearing - and this is what was missing in software rendering for me.

Now I can confidently say the full functionality of Acc_Rendering can be applied to soft_rendering. And this is somehow pleasing to me.

Maybe this is something irrelevant (who the hell uses soft_rendering anyway - right?) but I just wanted to leave this solution somewhere if anyone was wondering like I did how to do it, because they are trying out SDL on computer without proper graphics card, or want to simplify their app by using just surfaces. Now You can do it without picture tearing. So cheers!

If you found this helpful future person, please leave a comment, it will make my day!