Discussion:
OpenGL stretch of a pygame.Surface
VertPingouin
2014-07-28 04:54:57 UTC
Permalink
Hi everyone,

I try to make a little 2d engines for my needs. I use the gameobject
library which bring me to a really really decent frame rate (between 400
and 2000 FPS depending on the computer). But I wanted to do some
beautiful pixel art so every frame, I pygame.transform.scale my 640 x
480 display into my native resolution. Despite the fact I carefully have
converted my surfaces to match each other, FPS is really slower (can't
have constant 60FPS anymore !). After a few investigation, the
transformation is slow but not as the blitting of an 1920x1080 surface.

So I came up with the idea of an hardware opengl texture stretching
instead of a dumb blit but I don't know how to achieve it.

Anyone has already done this ?
Sam Bull
2014-07-28 11:32:40 UTC
Permalink
Post by VertPingouin
So I came up with the idea of an hardware opengl texture stretching
instead of a dumb blit but I don't know how to achieve it.
Anyone has already done this ?
You would just need to code the graphics in OpenGL without using
pygame.Surface and pygame.draw. First though, check you are using the
HWSURFACE flag, if you are running fullscreen, it's possible this might
provide the necessary speedup without going to OpenGL.

http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
Noel Garwick
2014-07-28 15:50:07 UTC
Permalink
Right now you are blitting tiles to a 640x480 surface, and then performing
a transform on the whole surface and then blitting it to the display?

If this is the case, then try to only perform the scale operation when the
resolution is changed (instead of once each frame) and see how that works.
I know you mentioned that the full screen blit operation seems to be the
main bottleneck, but this should help too.
Post by Sam Bull
Post by VertPingouin
So I came up with the idea of an hardware opengl texture stretching
instead of a dumb blit but I don't know how to achieve it.
Anyone has already done this ?
You would just need to code the graphics in OpenGL without using
pygame.Surface and pygame.draw. First though, check you are using the
HWSURFACE flag, if you are running fullscreen, it's possible this might
provide the necessary speedup without going to OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
vertpingouin
2014-07-28 20:41:50 UTC
Permalink
to Sam :
I'm using HWSURFACE flag but I got exatly the same framerate. The ideal
would be to rewrite everything in openGL but I don't know it well...
yet.

to Noel:
On the topic of performing transform one time only, I'm not sure what
mean here. If I scale my surface one time, it gets, say, 1920x1080, but
then blitting is done only of a 640x480 part of the surface... So maybe
I misunderstood something here.

I'm using this to transform :

pygame.transform.scale(self.native, (SCREENWIDTH, SCREENHEIGHT),
self.screen)

where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...

I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious frames per
second.

It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Don't know if it's even possible.
Post by Noel Garwick
Right now you are blitting tiles to a 640x480 surface, and then
performing a transform on the whole surface and then blitting it to
the display?
If this is the case, then try to only perform the scale operation when
the resolution is changed (instead of once each frame) and see how
that works. I know you mentioned that the full screen blit operation
seems to be the main bottleneck, but this should help too.
Post by VertPingouin
So I came up with the idea of an hardware opengl texture
stretching
Post by VertPingouin
instead of a dumb blit but I don't know how to achieve it.
Anyone has already done this ?
You would just need to code the graphics in OpenGL without using
pygame.Surface and pygame.draw. First though, check you are using the
HWSURFACE flag, if you are running fullscreen, it's possible this might
provide the necessary speedup without going to OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
Noel Garwick
2014-07-28 21:14:10 UTC
Permalink
vertpingouin,

If you are doing that every frame as part of the sprite's .draw or .update
method , it's still possible the transform is what is taking up CPU time.
You may want to use something like this instead:

class MySpriteThing( pygame.sprite.Sprite):
image = None
def __init___( self ):

.....
if MySpriteThing.image is None:
MySpriteThing.image = pygame.image.load( "foo.png" )
size = MySpriteThing.image.get_size()
new_width = size[0] * X_SCALE # where X_SCALE is the ratio
between RESOLUTION_X (the big resolution) and GRAPHICS_X (the resolution
the images were made at) ; ( 1920 / 640 )
new_height = size[1] * Y_SCALE
MySpriteThing..image = pygame.transform.scale( self.image, (
new_width, new_height ) )

self.image = MySpriteThing.image

........

# then, in your main loop, blit the sprite's .image attribute to your
display surface

