Java faster than C++ with SDL!

Hi,

I have done two programs that do the same thing one in JAVA the other in C++ with SDL.
My JAVA program seems to be faster that the SDL one.
Because it doesn’t sound good I sure I miss something in SDL?
Could you tell me where my mistake is?

The code is very simple:
It loads 2 images (640x480)
It blits the more picture’s part it can, in one second. (if it adds blit a full image then it will switch to the other one)
Then it print the number of pictures blitted and the size of those pictures

Here is the C++ SDL code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <SDL.h>

#include
using namespace std ;

class Measurements{

// Screen size
static const int	_ScreenWidth;
static const int	_ScreenHeight;

static const string		_Image;
static const string		_Image2;

// Number of test per picture size
static const int			_NbTestPerSize;

public:
Measurements(){
_BlitedPictureWidth = 1;
_BlitedPictureHeight = 1;
_NumTest = 1;
_NumTestPerSize = 0;
_NumPicturePerSecond = 0;

	printf("Trying to Load the picture \"%s\"\n",_Image.c_str());
	printf("Trying to Load the picture \"%s\"\n",_Image2.c_str());
	
	// Load the picture
	_Map	= SDL_LoadBMP(_Image.c_str());
	_Map2	= SDL_LoadBMP(_Image2.c_str());
	if( !_Map || !_Map2)
	   exit(3);
}

~Measurements(){
	
	delete(_Map);
	delete(_Map2);
}

bool isFinish(){
	return ((_NumTest == 101)?true:false);
}

void paint(SDL_Surface* pSurface){
	
	int s=0; 	// Number of small picture drew
	int n=0; 	// Number of full picture drew
	int modulo = 0;
	int max = 0;
	
	// Define the first picture to be drew
	SDL_Surface* theMap = _Map;

	// Define some constant
	modulo = _ScreenWidth/_BlitedPictureWidth;
	max = (_ScreenWidth/_BlitedPictureWidth)*(_ScreenHeight/_BlitedPictureHeight);
	
	time_t tnewTime, toldTime;
	
	SDL_Rect    sdlSrc, sdlDst;
	
	time(&toldTime);
	
	do{
		
		// the Src is a part of the picture [ (blitted picture size)*horizontal position, (blitted picture size)*vertical position]
		sdlSrc.x = _BlitedPictureWidth*(s%modulo);
		sdlSrc.y = _BlitedPictureHeight*(int)(s/modulo);
		sdlSrc.w = _BlitedPictureWidth;
		sdlSrc.h = _BlitedPictureHeight;
	
		// the Dst is a part of the picture [ (blitted picture size)*horizontal position, (blitted picture size)*vertical position]
		sdlDst.x = sdlSrc.x;
		sdlDst.y = sdlSrc.y;
		SDL_BlitSurface(theMap, &sdlSrc, pSurface, &sdlDst );
		
		// one picture have been fully drewn -> draw the other picture
		if (++s>max){
			s=0;
			theMap = ((++n)%2 == 0)?_Map:_Map2;
		}
		
		time( &tnewTime );

		// Draw during 1 second
	}while( tnewTime - toldTime<1);
	// Add the number of picture draw during this test
	_NumPicturePerSecond += s + n*max;
	
	// If the test is finish
	if ((++_NumTestPerSize) == _NbTestPerSize){
		_NumTestPerSize = 0;
		
		// Print the number of picture drew in one second
		long picPerSec = _NumPicturePerSecond/_NbTestPerSize;			
		printf("[%d, %d] => %d pic/sec => %d pix/sec\n", _BlitedPictureWidth, _BlitedPictureHeight, picPerSec, (picPerSec*_BlitedPictureWidth*_BlitedPictureHeight));
		
		// Increase the number of test done
		_NumTest++;
		
		// Reset variable 
		_NumPicturePerSecond = 0;			
		
		// Define the properties of the next test
		_BlitedPictureWidth = (_NumTest*_ScreenWidth)/100;
		_BlitedPictureHeight = (_NumTest*_ScreenHeight)/100;
	}
}

private:
// First picture propertie

SDL_Surface*		_Map;

// Second picture propertie
SDL_Surface*		_Map2;

// Size of the blited picture
int					_BlitedPictureWidth;
int					_BlitedPictureHeight;

// Current number test
int					_NumTest;

// Current number of test for the current size
int					_NumTestPerSize;

// Number of picture drew since the begining of the current test
long				_NumPicturePerSecond;

};
const int Measurements::_ScreenWidth = 640;
const int Measurements::_ScreenHeight = 480;
const string Measurements::_Image = “at 640x480.bmp”;
const string Measurements::_Image2 = “box 640x480.bmp”;
const int Measurements::_NbTestPerSize = 1;

