We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 992

Summary: SDL and OpenGL problem with possibly SDL_DisplayFormatAlpha
Product: SDL Reporter: Aleksandar Vidakovic <rebelscripts>
Component: videoAssignee: Ryan C. Gordon <icculus>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: major    
Priority: P2    
Version: 1.2.14   
Hardware: x86   
OS: Windows 7   

Description Aleksandar Vidakovic 2010-04-23 06:28:34 UTC
Hello,

Under XP everything is displayed properly, all the textures loaded from the surface into OpenGL texture are properly displayed.

Under Windows 7 most of the textures are white rectangles, some are displayed correctly. The format of all images is 32bit with 8bit alpha.

[code]
    SDLw = surface->w;
    SDLh = surface->h;

    Release(); // release the previous memory

    GLfloat coord[4];

    if(surface)
    {
        SDL_Surface *temp = SDL_DisplayFormatAlpha(surface);
        if(temp) //if conversion succeeds, free old surface
        {
            FreeImage(surface);
            surface = temp;
        }
        else    //can't convert, leave surface as is
        {
            Error(CRITICAL,"SDL_DisplayFormatAlpha failed: %s for image: %s",SDL_GetError(), imageFileName.c_str());
        }

        origWidth = rWidth = static_cast<float>(surface->w);
        origHeight = rHeight = static_cast<float>(surface->h);
        rTexID = SurfaceToTexture(surface,coord);
        rTexMinX = coord[0];
        rTexMinY = coord[1];
        rTexMaxX = coord[2];
        rTexMaxY = coord[3];

        rImage = surface;

        // scale the image to the current resolution scale
        if( !DontScale && PEngine::scale != 1.0f ) {
            PermanentScale( PEngine::scale );
        }
[/code]


here is the part where the image data is loaded into OpenGL texture:

[code]
GLuint texture;
    int w, h;
    SDL_Surface *temp;
    SDL_Rect area;
    Uint32 saved_flags;
    Uint8  saved_alpha;

    //expand width and height to nearest powers of 2
    if( w % 2 != 0 || h % 2 != 0 ) {
        w = PowerOfTwo(surface->w);
        h = PowerOfTwo(surface->h);
    }

    if( texcoord != NULL ) {
        texcoord[0] = 0.0f; //min X
        texcoord[1] = 0.0f; //min Y
        texcoord[2] = (GLfloat)surface->w / w;  //max X
        texcoord[3] = (GLfloat)surface->h / h;  //max Y
    }

    temp = SDL_CreateRGBSurface(
        SDL_SWSURFACE,
        w, h,
        32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN //endian specific color masks
        0x000000FF,
        0x0000FF00,
        0x00FF0000,
        0xFF000000
#else
        0xFF000000,
        0x00FF0000,
        0x0000FF00,
        0x000000FF
#endif
    );
    if(!temp)  //failure in CreateRGBSurface
        return 0;

    //save alpha
    saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
    saved_alpha = surface->format->alpha;
    if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
        SDL_SetAlpha(surface, 0, 0);

    //copy surface (do not alter passed surface to allow this function to be used in special situations)
    area.x = 0;
    area.y = 0;
    area.w = static_cast<Sint16>(surface->w);
    area.h = static_cast<Sint16>(surface->h);
    int r = SDL_BlitSurface(surface, NULL, temp, &area);

    //restore saved alpha
    if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
        SDL_SetAlpha(surface, saved_flags, saved_alpha);


    // get the number of channels in the SDL surface
        GLint nOfColors = temp->format->BytesPerPixel;
        GLenum texture_format;
        if (nOfColors == 4)     // contains an alpha channel
        {
                if (temp->format->Rmask == 0x000000ff)
                        texture_format = GL_RGBA;
                else
                        texture_format = GL_BGRA;
        } else if (nOfColors == 3)     // no alpha channel
        {
                if (temp->format->Rmask == 0x000000ff)
                        texture_format = GL_RGB;
                else
                        texture_format = GL_BGR;
        } else {
                //printf("warning: the image is not truecolor..  this will probably break\n");
                // this error should not go unhandled
        }


    //create the OpenGL texture
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, w, h, 0, texture_format, GL_UNSIGNED_BYTE, temp->pixels);
    //glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, w, h, 0, texture_format, GL_UNSIGNED_BYTE, temp->pixels);
    SDL_FreeSurface(temp); //temp surface no longer needed

    return texture;
[/code]
Comment 1 Aleksandar Vidakovic 2010-04-24 01:34:57 UTC
I just commented out the FreeImage(surface); line which is calling SDL_FreeSurface() after checking that the surface is not NULL. And now the exact same faulty memory management is behaving on Windows XP as well. Exactly the same.

The same textures that are white rectangles under Windows 7 are now under XP. When I allow for SDL_FreeSurface to be called, then everything is normal under XP, while under Windows 7 the same white rectangles.

I just need to add that when SDL_FreeSurface is not called, it behaves the same under all Windows: Windows XP, Windows Vista and Windows 7. Some rectangles are white, some are normal. And all 3 versions behave the same.

This must be a SDL_FreeSurface bug, treating freed surfaces as valid and reusing them, not all but some.
Comment 2 Aleksandar Vidakovic 2010-04-24 02:06:54 UTC
... SDL_FreeSurface problem started with 1.2.12 version. 1.2.11 has no problems with SDL_FreeSurface, but is having display problems.
Comment 3 Aleksandar Vidakovic 2010-04-25 04:42:47 UTC
Sorry about all of this. It was my fault. I had it compiled with MinGW 3.4.5 which did not complain about my programming error. When I switched to 4.4.1 version it immediately showed up.

Everything is fine with SDL, sorry about all of this again.

Regards and keep up the good work!