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 397

Summary: SDL_BlitSurface loses color information
Product: SDL Reporter: Uplink <advantis>
Component: videoAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: major    
Priority: P2    
Version: 1.2.11   
Hardware: x86   
OS: Linux   
Attachments: Screenshot showing Windows 98, Mac OS X, and Ubuntu
Screenshot of reported result
Source code and sample images
xdpyinfo on my Debian Etch system

Description Uplink 2007-02-22 09:50:43 UTC
SDL_BlitSurface seems to lose color information under Linux.

Doesn't work in:
- Ubuntu Edgy (SDL 1.2.10)
- Debian Etch (SDL 1.2.11)
- Mandriva 2007.0 (SDL 1.2.11)

Works in:
- Windows XP (SDL 1.2.11)
- Debian Sarge (SDL 1.2.7+1.2.8cvs20041007)

I'll create an attachment to this bug with a sample application.
Comment 1 Uplink 2007-02-22 10:01:04 UTC
Bugzilla is currently malfunctioning and I can't create an attachment. Here's the source code:

------------------------ CUT ------------------------

test.cpp:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef HAVE_ICONV
#include <iconv.h>
#endif

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

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	const Uint32 rmask = 0xff000000;
	const Uint32 gmask = 0x00ff0000;
	const Uint32 bmask = 0x0000ff00;
	const Uint32 amask = 0x000000ff;
	
	const int rshift = 24, gshift = 16, bshift = 8, ashift = 0;
#else
	const Uint32 rmask = 0x000000ff;
	const Uint32 gmask = 0x0000ff00;
	const Uint32 bmask = 0x00ff0000;
	const Uint32 amask = 0xff000000;

	const int rshift = 0, gshift = 8, bshift = 16, ashift = 24;
#endif

int main(int /*argc*/, char * /*argv*/[])
{
	/* Initialize SDL */
	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
		return(2);
	}

	/* Set a 640x480x8 video mode */
	SDL_Surface *screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);
	if ( screen == NULL ) {
		fprintf(stderr, "Couldn't set 640x480x8 video mode: %s\n",
							SDL_GetError());
		SDL_Quit();
		return(2);
	}

	SDL_FillRect(screen, NULL, SDL_MapRGBA(screen->format, 255, 0, 255, 128));


	SDL_Surface *pChild = IMG_Load("text-child.png");
	SDL_Surface *pParent = IMG_Load("background.png");
	SDL_BlitSurface(pParent, NULL, screen, NULL);	

	int X = 0, Y = 0, W = 320, H = 240;
    	SDL_Rect rect = {X, Y, W, H};
    	SDL_Surface* pTextSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32, rmask, gmask, bmask, amask);

	SDL_Surface *Surface = screen;
	bool WasSrcAlpha = (Surface->flags & SDL_SRCALPHA) != 0;
	Uint8 WasAlpha = Surface->format->alpha;
	SDL_SetAlpha(Surface, 0, 0);
	SDL_BlitSurface(Surface, &rect, pTextSurface, NULL);
	SDL_SetAlpha(Surface, WasSrcAlpha ? SDL_SRCALPHA : 0, WasAlpha);

	//the problem is here:
	SDL_BlitSurface(pChild, NULL, pTextSurface, NULL);
	
	
	SDL_SetAlpha(pTextSurface, 0, 0);
	SDL_BlitSurface(pTextSurface, NULL, Surface, NULL);	
	SDL_UpdateRect(screen, 0, 0, 0, 0);


	SDL_Event event;
	while (1) 
	{
		if ( SDL_WaitEvent(&event) < 0 ) 
		{
			fprintf(stderr, "SDL_PullEvent() error: %s\n", SDL_GetError());
			continue;
		}

		if(event.type == SDL_QUIT)
		{
			printf("done!\n");
			break;
		}

	}

	SDL_Quit();

	return 0;
}