int main (int argc, char *argv[])
{
SDL_Surface * sdlMainScreen;

if (SDL_Init (SDL_INIT_VIDEO) < 0)
    exit (1);

SDL_VideoInfo * pVideoInfo;
pVideoInfo = const_cast<SDL_VideoInfo*>(SDL_GetVideoInfo());

char namebuf[256];
SDL_VideoDriverName(namebuf, 256);
atexit(SDL_Quit);

sdlMainScreen = SDL_SetVideoMode (640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF);
pVideoInfo = const_cast<SDL_VideoInfo*>(SDL_GetVideoInfo());

if (sdlMainScreen == NULL)
    exit (2);

Measurements measurements;
while (!measurements.isFinish()){
	 SDL_Event event;

    while (SDL_PollEvent (&event));

	// draw
	measurements.paint(sdlMainScreen);
	
    // Flip the buffers
    SDL_Flip(sdlMainScreen);
}
SDL_Quit();
return 0;

}

Here is the java code:

import java.awt.; // Class [ Graphics, Graphics2D, Image, Color, Toolkit, MediaTracker ]
import java.awt.image.
; // Class [ ImageObserver, BufferedImage ]
import javax.swing.*; // Class [ JFrame, MediaTracker ]
import java.net.URL; // Class [ URL ]