mySpriteGroup.draw( screen )

pygame.display.update()



On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin <
Post by vertpingouin
I'm using HWSURFACE flag but I got exatly the same framerate. The ideal
would be to rewrite everything in openGL but I don't know it well...
yet.
On the topic of performing transform one time only, I'm not sure what
mean here. If I scale my surface one time, it gets, say, 1920x1080, but
then blitting is done only of a 640x480 part of the surface... So maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH, SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious frames per
second.
It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Don't know if it's even possible.
Post by Noel Garwick
Right now you are blitting tiles to a 640x480 surface, and then
performing a transform on the whole surface and then blitting it to
the display?
If this is the case, then try to only perform the scale operation when
the resolution is changed (instead of once each frame) and see how
that works. I know you mentioned that the full screen blit operation
seems to be the main bottleneck, but this should help too.
Post by VertPingouin
So I came up with the idea of an hardware opengl texture
stretching
Post by VertPingouin
instead of a dumb blit but I don't know how to achieve it.
Anyone has already done this ?
You would just need to code the graphics in OpenGL without using
pygame.Surface and pygame.draw. First though, check you are using the
HWSURFACE flag, if you are running fullscreen, it's possible this might
provide the necessary speedup without going to OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
sylvain.boussekey
2014-07-29 12:38:33 UTC
Permalink
I tried that with almost no perf gain.
I managed to do it in opengl but perfs are poor... The only advantage
is
that there is almost no fps differences when increasing resolution. But
still framerate is poor. Here is roughly what I do (without knowing
what I
do really)e :

def openglblit(self, surf):
textureSurface = surf

textureData = pygame.image.tostring(textureSurface, "RGBA", 1)

width = textureSurface.get_width()
height = textureSurface.get_height()

texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA,
GL_UNSIGNED_BYTE, textureData)

glClear(GL_COLOR_BUFFER_BIT)

glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2d(0,1)
glVertex2d(-1,1)
glTexCoord2d(0,0)
glVertex2d(-1,-1)
glTexCoord2d(1,0)
glVertex2d(1,-1)
glTexCoord2d(1,1)
glVertex2d(1,1)

glEnd()
glFlush()

glDeleteTextures(texture)

But it seems that the conversion between pygame surface and opengl tex
is
slow.
Argh !! I will really need to go full opengl if I want better perfs...
sad...
Post by Noel Garwick
vertpingouin,
If you are doing that every frame as part of the sprites .draw or
.update method , its still possible the transform is what is taking
up
    image = None
        .....
            MySpriteThing.image = pygame.image.load( "foo.png" )
            size = MySpriteThing.image.get_size()
            new_width = size[0] * X_SCALE # where X_SCALE is the
ratio between RESOLUTION_X (the big resolution) and GRAPHICS_X (the
resolution the images were made at) ; ( 1920 / 640 )
            new_height = size[1] * Y_SCALE
            MySpriteThing..image = pygame.transform.scale(
self.image, ( new_width, new_height ) ) 
        self.image = MySpriteThing.image
........
# then, in your main loop, blit the sprites .image attribute to your
display surface
mySpriteGroup.draw( screen )
pygame.display.update()
On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin
Im using HWSURFACE flag but I got exatly the same framerate. The
ideal
would be to rewrite everything in openGL but I dont know it well...
yet.
On the topic of performing transform one time only, Im not sure
what
mean here. If I scale my surface one time, it gets, say, 1920x1080, but
then blitting is done only of a 640x480 part of the surface... So maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH, SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious frames per
second.
It will be really cool to send my little native surface to my
graphic
card, then let it scale by itself. Dont know if its even possible.
Post by Noel Garwick
Right now you are blitting tiles to a 640x480 surface, and then
performing a transform on the whole surface and then blitting it
to
Post by Noel Garwick
the display?
If this is the case, then try to only perform the scale operation
when
Post by Noel Garwick
the resolution is changed (instead of once each frame) and see
how
Post by Noel Garwick
that works.  I know you mentioned that the full screen blit
operation
Post by Noel Garwick
seems to be the main bottleneck, but this should help too.
[1]>
Post by Noel Garwick
        On lun, 2014-07-28 at 06:54 +0200, VertPingouin
        > So I came up with the idea of an hardware opengl
texture
Post by Noel Garwick
        stretching
        > instead of a dumb blit but I dont know how to
