What Is an Sdl Renderer

What is an SDL renderer?

SDL_Window

SDL_Window is the struct that holds all info about the Window itself: size, position, full screen, borders etc.


SDL_Renderer

SDL_Renderer is a struct that handles all rendering. It is tied to a SDL_Window so it can only render within that SDL_Window. It also keeps track the settings related to the rendering. There are several important functions tied to the SDL_Renderer

  • SDL_SetRenderDrawColor(renderer, r, g, b, a);
    This sets the color you clear the screen to ( see below )

  • SDL_RenderClear(renderer);
    This clears the rendering target with the draw color set above

  • SDL_RenderCopy(
    This is probably the function you'll be using the most, it's used for rendering a SDL_Texture and has the following parameters :

    • SDL_Renderer* renderer,
      The renderer you want to use for rendering.
    • SDL_Texture* texture,
      The texture you want to render.
    • const SDL_Rect* srcrect,
      The part of the texture you want to render, NULL if you want to render the entire texture
    • const SDL_Rect* dstrect)
      Where you want to render the texture in the window. If the width and height of this SDL_Rect is smaller or larger than the dimensions of the texture itself, the texture will be stretched according to this SDL_Rect
  • SDL_RenderPresent(renderer);
    The other SDL_Render* functions draws to a hidden target. This function will take all of that and draw it in the window tied to the renderer.

SDL_Textures and SDL_Surface

The SDL_Renderer renders SDL_Texture, which stores the pixel information of one element. It's the new version of SDL_Surface which is much the same. The difference is mostly that SDL_Surface is just a struct containing pixel information, while SDL_Texture is an efficient, driver-specific representation of pixel data.

You can convert an SDL_Surface* to SDL_Texture using

SDL_Texture* SDL_CreateTextureFromSurface(SDL_Renderer* renderer,
SDL_Surface* surface)

After this, the SDL_Surface should be freed using

SDL_FreeSurface( SDL_Surface* surface )

Another important difference is that SDL_Surface uses software rendering (via CPU) while SDL_Texture uses hardware rendering (via GPU).


SDL_Rect

The simplest struct in SDL. It contains only four shorts. x, y which holds the position and w, h which holds width and height.

It's important to note that 0, 0 is the upper-left corner in SDL. So a higher y-value means lower, and the bottom-right corner will have the coordinate x + w, y + h


You can read more about SDL2 on my blog.

What exactly is a renderer in SDL2?

for the first part of your question see this SO question.

as to why your code doesnt do much:

you are correct that you need to use either SDL_RenderDrawRect(), or SDL_RenderFillRect().
SDL_RenderDrawRect will draw an unfilled rectangle. SDL_RenderFillRect will be filled (hopefully that is obvious).

With SDL_renderer you need to call SDL_RenderPresent to copy the "scene" to the screen.

...
//Renderer
SDL_Renderer* renderer = SDL_CreateRenderer(MainWindow, -1, 0);

SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

SDL_RenderClear(renderer); // fill the scene with white

SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // the rect color (solid red)
SDL_Rect rect(0, 0, 100, 50); // the rectangle
SDL_RenderFillRect(renderer, &rect);
SDL_RenderPresent(renderer); // copy to screen

SDL_Delay(3000);
...

SDL2 Segfaults - Implementing a renderer

Following the link provided by user:keltar,

It seems to me the way to go with SDL2 is to use a renderer for drawing to the window intead of the old SDL1 method of using a surface.

I did just that, removed the surface code and used a renderer only and the code works without problem

Thank You

SDL - Difference between SDL_GetRenderer and SDL_CreateRenderer

SDL_CreateRenderer allows you to create a renderer for a window by specifying some options. It's stored in the specific window data which you can query with SDL_GetRenderer (so the latter is equivalent to (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA))

If you call SDL_GetRenderer without having created it beforehand, you'll get a NULL pointer.

If you call SDL_CreateRenderer on a window twice, the second call will fail with SDL_SetError("Renderer already associated with window"); (see line 805).

See here

What is Renderer and Texture in SDL2, conceptually?

You might want to take a look at the migration guide for SDL2, it provides information on the new way of dealing with 2D graphics.

