Mojave green artifacts in windowed mode


#1

Using windowed mode (works fine in fullscreen) on SDL in OSX Mojave with SDL_image I load a png. The png loads fine but I notice green artifacts across the screen. Note: This happens with SDL_LoadBMP as well. Does anyone else experience this?

Using SDL 2.0.9, Xcode 10.1 and SDL Image 2.0.4
Here is the code in Xcode:

#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>

const int WIDTH = 800, HEIGHT = 600;

int main(int argc, char *argv[])
{
    SDL_Surface *imageSurface = NULL;
    SDL_Surface *windowSurface = NULL;
    
    SDL_Init( SDL_INIT_EVERYTHING );
    
    SDL_Window *window = SDL_CreateWindow( "Hello SDL World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI );
    windowSurface = SDL_GetWindowSurface( window );
    
    // Check that the window was successfully created
    if ( window == NULL )
    {
        // In the case that the window could not be made...
        std::cout << "Could not create window: " << SDL_GetError( ) << std::endl;
        return 1;
    }
    
    if( !( IMG_Init( IMG_INIT_PNG ) & IMG_INIT_PNG ) )
    {
        std::cout << "Could not create window: " << IMG_GetError( ) << std::endl;
        return 1;
    }
    
    SDL_Event windowEvent;
    
    imageSurface = IMG_Load( "logo.png" );
    
    if ( imageSurface == NULL )
    {
        std::cout << "SDL could not load image! SDL Error: " << SDL_GetError( ) << std::endl;
    }
    
    while ( true )
    {
        if ( SDL_PollEvent( &windowEvent ) )
        {
            if ( windowEvent.type == SDL_QUIT )
            {
                break;
            }
        }
        
        SDL_BlitSurface( imageSurface, NULL, windowSurface, NULL );
        
        SDL_UpdateWindowSurface( window );
    }
    
    SDL_FreeSurface( imageSurface );
    SDL_FreeSurface( windowSurface );
    
    imageSurface = NULL;
    windowSurface = NULL;
    
    SDL_DestroyWindow( window );
    SDL_Quit( );
    
    return EXIT_SUCCESS;
}

#2

Using your sample code, I didn’t get a green line, but it did act weird, like it wasn’t finished setting up the window. Then I noticed you aren’t going through the whole event queue every frame. Change the start of your main loop to something like

bool quit = false;
while(quit) {
    // Check every event on the event queue        
    while(SDL_PollEvent(&windowEvent)) {
    if(windowEvent.type == SDL_QUIT) {
        quit = true;
    }
}

Once I did this it worked fine.

Also you don’t need to free windowSurface. The SDL_GetWindowSurface() docs explicitly say not to free the returned surface.


#3

Another thought: could it be that SDL isn’t clearing the window surface’s memory? I haven’t seen it not clear it, but maybe a rare bug?

What happens if you add SDL_FillRect(windowSurface, NULL, SDL_MapRGBA(windowSurface->format, 0, 0, 0, 255)); before the call to SDL_BlitRect()?


#4

I had the same exact issue yesterday with macOS Mojava. I thought it was an issue with Mojave but I copy pasted lazyfoo’s code and when I rendered that it started working. Also there is an issue in Moajve where you have to drag the window a bit for renderer to start.


#5

@sjr Thanks for the quick response! Sorry I had been busy with work this past weekend. I added the code to make sure I was running through all of the event queue and removed the line that frees up the windowSurface. I got slightly different artifacts one time, and then it went back to the normal issue.

I tried SDL_FillRect before the Blit call, and sure enough there’s a nice clean black background!

Is it an issue because the logo doesn’t cover the entire window surface and it doesn’t know what to do with the rest of the surface?


#6

No, your sprite not covering the whole window shouldn’t matter. The window surface may not be getting cleared when created, and thus is filled with garbage. Which seems strange, but maybe you’ve encountered a weird bug. Seems like it should be random garbage in that case, though, not mostly black.

Either way, calling SDL_FillRect() fills it with black.

Depending on what you’re doing, it might be better to only clear it once and then use dirty rects. Or (best option) switch to the hardware accelerated renderer.