[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pygame] Bizarre(?) per-pixel alpha vs. no alpha benchmark results



I benchmarked (code attached) blitting a 128x128 sprite 
(attached) with and without per pixel alpha information 
under PyGame. On each frame, I clear the 640x480 screen 
with the background color via fill(), then blit the 
sprite 4 times.  The results are quite interesting:

640x480 windowed            16-bit       32-bit
===============================================
plain opaque blit:          70 fps       47 fps
per pixel alpha :           80 fps (!)   49 fps
per pixel alpha + RLEACCEL: 93 fps (!)   55 fps

Comment: Why is p.p. Alpha blit faster in 
windowed modes?  Does this mean that there 
will not be much benefit gained from optimizing 
the alpha blending routines (like say, using
MMX)?


120Hz 640x480 16-bit full screen, SWSURFACE  
                            DOUBLEBUF    no DOUBLEBUF
=============================================================
plain opaque blit:          120 fps      71 fps (!)
per pixel alpha :           24  fps(!)   80 fps 
per pixel alpha + RLEACCEL: 30  fps(!)   95 fps 

Comment: Why does using double-buffering impose
such a huge performance hit on the alpha blending and
at the same time INCREASE the performance of the
plain opaque blit?!? Could this be an artifact of 
using PyGame? 640x480 32-bit mode exhibited analogous 
behavior.  No tearing visible in all tests.


120Hz 640x480 16-bit full screen, HWSURFACE
                            DOUBLEBUF     no DOUBLEBUF
=============================================================
plain opaque blit:          120 fps     / 146 fps 
per pixel alpha :           23 fps      / 25 fps
per pixel alpha + RLEACCEL: 35 fps      / 35 fps

Comment: Severe tearing when not using DOUBLEBUF, even 
when the fps was way below the refresh rate as in the 
case of the alpha blits!  Why would using HWSURFACE
create tearing? 32-bit results analogous to 16-bit
ones.


Notes
=====
1. Enabling RLEACCEL made no difference for all the 
plain opaque blits.
2. In windowed mode, HWSURFACE doesn't seem to have
an effect even if i use a low-res mode like 800x600. 
Considering I'm using a 16MB Voodoo3, shouldn't
there be plenty of video memory to store the sprite 
in?

Details on the sprite image I used
==================================
They come from the same image generated under 
Photoshop.  One was saved as a Targa (with alpha 
channel) and the other is a PNG (Photoshop 6 does 
not export alpha channel for PNGs), otherwise
identical. I've included it the PNG version to 
show the background pixel to non-background pixel 
ratio as well as the alpha channel in grayscale
PNG.

My setup
========
DirectX 8
Win2K SP1
16MB Voodoo3 AGP
120Hz refresh at 640x480 fullscreen


import pygame
import pygame.image
import whrandom
from pygame.locals import *
from whrandom import randint

# position sprites randomly clustered in the center
pos1=randint(200,300); pos2=randint(150,200); 
pos3=randint(200,300); pos4=randint(150,200); 
pos5=randint(200,300); pos6=randint(150,200); 
pos7=randint(200,300); pos8=randint(150,200); 
whrandom.seed(1,2,2)

fps_frames = 0
fps_time = 0

def main():
	global screen,alpha1
	pygame.init()
	# Uncomment for proper display mode
	#screen = pygame.display.set_mode((640,480))
	screen = pygame.display.set_mode((640,480), FULLSCREEN, 32)
	#screen = pygame.display.set_mode((640,480), HWSURFACE|FULLSCREEN, 32)
	print screen.get_flags()
	# Select between alpha, no alpha, RLEACCEL and none
	alpha1 = pygame.image.load('c:\\temp\\alpha1.tga')
	#alpha1 = pygame.image.load('c:\\temp\\alpha1.png') 
	alpha1.set_alpha(255,RLEACCEL)
	while not pygame.event.peek((QUIT,KEYDOWN,MOUSEBUTTONDOWN)):
		calculateFrame()
		pygame.display.flip()
		calcfps()

def calcfps():
	global fps_time, fps_frames
	if not fps_time:
		fps_time = pygame.time.get_ticks()
		fps_frames = 0
		return
	fps_frames += 1
	now = pygame.time.get_ticks()
	time = now - fps_time
	if time > 1000:
		time = time / 1000.0
		print 'TIME: %.3f   FPS: %.2f' % (time/fps_frames, fps_frames/time)
		fps_frames = 0
		fps_time = now

def initscreen():
	pygame.init()
	screen = pygame.display.set_mode((640,480), 0, 32)
	print screen.get_flags()

def benchblit():
	while not pygame.event.peek((QUIT,KEYDOWN,MOUSEBUTTONDOWN)):
		calculateFrame()
		pygame.display.flip()
		calcfps()

def calculateFrame():
	global pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8
	if randint(0,1)==0: pos1=pos1+randint(0,6)-3
	if randint(0,1)==0: pos2=pos2+randint(0,6)-3
	if randint(0,1)==0: pos3=pos3+randint(0,6)-3
	if randint(0,1)==0: pos4=pos4+randint(0,6)-3
	if randint(0,1)==0: pos5=pos5+randint(0,6)-3
	if randint(0,1)==0: pos6=pos6+randint(0,6)-3
	if randint(0,1)==0: pos7=pos7+randint(0,6)-3
	if randint(0,1)==0: pos8=pos8+randint(0,6)-3
	screen.fill((200,200,200))
	screen.blit(alpha1,[pos1,pos2])
	screen.blit(alpha1,[pos3,pos4])
	screen.blit(alpha1,[pos5,pos6])
	screen.blit(alpha1,[pos7,pos8])

if __name__ == '__main__': main()

alpha1-channel.png

alpha1.png