achieve it.
Post by Noel Garwick
        >
        > Anyone has already done this ?
        >
        You would just need to code the graphics in OpenGL
without
Post by Noel Garwick
        using
        pygame.Surface and pygame.draw. First though, check
you are
Post by Noel Garwick
        using the
        HWSURFACE flag, if you are running fullscreen, its
possible
Post by Noel Garwick
        this might
        provide the necessary speedup without going to
OpenGL.
Post by Noel Garwick
       
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
[2]
------
[2]
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
Jeffrey Kleykamp
2014-07-29 13:28:33 UTC
Permalink
I still don't understand what you are doing in the first place. Are you
taking a bunch of frames of art and running them as a movie? Do you really
have 60 frames of art per second? If not, then there's no reason to redraw
everything each frame. Only redraw when something changes. Or, redraw only
the part of the screen that changes. At least, as a rule, only transform an
image ONCE. If you transform the same image more than once then you're
wasting resources! It's much faster to save the transformed image and blit
it onto the screen each time you use it. It's even faster to not redraw the
screen if nothing changed.

I understand that each frame you're trying to draw is 640x480 and then you
want to upscale that to your screen's resolution. How many frames in total
are you trying to draw over how much time?? If the answer isn't 60 frames
over 1 second then there's no reason to redo your transform and blit each
frame!

Are they looping? If they are then save the transformed image for the next
loop.

I hope that helps,
Jeffrey




On Tue, Jul 29, 2014 at 8:38 AM, sylvain.boussekey <
Post by sylvain.boussekey
I tried that with almost no perf gain.
I managed to do it in opengl but perfs are poor... The only advantage is
that there is almost no fps differences when increasing resolution. But
still framerate is poor. Here is roughly what I do (without knowing what I
textureSurface = surf
textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
width = textureSurface.get_width()
height = textureSurface.get_height()
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData)
glClear(GL_COLOR_BUFFER_BIT)
glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2d(0,1)
glVertex2d(-1,1)
glTexCoord2d(0,0)
glVertex2d(-1,-1)
glTexCoord2d(1,0)
glVertex2d(1,-1)
glTexCoord2d(1,1)
glVertex2d(1,1)
glEnd()
glFlush()
glDeleteTextures(texture)
But it seems that the conversion between pygame surface and opengl tex is
slow.
Argh !! I will really need to go full opengl if I want better perfs...
sad...
Post by Noel Garwick
vertpingouin,
If you are doing that every frame as part of the sprites .draw or
.update method , its still possible the transform is what is taking up
image = None
.....
MySpriteThing.image = pygame.image.load( "foo.png" )
size = MySpriteThing.image.get_size()
new_width = size[0] * X_SCALE # where X_SCALE is the
ratio between RESOLUTION_X (the big resolution) and GRAPHICS_X (the
resolution the images were made at) ; ( 1920 / 640 )
new_height = size[1] * Y_SCALE
MySpriteThing..image = pygame.transform.scale(
self.image, ( new_width, new_height ) )
self.image = MySpriteThing.image
........
# then, in your main loop, blit the sprites .image attribute to your
display surface
mySpriteGroup.draw( screen )
pygame.display.update()
On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin
Im using HWSURFACE flag but I got exatly the same framerate. The
ideal
would be to rewrite everything in openGL but I dont know it well...
yet.
On the topic of performing transform one time only, Im not sure
what
mean here. If I scale my surface one time, it gets, say, 1920x1080, but
then blitting is done only of a 640x480 part of the surface... So maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH, SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious frames per
second.
It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Dont know if its even possible.
Right now you are blitting tiles to a 640x480 surface, and then
Post by Noel Garwick
performing a transform on the whole surface and then blitting it
to
Post by Noel Garwick
the display?
If this is the case, then try to only perform the scale operation
when
Post by Noel Garwick
the resolution is changed (instead of once each frame) and see
how
Post by Noel Garwick
that works. I know you mentioned that the full screen blit
operation
Post by Noel Garwick
seems to be the main bottleneck, but this should help too.
[1]>
Post by Noel Garwick
On lun, 2014-07-28 at 06:54 +0200, VertPingouin
Post by VertPingouin
So I came up with the idea of an hardware opengl
texture
Post by Noel Garwick
stretching
Post by VertPingouin
instead of a dumb blit but I dont know how to
achieve it.
Post by Noel Garwick
Post by VertPingouin
Anyone has already done this ?
You would just need to code the graphics in OpenGL
without
Post by Noel Garwick
using
pygame.Surface and pygame.draw. First though, check
you are
Post by Noel Garwick
using the
HWSURFACE flag, if you are running fullscreen, its
possible
Post by Noel Garwick
this might
provide the necessary speedup without going to
OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
[2]
------
[2] http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
--
Jeffrey Kleykamp
sylvain.boussekey
2014-07-29 15:02:37 UTC
Permalink
I have an asynchronous rendering function.
My game does logic updates at a fixed rate.
Rendering is done as fast as it can, possibly fps limited by a
pygame.time.Clock with interpolated position for sprites.
I'm actually drawing everything every frames because everthing is
moving constantly moving.