/*
import sdl.core.Main;
import org.havi.ui.HScene;
public class Measurements extends HScene implements ImageObserver{
*/
public class Measurements extends JFrame implements ImageObserver{

// Screen size
final int			m_ScreenWidth				= 640;
final int			m_ScreenHeight				= 480;

// Number of test per picture size
final int			m_NbTestPerSize			= 1;

public static void main(String[] args){
	long initTime, initMem;
	
	// Free all unused memory - gc for Garbage Collector -
	System.gc();
	
	
	//		// !!!!PERFORMANCE TRACKING!!!!	
	initTime = System.currentTimeMillis();
	initMem =Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
	System.out.println("H INIT TIME: "+initTime+"ms MEMORY: "+(double)initMem/1000+"k");
	//		// !!!!PERFORMANCE TRACKING!!!!
	
	// Load the program
	Measurements program = new Measurements();
	long start = System.currentTimeMillis();
	
	// Refreshing loop
	do{
			if (program.m_Status == READY)
				program.paint(program.getGraphics());
	}while(program.m_Status != TEST_FINISH);
	
	long stop = System.currentTimeMillis();
	System.out.println("total time = "+(stop-start)+" ");
	
	//		// !!!!PERFORMANCE TRACKING!!!!
	System.out.println("PREFETCH INIT TIME: +"+((System.currentTimeMillis()-initTime))+
			   "ms MEMORY: +"+((double)(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()-initMem))/1000 +"k");
	
	// Free all unused memory - gc for Garbage Collector -
	System.gc();
	
	System.out.println("PREFETCH GC TIME: +"+((System.currentTimeMillis()-initTime))+
			   "ms MEMORY: +"+((double)(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()-initMem))/1000 +"k");
	//		// !!!!PERFORMANCE TRACKING!!!!
	
	program.quit();
}

public Measurements(){
	
	m_BufferedImage = new BufferedImage( m_ScreenWidth, m_ScreenHeight, BufferedImage.TYPE_INT_ARGB);
	Graphics   gr	=	m_BufferedImage.getGraphics();
	m_Graphics2D	=	(Graphics2D)gr;
	
	m_Image = m_Image+ " " +m_ScreenWidth+"x"+m_ScreenHeight+".jpg";
	m_Image2 = m_Image2+ " " +m_ScreenWidth+"x"+m_ScreenHeight+".jpg";
	System.out.println("Trying to Load the picture \""+m_Image+"\"");
	System.out.println("Trying to Load the picture  \""+m_Image2+"\"");
	
	// Load the 2 pictures into the maps
	URL imgURL = getClass().getResource(m_Image);
	URL imgURL2 = getClass().getResource(m_Image2);
	Toolkit tk = Toolkit.getDefaultToolkit();
	
	try {
		MediaTracker m = new MediaTracker(this);
		m_Map = tk.getImage(imgURL);
		m_Map2 = tk.getImage(imgURL2);
		m.addImage(m_Map, 0);
		m.addImage(m_Map2, 0);
		m.waitForAll();
		System.out.println("Loaded picture \""+m_Image+"\" ["+m_Map.getWidth(this)+", "+m_Map.getHeight(this)+"]");
		System.out.println("Loaded picture \""+m_Image2+"\" ["+m_Map2.getWidth(this)+", "+m_Map2.getHeight(this)+"]");
	 }
	catch (Exception e) {
		 e.printStackTrace();
	 }

	 //close the window
	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	this.setSize(new java.awt.Dimension(m_ScreenWidth, m_ScreenHeight));
	//this.setLayout(null);
	this.setBackground(Color.gray);		
	this.setVisible(true);
}

public void paint(Graphics g){		
	
	int s=0; 	// Number of small picture draw
	int n=0; 	// Number of full picture draw
	int modulo = 0;
	int max = 0;
	
	// Exit it it is currently refreshing
	if (m_Status == 0) return;
		
	// Disable refresh
	m_Status = REFRESHING;
	
	// Define the first picture to be draw
	Image theMap = m_Map;

	// Define some constant
	modulo = m_ScreenWidth/m_BlitedPictureWidth;
	max = (m_ScreenWidth/m_BlitedPictureWidth)*(m_ScreenHeight/m_BlitedPictureHeight);
	
	long oldTime = System.currentTimeMillis();
	
	do{
		m_Graphics2D.drawImage(	theMap,
									(m_BlitedPictureWidth*(s%modulo)), (m_BlitedPictureHeight*(int)(s/modulo)),
									(m_BlitedPictureWidth+m_BlitedPictureWidth*(s%modulo)) , (m_BlitedPictureHeight+m_BlitedPictureHeight*

(int)(s/modulo)),
m_BlitedPictureWidth*(s%modulo), m_BlitedPictureHeight*(s/modulo),
m_BlitedPictureWidth*(s%modulo) +m_BlitedPictureWidth, m_BlitedPictureHeight + m_BlitedPictureHeight*
(s/modulo),
Color.black,
this);

		// one picture have been fully drawn -> draw the other picture
		if (++s>max){
			s=0;
			n++;
			theMap = ((n)%2 == 0)?m_Map:m_Map2;
		}
		// Draw during 1 second
	}while( System.currentTimeMillis() - oldTime<1000);
	
	// Add the number of picture draw during this test
	m_NumPicturePerSecond += s + n*max;
	
	// If the test is finish
	if ((++m_NumTestPerSize) == m_NbTestPerSize){
		m_NumTestPerSize = 0;
		
		// Print the number of picture draw in one second
		long picPerSec = m_NumPicturePerSecond/m_NbTestPerSize;			
		System.out.println("["+m_BlitedPictureWidth+", "+m_BlitedPictureHeight+"] => "+picPerSec+" pic/sec => "+(picPerSec*m_BlitedPictureWidth*m_BlitedPictureHeight)+" pix/sec");
		
		// Increase the number of test done
		m_NumTest++;
		
		// Reset variable 
		m_NumPicturePerSecond = 0;			
		
		// Define the properties of the next test
		m_BlitedPictureWidth = (m_NumTest*m_ScreenWidth)/100;
		m_BlitedPictureHeight = (m_NumTest*m_ScreenHeight)/100;
	}

	// Blit the buffer
	g.drawImage(m_BufferedImage, 0, 0, m_ScreenWidth, m_ScreenHeight, this);
	
	// If the test have been completed
	if (m_NumTest == 101) m_Status = TEST_FINISH; else m_Status = READY;
}

// Quit properly the program
public void quit(){
	/*
	Toolkit toolkit = Toolkit.getDefaultToolkit();
	Main main = toolkit.getMain();
	toolkit.terminate();
	main.TTFQuit();
	main.SDLQuit();
	*/
	System.exit(0);
}

// First picture propertie
String				m_Image		= new String("at");
Image 				m_Map			= null;											

// Second picture propertie
String				m_Image2	= new String("box");
Image 				m_Map2		= null;

// Size of the blited picture
int					m_BlitedPictureWidth		= 1;
int					m_BlitedPictureHeight		= 1;

// Current number test
int					m_NumTest 					= 1;

// Current number of test for the current size
int					m_NumTestPerSize 			= 0;

// Number of picture draw since the begining of the current test
long					m_NumPicturePerSecond = 0;

// Is it ready for a refresh
public int			m_Status 						= 1;
	
public BufferedImage	m_BufferedImage;
public Graphics2D		m_Graphics2D;
	
// Constant
static final int			REFRESHING					= 0;
static final int 		READY								= 1;
static final int			TEST_FINISH					= 2;

}

Hi,

I have done two programs that do the same thing one in JAVA the other in C++ with SDL.
My JAVA program seems to be faster that the SDL one.
Because it doesn’t sound good I sure I miss something in SDL?
Could you tell me where my mistake is?

Most likely your screen is in 32-bit mode and your BMP files are 24-bit,
and you are setting a 16 bit video mode. This means that you are converting
the images from 24 bit to 16 bit (very slow) and then converting the screen
contents from 16 bit to 32 bit, which is faster, but still unnecessary.

The best thing to do is pass 0 for the SetVideoMode depth, which will use
the current screen depth, and then use SDL_DisplayFormat to convert the
BMP images to the display format. It should be a little faster. :slight_smile:

See ya,
-Sam Lantinga, Software Engineer, Blizzard Entertainment