The point of using textures instead of surfaces is that textures works on the GPU and get loaded into video memory and surfaces works in system memory with the CPU and since GPUs are much better suited than CPU for handling graphics it will be faster. Also, the renderer hides the underlying system used (it could be D3D, OpenGL, or something else).

You can still load surfaces, but you'll have to convert them to textures before rendering them or use the SDL_UpdateWindowSurface and SDL_GetWindowSurface functions; the latter link includes an example on how to use them.

As for the SDL2 approach being slow, as you assert, I don't agree with you, you set up the window and renderer once, load your textures much like you loaded surfaces, copy them to the renderer instead of blitting and finally use SDL_RenderPresent instead of SDL_Flip. Not that different really :)

But, take a look at the migration guide, it has the information you're looking for.

Should each texture have its own dedicated renderer in SDL?

Short Answers

I believe the reason a SDL_Texture requires a renderer is because some backend implementations (OpenGL?) have contexts (this is essentially what SDL_Renderer is) and the image data must be associated with that particular context. You cannot use a texture created in one context inside of another.

for your other question, no, you don't need or want a renderer for each texture. That probably would only produce correct results with the software backend for the same reason (context).


As @keltar correctly points out none of the renderer's will work with a texture that was created with a different renderer due to a check in SDL_RenderCopy. However, this is strictly an API requirement to keep things consistent, my point above is to highlight that even if that check were absent it would not work for backends such as OpenGL, but there is no technical reason it would not work for the software renderer.


Some Details about SDL_Renderer

Remember that SDL_Renderer is an abstract interface to multiple possible backends (OpenGL, OpenGLES, D3D, Metal, Software, more?). Each of these are going to possibly have restrictions on sharing data between contexts and therefore SDL has to limit itself in the same way to maintain sanity.

Example of OpenGL restrictions

Here is a good resource for general restrictions and platform dependent functionality on OpenGL contexts.

As you can see from that page that sharing between contexts has restrictions.

  1. Sharing can only occur in the same OpenGL implementation

This means that you certainly cant share between an SDL_Renderer using OpenGL an a different SDL_Renderer using another backend.


  1. You can share data between different OpenGL Contexts
    ...
    This is done using OS Specific extensions

Since SDL is cross platform this means they would have to write special code for each platform to support this, and all OpenGL implementations may not support it at all so its better for SDL to simply not support this either.


  1. each extra render context has a major impact of the applications
    performance

while not a restriction, it is a reason why adding support for sharing textures is not worthwhile for SDL.

Final Note: the 'S' in SDL stands for "simple". If you need to share data between contexts SDL is simply the wrong tool for the job.

Is SDL Renderer useless if I use opengl for drawing?

Can I not use any SDL2 drawing functions now? Do I only use raw opengl calls, and only use SDL for keyboard bindings?

Correct.

In order to use OpenGL API directly, the SDL window must be created with the flag SDL_WINDOW_OPENGL, as well as a new OpenGL context for it:

auto window = SDL_CreateWindow("Window name",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
auto context = SDL_GL_CreateContext(window);

If successful, one would simply perform calls to OpenGL like in any other context handler. That same website linked in the question provides tutorials for using OpenGL with SDL 2, both legacy and modern. Note that none of the two involve creating an SDL renderer.
In fact, using it would be inappropriate since the two APIs are meant to be mutually exclusive: you should either use one or the other. This answer makes a quick explanation for why you should not mix them.

Nevertheless, there are ways to achieve the same output from certain SDLRenderer calls using OpenGL (since the same renderer has an OpenGL implementation!), but this will naturally be case specific. Want to draw a simple rectangle? The legacy glBegin and glEnd approach might suffice. Want to draw a sprite? You'll have to send it to the OpenGL device's memory first. Once you know the ropes around OpenGL, making a suitable wrapper layer is often appropriate.
If you want to use existing libraries that rely on OpenGL, replacing other drawing procedures to use this API (or utility libraries such as GLU) is the right way to go.

Also note that the SDL renderer does not have to rely on OpenGL (it may use Direct3D on Windows).



Related Topics



Leave a reply



Submit