On my not so fast computer, I acheive 400FPS, which is useless but a
good indicator to know how many sprites I can draw simultaneously.
Pretty confortable.
But if I want to go fullscreen in native resolution (to keep pixels art
pixelated !), I must resize and I drop below 60FPS.

But maybe I don't need 60FPS in the first place...
I still dont understand what you are doing in the first place. Are
you
taking a bunch of frames of art and running them as a movie? Do you
really have 60 frames of art per second? If not, then theres no
reason
to redraw everything each frame. Only redraw when something changes.
Or, redraw only the part of the screen that changes. At least, as a
rule, only transform an image ONCE. If you transform the same image
more than once then youre wasting resources! Its much faster to save
the transformed image and blit it onto the screen each time you use
it. Its even faster to not redraw the screen if nothing changed.
I understand that each frame youre trying to draw is 640x480 and then
you want to upscale that to your screens resolution. How many frames
in total are you trying to draw over how much time?? If the answer
isnt 60 frames over 1 second then theres no reason to redo your
transform and blit each frame!
Are they looping? If they are then save the transformed image for the
next loop.
I hope that helps,
Jeffrey
On Tue, Jul 29, 2014 at 8:38 AM, sylvain.boussekey
Post by sylvain.boussekey
I tried that with almost no perf gain.
I managed to do it in opengl but perfs are poor... The only
advantage is
that there is almost no fps differences when increasing resolution. But
still framerate is poor. Here is roughly what I do (without knowing what I
        textureSurface = surf
        textureData = pygame.image.tostring(textureSurface,
"RGBA", 1)
        width = textureSurface.get_width()
        height = textureSurface.get_height()
        texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData)
        glClear(GL_COLOR_BUFFER_BIT)
        glBindTexture(GL_TEXTURE_2D, texture)
        glBegin(GL_QUADS)
        glTexCoord2d(0,1)
        glVertex2d(-1,1)
        glTexCoord2d(0,0)
        glVertex2d(-1,-1)
        glTexCoord2d(1,0)
        glVertex2d(1,-1)
        glTexCoord2d(1,1)
        glVertex2d(1,1)
        glEnd()
        glFlush()
        glDeleteTextures(texture)
But it seems that the conversion between pygame surface and opengl tex is
slow.
Argh !! I will really need to go full opengl if I want better
perfs... sad...
Post by Noel Garwick
vertpingouin,
If you are doing that every frame as part of the sprites .draw or
.update method , its still possible the transform is what is
taking up
    image = None
        .....
            MySpriteThing.image = pygame.image.load(
"foo.png" )
            size = MySpriteThing.image.get_size()
            new_width = size[0] * X_SCALE # where X_SCALE is the
ratio between RESOLUTION_X (the big resolution) and GRAPHICS_X (the
resolution the images were made at) ; ( 1920 / 640 )
            new_height = size[1] * Y_SCALE
            MySpriteThing..image = pygame.transform.scale(
self.image, ( new_width, new_height ) ) 
        self.image = MySpriteThing.image
........
# then, in your main loop, blit the sprites .image attribute to your
display surface
mySpriteGroup.draw( screen )
 pygame.display.update()