------------------------ CUT ------------------------

Makefile:

CXX=g++
CC=$(CXX)
CPPFLAGS=-W -Wall -pipe -ggdb3 -I/usr/include/SDL
CXXFLAGS=-I. 
LDFLAGS=-L/usr/local/lib
LDLIBS=-lSDL -lSDL_image 
#-lGL -lSGE -lGLU -lXrender

sources = test.cpp 

all: $(sources:.cpp=.o)
	$(CXX) -o test $+ $(LDFLAGS) $(LDLIBS)

clean:
	rm -f test $(sources:.cpp=.o) 

------------------------ CUT ------------------------

You'll also need to create two images: background.png and text-child.png, where text-child.png contains black text on transparent background.

I uploaded the archive here:
http://myfreefilehosting.com/f/6c2c932231_0.08MB

The is usually kept by the server for around a month before being deleted.
Comment 2 Sam Lantinga 2007-07-06 23:59:42 UTC
Can you describe what the problem actually is?  Maybe add a screenshot of the correct behavior?  I tested it on Windows 98, Mac OS X, and Ubuntu and got the same result each time.  I'm attaching a screenshot.
Comment 3 Sam Lantinga 2007-07-07 00:00:34 UTC
Created attachment 219 [details]
Screenshot showing Windows 98, Mac OS X, and Ubuntu
Comment 4 Uplink 2007-07-07 00:48:20 UTC
Created attachment 220 [details]
Screenshot of reported result

