Closed runedevros closed 5 months ago
I don't see a way to fix this.
As best as I can tell, SDL1 had an mmx-optimized alpha blitter, which is gone in SDL2. In fact, the blit semantics have changed so much between versions that we can't use the SDL2 alpha blitter, we generally used our own.
But even when I modified pygame_sdl2 to be as close to pygame as possible - forcing the use of an the SDL blitter, modifying various surfaces so the masks and flags are all the same - I still get a similar slowdown.
I don't know what your way forwards is. If an optimized alpha blitter were to become available, I'd merge it. It might also be possible to use the pygame_sdl2.renderer to do some sort of accelerated blitting - to be honest, I didn't write and haven't looked at that code. Perhaps the best way - but also the most intrusive - would be to come up with a pygame_sdl2.gl API.
I'll leave this open, in the hopes someone will drop by and tell me what I'm doing wrong. But I don't see a simple fix.
The renderer module will probably be a little faster, but SDL2 doesn't provide a way to do draw call batching. I'll see if I can add something with OpenGL that would be simple to use.
I think the way forward would be retiring the surface/blit concept and start teaching how to use SDL2's excellent Renderer. It will offer a gentle introduction to GPU programming and also make things fast. Holding on to surface/blit rendering is just going to slow down progress.
So I have a rather extensive codebase tied to the Pygame surface/blit system where our game has been engine-stable for about a year now. How hard would it be to port everything to the proposed SDL2 GPU thing that bitcraft suggested?
If you have something similar to pygame's sprite and group system, I don't think it would be too difficult, as SDL2s renderer is not much different conceptually. On the other hand, if you have blits spread out all over, then it may be more difficult. -- you will have to manage and track textures yourself. You can follow any migration guide for SDL 1.2 => 2.x and it will be more or less that same, provided that there is a Renderer api in pygame2...is there?
On Mon, Mar 14, 2016 at 5:48 PM runedevros notifications@github.com wrote:
So I have a rather extensive codebase https://bitbucket.org/featheredmelody/lost-sky-project/wiki/Home tied to the Pygame surface/blit system where our game has been engine-stable for about a year now. How hard would it be to port everything to the proposed SDL2 GPU thing that bitcraft suggested?
— Reply to this email directly or view it on GitHub https://github.com/renpy/pygame_sdl2/issues/36#issuecomment-196553756.
I tried experimenting with the pygame_sdl2 renderer and I see a very huge difference in the fps.
Modified Code:
#Sprite Test
sdl2_mode = True
if sdl2_mode:
try:
import pygame_sdl2
pygame_sdl2.import_as_pygame()
except ImportError:
print "OOPS Pygame SDL2 not available"
import pygame
from pygame.locals import *
import os
import sys
import random
from pygame.render import *
class Bullet(pygame.render.Sprite):
def __init__(self,img_tex):
pygame.render.Sprite.__init__(self, img_tex)
def main():
pygame.init()
screen = pygame.display.set_mode((840,630))
renderer = Renderer(None)
renderer.render_present()
img = pygame.image.load(os.path.join('images','bullets','02-orangeorb.png')) # SDL_Surface
img_tex = renderer.load_texture(img) # SDL_Texture
file = open('output_data.txt','w')
menu_flag = True
clock = pygame.time.Clock()
bullets = []
counter = 0
bullet_num = 0
fps_list = []
data_list = []
while menu_flag:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
menu_flag = False
if counter == 60:
# spawn 20 new bullets
for i in xrange(0,20):
position = (random.randint(0, 840), random.randint(0,630))
new_bullet = Bullet(img_tex)
new_bullet.render(position) # SDL_RenderCopy()
renderer.render_present() # SDL_RenderPresent()
bullet_num += 1
avg_fps = sum(fps_list)/len(fps_list)
print (bullet_num,avg_fps)
data_list.append((bullet_num,avg_fps))
fps_list = []
counter = 0
# End Simulation at 2000 bullets
if bullet_num > 2000:
menu_flag = False
clock.tick(60)
fps_list.append(clock.get_fps())
counter += 1
print "Exporting Data"
[file.write("%s %s \n"%(str(data_pt[0]),str(data_pt[1]))) for data_pt in data_list]
if __name__ == "__main__":
main()
In summary, I believe pygame_sdl2 should take full advantage of the SDL2 render and texture for sprites transformation and blit surface.
The way forward is with hardware rendering.
Guys, when running eshikafe's modified code (two posts above) using the SDL2 render and texture for sprites: there's a magenta border around every sprite.
I've had the same result (magenta borders) in two computers running Xubuntu 16.04. One with intel's integrated graphics and the other with nvidia video card and proprietary drivers. With the default ubuntu package "python-pygame-sdl2" as well as the most recent version built from source (today).
I've opened issue #65 for this. Is it a bug or is it just me?
I have just provided a solution for this issue in #65
Here is the result:
I think issue #36 can be closed. This is already solved by using the render module.
How do you use the render module on android? I get the error:
File "main.py", line 7, in
I am using rapt to package my game. It is extremely slow. How do you make it use the GPU?
Well, actually I left this render method as "PC only" feature, because I couldn't run it on Android. I also tried to import "Renderer" instead of "*" from pygame but it returns the same error.
My code:
try:
import pygame_sdl2
pygame_sdl2.import_as_pygame() #It's normally imported on Android
from pygame.render import Renderer #Returns exception "No module named Renderer" on Android
SDL2 = True
SDL2_Render = False
except:
SDL2 = False
SDL2_Render = False
If SDL2 is True, User will be offered to choose one of two render methods.
Which render method should I use on android to speed up my game? To see my code, look at the latest issue which I created. I use canvas.blit and Pygame.display.update.
Introduction
I noticed that Pygame SDL2 seems to be slower when many sprites are drawn on the screen. I created a program a while ago called bullet stress test in order to test the limits of the number of sprites that can be drawn while keeping the framerate up. In this program, a set of bullet images are drawn on the screen at random positions. Periodically 20 more are added, and the framerate is recorded until 2000 bullets are present. CProfile was used to track which function calls are the most costly.
Experimental Procedure
The test was run on the following system. I'm having some difficulty getting Pygame to run properly due to problems that OSX 10.11 introduced but the same behavior is seen in Pygame_SDL2 on OSX.
Python version:
OS and Hardware:
Results and Discussion
Figure 1 shows the results of the recorded FPS as a function of number of bullets drawn to the screen. For Pygame 1.9.1 we are able to keep 60 FPS for up to 1000 bullets, dropping to 30 FPS once 2000 bullets are on the screen and the experiment is ended. However, for Pygame_SDL2, the FPS declines starting at roughly 250 bullets, and decreases to below 10 FPS by 2000 bullets.
Figure 1. FPS as a function of number of bullets on the screen. While Pygame can maintain 60 FPS up to over 1000+ sprites, Pygame_SDL2's frame rate drops precipitously above 250 bullets.
Cprofile stats are shown in Table 1 and Table 2 for Pygame and Pygame_SDL2 respectively. For over 12 million calls to blit, the cumulative time is less than 40 seconds. In contrast, the cumulative time spent in blit for Pygame_SDL2 is on the order of 400 seconds, representing an order of magnitude increase in time spent in this function.
As for the specific implementation details, I do not know why this occurs in Pygame vs. Pygame_SDL2 but I hope this data will help you be able to make the library run faster.
Table 1. Cprofile results of the script for Pygame 1.9.1. Note the total time spent in blit is less than 1 minute.
Table 2. Cprofile results of the same script for Pygame_SDL2. The total time spent in blit time is over an order of magnitude greater than in Pygame.