On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin
Im using HWSURFACE flag but I got exatly the same framerate. The
ideal
would be to rewrite everything in openGL but I dont know it
well...
yet.
On the topic of performing transform one time only, Im not sure
what
mean here. If I scale my surface one time, it gets, say,
1920x1080,
but
then blitting is done only of a 640x480 part of the surface...
So
maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH,
SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious
frames
per
second.
It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Dont know if its even
possible.
Post by Noel Garwick
Right now you are blitting tiles to a 640x480 surface, and
then
performing a transform on the whole surface and then blitting
it
to
Post by Noel Garwick
the display?
If this is the case, then try to only perform the scale
operation
when
Post by Noel Garwick
the resolution is changed (instead of once each frame) and
see
how
Post by Noel Garwick
that works.  I know you mentioned that the full screen blit
operation
Post by Noel Garwick
seems to be the main bottleneck, but this should help too.
On Mon, Jul 28, 2014 at 7:32 AM, Sam Bull
[1]>
Post by Noel Garwick
        On lun, 2014-07-28 at 06:54 +0200, VertPingouin
        > So I came up with the idea of an hardware
opengl
texture
Post by Noel Garwick
        stretching
        > instead of a dumb blit but I dont know how to
achieve it.
Post by Noel Garwick
        >
        > Anyone has already done this ?
        >
        You would just need to code the graphics in
OpenGL
without
Post by Noel Garwick
        using
        pygame.Surface and pygame.draw. First though,
check
you are
Post by Noel Garwick
        using the
        HWSURFACE flag, if you are running fullscreen,
its
possible
Post by Noel Garwick
        this might
        provide the necessary speedup without going to
OpenGL.
Post by Noel Garwick
       
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
Post by Noel Garwick
[2]
[2]
------
[2]
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
Post by Noel Garwick
[5]
Jeffrey Kleykamp
2014-07-29 15:06:22 UTC
Permalink
Well you might be able to scroll for some speedup. If everything is moving
in the same general direction then scroll the biggest thing (like the
background) and redraw everything else and the edges.