This is the screenshot of the result on my Debian Etch system. Under Ubuntu Dapper (SDL 1.2.9) the result seems to be correct (I didn't report this version of Ubuntu in the original post).
Comment 5 Uplink 2007-07-07 00:50:40 UTC
Created attachment 221 [details]
Source code and sample images

Since attachments work now, I'm posting the archive here too (I was lucky that the file sharing site kept the file for so long)
Comment 6 Sam Lantinga 2007-07-07 00:54:05 UTC
What's the output of xdpyinfo on your Debian Etch system?
Comment 7 Uplink 2007-07-07 00:58:17 UTC
Created attachment 222 [details]
xdpyinfo on my Debian Etch system
Comment 8 Sam Lantinga 2007-07-07 01:04:15 UTC
Nevermind, looking closer I don't think it matters.  Can you debug into
SDL_BlitSurface(pChild, NULL, pTextSurface, NULL) and see what blitter it's
actually using there?
Comment 9 Uplink 2007-07-07 01:21:40 UTC
I don't seem to have a debug version of the SDL libs in Debian Etch so I can't step into the function and see what it's doing. I'll have to build one myself. Can you be more specific about what I should be looking for?
Comment 10 Sam Lantinga 2007-07-07 09:44:12 UTC
When you step into the blit function you'll be going through code that looks at the source surface and the destination surface and picks a blit function to use.  I'm curious which blit function it's choosing.

For example on Mac OS X, SDL_UpperBlit goes into SDL_LowerBlit and then SDL_CalculateBlit eventually calls SDL_CalculateAlphaBlit() which assigns SDL_SoftBlit to surface->map->sw_blit.  Then inside SDL_SoftBlit, the actual blit function ends up being BlitRGBtoRGBPixelAlphaMMX()

I'm guessing you end up in the 3DNow! or C blitters which have a bug in them...
Comment 11 Sam Lantinga 2007-07-07 09:59:41 UTC
So what processor do you have in your Debian system?
Comment 12 Uplink 2007-07-07 13:53:14 UTC
I have an AMD Athlon 64 CPU (but the OS is 32bit)
Comment 13 Sam Lantinga 2007-07-07 14:52:03 UTC
I bet you're hitting the 3DNow! codepath.  I have an AMD system I can check it out on.  Thanks!
Comment 14 Sam Lantinga 2007-07-07 21:12:24 UTC
Strange, I tested this on my AMD system and it works fine.  The blit function that's used is BlitRGBtoRGBPixelAlphaMMX3DNOW()

Can you set a breakpoint at line 64 in test.cpp, and then when you hit it, set a breakpoint in SDL_SoftBlit and then step into the blit function to find out which it is?

Do you know if you've compiled SDL as 32-bit or 64-bit code?  Could the problem simply be that the assembly blitters are used in 64-bit mode?
Comment 15 Ryan C. Gordon 2007-07-08 23:50:44 UTC
Bumping some bugs' priorities to P1 for consideration before the 1.2.12 release (though some may not be resolved for 1.2.12).

--ryan.

Comment 16 Uplink 2007-07-09 07:58:38 UTC
BlitRGBtoRGBPixelAlphaMMX3DNOW. This is the function called from SDL_SoftBlit on my system.

But I ran the code on a Intel Pentium 4 running Ubuntu Feisty (SDL 1.2.11) and the result is the same. Later I'll try to see which blitter that CPU is using, as it doesn't have 3DNow!
Comment 17 Uplink 2007-07-09 08:02:28 UTC
BTW, the Operating Systems are 32bit-only on both systems (the Pentium 4 I used doesn't have AMD64/EM64T instructions at all).
Comment 18 Uplink 2007-07-09 08:46:44 UTC
On the Intel Pentium 4 machine the blitting function is BlitRGBtoRGBPixelAlphaMMX.
Comment 19 Sam Lantinga 2007-07-09 09:33:35 UTC
Okay, then maybe the problem is in the load, somehow?

Can you save out the text surface after it's loaded just to make sure it looks good?  You can probably use SDL_SaveBMP(), and if that shows the problem you might be able to cut the test program down to "load file, save file, view"
Comment 20 Uplink 2007-07-09 10:11:26 UTC
The text image has alpha information which a BMP can't store. I'll get some code that saves PNG from a SDL surface and use that.
Comment 21 Sam Lantinga 2007-07-15 10:40:28 UTC
Any luck debugging this yet?

You shouldn't actually need to save the alpha information to see whether the image is correct.  Without alpha I believe the background will be black.
Comment 22 Uplink 2007-07-16 03:13:27 UTC
Sorry, I didn't have the time to continue. I already have the code for saving as PNG from a SDL surface, but barely have the time to copy/paste it and do the test itself and other debugging. Saving the image as a PNG is important because the test is black, and displayed on a black background in BMP is just not useful. I'll try to get back to you in the following days.
Comment 23 Uplink 2007-07-17 08:47:37 UTC
Saving the text image as PNG doesn't show any problems, so the image is loaded fine. My PNG-saving function only knows RGBA surfaces, so I saved the background.png image using SDL_SaveBMP. Again, no problem. So it's something else. 

In the following days I'll have a Kubuntu machine setup on the Internet. I can give you direct access to it once it's up and running.
Comment 24 Sam Lantinga 2007-07-18 23:20:13 UTC
I logged into this system remotely and ran the test program with SDL 1.2.11, and the output was as described.  I built SDL 1.2.12, and the output was fine.  I suspect either the SDL 1.2.11 build was built with optimization bugs or the bug was fixed in SDL 1.2.12.

Please reopen this bug if you can reproduce it with SDL 1.2.12.

Thanks!
Comment 25 Sam Lantinga 2007-07-18 23:33:21 UTC
BTW, I poked through the debian diffs there, and I see some suspicious patches that add a hermes MMX blitter and a bunch of PIC changes for hermes itself.  I wonder if this is the culprit?  Can you build your SDL 1.2.11 sources without the debian patches and see if that's it?
Comment 26 Sam Lantinga 2007-07-18 23:48:51 UTC
Okay, I just compiled fresh SDL 1.2.11 and confirmed the bug exists, and fresh SDL 1.2.12 and confirmed the bug no longer exists.

Woo!  Thanks for the access to help me track this down!