SDL2 program only works if Renderer is created wit

2020-02-02 03:52发布

问题:

I've written a program using C++ and SDL2 which:

  1. creates a window
  2. gets the window's surface
  3. creates a renderer for the window
  4. renders some filled rectangles onto the window
  5. creates a texture from the window's surface
  6. clears the screen
  7. renders some filled circles onto the window
  8. creates a second texture from the window's surface
  9. enters an event loop, where every time a key is pressed:
  10. if circles are currently being displayed, SDL_RenderCopy() is used to copy the squares texture to the window.
  11. else if squares are currently being displayed, the circles texture is copied to the window.

The program works perfectly if the renderer is created with the SDL_RENDERER_SOFTWARE flag.

If the renderer is created with the SDL_RENDERER_ACCELERATED flag, I find that while I can render direct to the screen, if I create a couple of different textures from the window's surface and then try to copy them back to the window using SDL_RenderCopy(); all I see is a black window.

I can't find any failing SDL calls.

I've wondered whether there might be some incompatibility between the texture format and the renderer - but I'm not sure how to follow this up.

Any help or suggestions?

My environment is :

  • Windows 10
  • Visual Studio Community 2015
  • SDL2 version 2.0.4

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Additional information and source code :

I've added cut down source code to demonstrate the problem below.

Note, to keep down the size, I've removed all of the error checking and consolidated the relevant code into a single main function.

What I get is that the program works for me as expected if I uncomment line 40 so that I am calling SDL_CreateRenderer with the SDL_RENDERER_SOFTWARE flag.

If I un-comment any of the other SDL_CreateRenderer lines instead (line 41-43 : to use hardware acceleration), I see the red and blue squares when they are initially rendered to screen.

But as I press keys, instead of the window flicking between red and blue squares, I'm looking at a black window.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <SDL.h>
#include <SDL_image.h>
#include <stdio.h>
#include <string>


//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;


int main(int argc, char* args[])
{

    //The window we'll be rendering to
    SDL_Window* gWindow = NULL;

    //The surface contained by the window
    SDL_Surface* gScreenSurface = NULL;

    //And two textures, one for a red square, on for a blue square
    SDL_Texture* texture_red = NULL;
    SDL_Texture* texture_blue = NULL;

    //The window renderer
    SDL_Renderer* gRenderer = NULL;


    //Initialize SDL
    SDL_Init(SDL_INIT_VIDEO);

    //Create window
    gWindow = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);

    //Get the screen surface
    gScreenSurface = SDL_GetWindowSurface(gWindow);


    //Create renderer for window
    gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_SOFTWARE);
    //gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
    //gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_PRESENTVSYNC);
    //gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);

    /*###########################################################################################
    # I can not figure out how to make this program work with hardware acceleration. It works   #
    # fine when I define the renderer using SDL_RENDERER_SOFTWARE, but doesn't display anything #
    # if I define the renerer using the SDL_RENDERER_ACCELERATED flag                           #
    ###########################################################################################*/

    //Initialize renderer color
    SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);


    //Clear screen
    SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderClear(gRenderer);

    //Render red filled quad
    SDL_Rect fillRect = { 100, 75, 100, 100 };
    SDL_SetRenderDrawColor(gRenderer, 0xFF, 0x00, 0x00, 0xFF);
    SDL_RenderFillRect(gRenderer, &fillRect);

    //Update the rendered image on screen
    SDL_RenderPresent(gRenderer);

    //Pause long enough to see it
    SDL_Delay(200);

    //Create texture_red texture from the screen surface
    texture_red = SDL_CreateTextureFromSurface(gRenderer, gScreenSurface);


    //Clear screen
    SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderClear(gRenderer);

    //Render blue filled quad
    fillRect = { 225, 250, 100, 100 };
    SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0xFF, 0xFF);
    SDL_RenderFillRect(gRenderer, &fillRect);

    //Update the rendered image on screen
    SDL_RenderPresent(gRenderer);

    //Pause long enough to see it
    SDL_Delay(200);

    //Create texture_red texture from the screen surface
    texture_blue = SDL_CreateTextureFromSurface(gRenderer, gScreenSurface);


    //Main loop flag
    bool quit = false;

    //Flag to keep track of which colour we're currently looking at
    bool blue = true;

    //Event handler
    SDL_Event e;

    //While application is running
    while (!quit)
    {
        //Handle events on queue
        while (SDL_PollEvent(&e) != 0)
        {
            //User requests quit
            if (e.type == SDL_QUIT)
            {
                quit = true;
            }
            //User presses a key
            else if (e.type == SDL_KEYDOWN)
            {
                //Select surfaces based on key press
                switch (e.key.keysym.sym)
                {

                case SDLK_ESCAPE:
                    quit = true;
                    break;

                default:
                    if (blue)
                    {
                        //Copy surface used to store red image onto the screen surface
                        SDL_RenderCopy(gRenderer, texture_red, NULL, NULL);

                        //Update current colour flag
                        blue = false;
                    }
                    else
                    {

                        //Copy surface used to store blue image onto the screen surface
                        SDL_RenderCopy(gRenderer, texture_blue, NULL, NULL);

                        //Update current colour flag
                        blue = true;
                    }

                    //Update the screen with recent render activity
                    SDL_RenderPresent(gRenderer);

                    break;
                }
            }
        }
    }


    //Deallocate surfaces
    SDL_FreeSurface(gScreenSurface);

    //Destroy window
    SDL_DestroyWindow(gWindow);
    gWindow = NULL;

    //Quit SDL subsystems
    SDL_Quit();

    return 0;
}

回答1:

The SDL_GetWindowSurface() header comment specifically prohibits using it with the SDL_Renderer functionality:

/**
 *  \brief Get the SDL surface associated with the window.
 *
 *  \return The window's framebuffer surface, or NULL on error.
 *
 *  A new surface will be created with the optimal format for the window,
 *  if necessary. This surface will be freed when the window is destroyed.
 *
 *  \note You may not combine this with 3D or the rendering API on this window.
 *
 *  \sa SDL_UpdateWindowSurface()
 *  \sa SDL_UpdateWindowSurfaceRects()
 */
extern DECLSPEC SDL_Surface * SDLCALL SDL_GetWindowSurface(SDL_Window * window);

Use SDL_RENDERER_TARGETTEXTURE & SDL_SetRenderTarget() if you want to capture SDL_Renderer output.

You can use SDL_GetRendererInfo() to query a compatible texture format. Or just blast ahead with SDL_PIXELFORMAT_ARGB8888 like testrendertarget.c does and hope for the best :)



回答2:

Try adding SDL_RENDERER_PRESENTVSYNC to your renderer's flag (Proposed by someone here).

C++ seems to be the programming language you're using but for those looking for a fully working SDL2.0.8-based C program that does not use GetWindowSurface(), please take a look here:

Mainly,

  • initWindowAndRenderer
  • drawText
  • drawImage
  • drawVideo
  • setBgColor
  • drawVideo
  • ...


标签: c++ sdl sdl-2