On Tue, Jul 29, 2014 at 11:02 AM, sylvain.boussekey <
Post by sylvain.boussekey
I have an asynchronous rendering function.
My game does logic updates at a fixed rate.
Rendering is done as fast as it can, possibly fps limited by a
pygame.time.Clock with interpolated position for sprites.
I'm actually drawing everything every frames because everthing is moving
constantly moving.
On my not so fast computer, I acheive 400FPS, which is useless but a good
indicator to know how many sprites I can draw simultaneously. Pretty
confortable.
But if I want to go fullscreen in native resolution (to keep pixels art
pixelated !), I must resize and I drop below 60FPS.
But maybe I don't need 60FPS in the first place...
I still dont understand what you are doing in the first place. Are you
taking a bunch of frames of art and running them as a movie? Do you
really have 60 frames of art per second? If not, then theres no reason
to redraw everything each frame. Only redraw when something changes.
Or, redraw only the part of the screen that changes. At least, as a
rule, only transform an image ONCE. If you transform the same image
more than once then youre wasting resources! Its much faster to save
the transformed image and blit it onto the screen each time you use
it. Its even faster to not redraw the screen if nothing changed.
I understand that each frame youre trying to draw is 640x480 and then
you want to upscale that to your screens resolution. How many frames
in total are you trying to draw over how much time?? If the answer
isnt 60 frames over 1 second then theres no reason to redo your
transform and blit each frame!
Are they looping? If they are then save the transformed image for the
next loop.
I hope that helps,
Jeffrey
On Tue, Jul 29, 2014 at 8:38 AM, sylvain.boussekey
I tried that with almost no perf gain.
Post by sylvain.boussekey
I managed to do it in opengl but perfs are poor... The only
advantage is
that there is almost no fps differences when increasing resolution. But
still framerate is poor. Here is roughly what I do (without knowing what I
textureSurface = surf
textureData = pygame.image.tostring(textureSurface,
"RGBA", 1)
width = textureSurface.get_width()
height = textureSurface.get_height()
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData)
glClear(GL_COLOR_BUFFER_BIT)
glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2d(0,1)
glVertex2d(-1,1)
glTexCoord2d(0,0)
glVertex2d(-1,-1)
glTexCoord2d(1,0)
glVertex2d(1,-1)
glTexCoord2d(1,1)
glVertex2d(1,1)
glEnd()
glFlush()
glDeleteTextures(texture)
But it seems that the conversion between pygame surface and opengl tex is
slow.
Argh !! I will really need to go full opengl if I want better
perfs... sad...
vertpingouin,
Post by Noel Garwick
If you are doing that every frame as part of the sprites .draw or
.update method , its still possible the transform is what is taking up
image = None
.....
MySpriteThing.image = pygame.image.load(
"foo.png" )
size = MySpriteThing.image.get_size()
new_width = size[0] * X_SCALE # where X_SCALE
is the
ratio between RESOLUTION_X (the big resolution) and GRAPHICS_X (the
resolution the images were made at) ; ( 1920 / 640 )
new_height = size[1] * Y_SCALE
MySpriteThing..image = pygame.transform.scale(
self.image, ( new_width, new_height ) )
self.image = MySpriteThing.image
........
# then, in your main loop, blit the sprites .image attribute to your
display surface
mySpriteGroup.draw( screen )
pygame.display.update()
On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin
Im using HWSURFACE flag but I got exatly the same framerate. The
ideal
would be to rewrite everything in openGL but I dont know it well...
yet.
On the topic of performing transform one time only, Im not sure
what
mean here. If I scale my surface one time, it gets, say,
1920x1080,
but
then blitting is done only of a 640x480 part of the surface...
So
maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH,
SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious
frames
per
second.
It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Dont know if its even
possible.
Right now you are blitting tiles to a 640x480 surface, and
Post by Noel Garwick
then
performing a transform on the whole surface and then blitting
it
to
Post by Noel Garwick
the display?
If this is the case, then try to only perform the scale
operation
when
Post by Noel Garwick
the resolution is changed (instead of once each frame) and
see
how
Post by Noel Garwick
that works. I know you mentioned that the full screen blit
operation
Post by Noel Garwick
seems to be the main bottleneck, but this should help too.
On Mon, Jul 28, 2014 at 7:32 AM, Sam Bull
[1]>
Post by Noel Garwick
On lun, 2014-07-28 at 06:54 +0200, VertPingouin
Post by VertPingouin
So I came up with the idea of an hardware
opengl
texture
Post by Noel Garwick
stretching
Post by VertPingouin
instead of a dumb blit but I dont know how to
achieve it.
Post by Noel Garwick
Post by VertPingouin
Anyone has already done this ?
You would just need to code the graphics in
OpenGL
without
Post by Noel Garwick
using
pygame.Surface and pygame.draw. First though,
check
you are
Post by Noel Garwick
using the
HWSURFACE flag, if you are running fullscreen,
its
possible
Post by Noel Garwick
this might
provide the necessary speedup without going to
OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
[2]
[2]
------
[2]
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
[5]
--
Jeffrey Kleykamp
Greg Ewing
2014-07-29 23:20:10 UTC
Permalink
Post by sylvain.boussekey
On my not so fast computer, I acheive 400FPS, which is useless but a
good indicator to know how many sprites I can draw simultaneously.
Are you clearing and redrawing the whole screen each frame,
or just drawing the areas where sprites have moved?

If the latter, then some of the performance decrease could
be due to the fact that you're now copying a whole screenful
of data per frame.

To avoid that with the OpenGL method, you would need to
keep track of the changed areas and just copy them to the
texture with glTexSubImage2D().
--
Greg
Greg Ewing
2014-07-29 23:15:45 UTC
Permalink
Post by sylvain.boussekey
I managed to do it in opengl but perfs are poor.
textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
* You're creating an extra copy of the texture data here.
To avoid that, you could use surfarray to create a surface
backed by a numpy array, do your drawing into that, and
then pass the numpy array directly to glTexImage2D.
Post by sylvain.boussekey
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
* You're creating a new OpenGL texture for each frame and
then discarding it. Try making these calls just once
at the beginning and re-using the texture.

* You're using a non-power-of-2 texture size. Not all
OpenGL implementations support that; yours seemingly does,
but it might be less efficient than a power-of-2 size.
You could try allocating the next larger power-of-2 size and
updating the part that you use with glTexSubImage2D().
--
Greg
VertPingouin
2014-07-31 04:35:23 UTC
Permalink
Ok I now create my texture once.

I'm having some issues with this
Post by Greg Ewing
You're creating an extra copy of the texture data here.
To avoid that, you could use surfarray to create a surface
backed by a numpy array, do your drawing into that, and
then pass the numpy array directly to glTexImage2D.
As I understand it, you suggest a surface with a surfarray.pixel2d bound
to it. But I can't blit on such surface beacause it's locked. Did you
mean drawing directly in surfarray or just create and update a
surfarray.2darray which involve to do a copy of the native screen also ?


Thanks for all your advises everyone.
Post by Greg Ewing
Post by sylvain.boussekey
I managed to do it in opengl but perfs are poor.
textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
* You're creating an extra copy of the texture data here.
To avoid that, you could use surfarray to create a surface
backed by a numpy array, do your drawing into that, and
then pass the numpy array directly to glTexImage2D.
Post by sylvain.boussekey
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
* You're creating a new OpenGL texture for each frame and
then discarding it. Try making these calls just once
at the beginning and re-using the texture.
* You're using a non-power-of-2 texture size. Not all
OpenGL implementations support that; yours seemingly does,
but it might be less efficient than a power-of-2 size.
You could try allocating the next larger power-of-2 size and
updating the part that you use with glTexSubImage2D().
Berlioz Silver
2014-08-04 21:14:31 UTC
Permalink
You want pixels2d, which gives you a variable which _references_ the data.
While the reference is still there, the surface is locked (otherwise you
could change the data mid-blit, which would be bad). Instead, you should
use:

del (variable with pixels2d in it)

right before you pass it off to GL or pygame.

Also, how are you setting up opengl? I haven't gotten that working (hence
why I've looked into surfarray).

Also, if you are dropping to a reasonably moniterable framerate (~120 or so
and below) you can check to see what is taking too long. Simply separate
your commands with calls to time.time() and check at the end. you can print
out the time required (possibly on keypress?) and it'll show you what is
taking so long:

firstTime = time.time()
(create texture)
aCheckpoint = time.time()
(draw your sprites)
bCheckpoint = time.time()
(scale)
cCheckpoint = time.time()

print firstTime, aCheckpoint - firstTime, bCheckpoint - aCheckpoint -
firstTime [etc]

This'll give you the time used (in milliseconds) for each step of the
frame. While I have my own suspicions of what is taking so long, timing it
will show us for certain.


On Wed, Jul 30, 2014 at 9:35 PM, VertPingouin <
Post by VertPingouin
Ok I now create my texture once.
I'm having some issues with this
Post by Greg Ewing
You're creating an extra copy of the texture data here.
To avoid that, you could use surfarray to create a surface
backed by a numpy array, do your drawing into that, and
then pass the numpy array directly to glTexImage2D.
As I understand it, you suggest a surface with a surfarray.pixel2d bound
to it. But I can't blit on such surface beacause it's locked. Did you
mean drawing directly in surfarray or just create and update a
surfarray.2darray which involve to do a copy of the native screen also ?
Thanks for all your advises everyone.
Post by Greg Ewing
Post by sylvain.boussekey
I managed to do it in opengl but perfs are poor.
textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
* You're creating an extra copy of the texture data here.
To avoid that, you could use surfarray to create a surface
backed by a numpy array, do your drawing into that, and
then pass the numpy array directly to glTexImage2D.
Post by sylvain.boussekey
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST)
Post by Greg Ewing
Post by sylvain.boussekey
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST)
Post by Greg Ewing
* You're creating a new OpenGL texture for each frame and
then discarding it. Try making these calls just once
at the beginning and re-using the texture.
* You're using a non-power-of-2 texture size. Not all
OpenGL implementations support that; yours seemingly does,
but it might be less efficient than a power-of-2 size.
You could try allocating the next larger power-of-2 size and
updating the part that you use with glTexSubImage2D().
Greg Ewing
2014-08-04 22:03:15 UTC
Permalink
Post by Berlioz Silver
You want pixels2d, which gives you a variable which _references_ the data.
Yes, sorry, I got it the wrong way round. You need to start
with a normal surface that you can blit into, and then use
pixels2d to create a numpy view of it that you can pass
directly to OpenGL.
Post by Berlioz Silver
While the reference is still there, the surface is locked
(otherwise you could change the data mid-blit, which would be bad).
del (variable with pixels2d in it)
right before you pass it off to GL or pygame.
I think you mean *after* passing it to GL, don't you?
--
Greg
Berlioz Silver
2014-08-08 02:36:28 UTC
Permalink
right. Before you blit. My bad.
Post by Greg Ewing
Post by Berlioz Silver
You want pixels2d, which gives you a variable which _references_ the data.
Yes, sorry, I got it the wrong way round. You need to start
with a normal surface that you can blit into, and then use
pixels2d to create a numpy view of it that you can pass
directly to OpenGL.
While the reference is still there, the surface is locked (otherwise you
Post by Berlioz Silver
could change the data mid-blit, which would be bad). Instead, you should
del (variable with pixels2d in it)
right before you pass it off to GL or pygame.
I think you mean *after* passing it to GL, don't you?
--
Greg
Jake b
2014-08-04 21:36:43 UTC
Permalink
Just a warning, glBegin(), glEnd() is deprecated, and so you know it's an
old tutorial.

Have you tried SFML's python binding? It's a bit like Pygame, and
abstracts the OpenGL functions for you.


On Tue, Jul 29, 2014 at 7:38 AM, sylvain.boussekey <
Post by sylvain.boussekey
I tried that with almost no perf gain.
I managed to do it in opengl but perfs are poor... The only advantage is
that there is almost no fps differences when increasing resolution. But
still framerate is poor. Here is roughly what I do (without knowing what I
textureSurface = surf
textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
width = textureSurface.get_width()
height = textureSurface.get_height()
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData)
glClear(GL_COLOR_BUFFER_BIT)
glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2d(0,1)
glVertex2d(-1,1)
glTexCoord2d(0,0)
glVertex2d(-1,-1)
glTexCoord2d(1,0)
glVertex2d(1,-1)
glTexCoord2d(1,1)
glVertex2d(1,1)
glEnd()
glFlush()
glDeleteTextures(texture)
But it seems that the conversion between pygame surface and opengl tex is
slow.
Argh !! I will really need to go full opengl if I want better perfs...
sad...
Post by Noel Garwick
vertpingouin,
If you are doing that every frame as part of the sprites .draw or
.update method , its still possible the transform is what is taking up
image = None
.....
MySpriteThing.image = pygame.image.load( "foo.png" )
size = MySpriteThing.image.get_size()
new_width = size[0] * X_SCALE # where X_SCALE is the
ratio between RESOLUTION_X (the big resolution) and GRAPHICS_X (the
resolution the images were made at) ; ( 1920 / 640 )
new_height = size[1] * Y_SCALE
MySpriteThing..image = pygame.transform.scale(
self.image, ( new_width, new_height ) )
self.image = MySpriteThing.image
........
# then, in your main loop, blit the sprites .image attribute to your
display surface
mySpriteGroup.draw( screen )
pygame.display.update()
On Mon, Jul 28, 2014 at 4:41 PM, vertpingouin
Im using HWSURFACE flag but I got exatly the same framerate. The
ideal
would be to rewrite everything in openGL but I dont know it well...
yet.
On the topic of performing transform one time only, Im not sure
what
mean here. If I scale my surface one time, it gets, say, 1920x1080, but
then blitting is done only of a 640x480 part of the surface... So maybe
I misunderstood something here.
pygame.transform.scale(self.native, (SCREENWIDTH, SCREENHEIGHT),
self.screen)
where native is the little one and screen the big one. I assume that
self.native is scaled then blit onto self.screen...
I think this is the blitting that is slow because if I use a lesser
resolution for self.screen, I almost get back my precious frames per
second.
It will be really cool to send my little native surface to my graphic
card, then let it scale by itself. Dont know if its even possible.
Right now you are blitting tiles to a 640x480 surface, and then
Post by Noel Garwick
performing a transform on the whole surface and then blitting it
to
Post by Noel Garwick
the display?
If this is the case, then try to only perform the scale operation
when
Post by Noel Garwick
the resolution is changed (instead of once each frame) and see
how
Post by Noel Garwick
that works. I know you mentioned that the full screen blit
operation
Post by Noel Garwick
seems to be the main bottleneck, but this should help too.
[1]>
Post by Noel Garwick
On lun, 2014-07-28 at 06:54 +0200, VertPingouin
Post by VertPingouin
So I came up with the idea of an hardware opengl
texture
Post by Noel Garwick
stretching
Post by VertPingouin
instead of a dumb blit but I dont know how to
achieve it.
Post by Noel Garwick
Post by VertPingouin
Anyone has already done this ?
You would just need to code the graphics in OpenGL
without
Post by Noel Garwick
using
pygame.Surface and pygame.draw. First though, check
you are
Post by Noel Garwick
using the
HWSURFACE flag, if you are running fullscreen, its
possible
Post by Noel Garwick
this might
provide the necessary speedup without going to
OpenGL.
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
[2]
------
[2] http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
--
Jake
Loading...