Pygame for SDL 2, and how it may look.

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
28 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Pygame for SDL 2, and how it may look.

Lenard Lindstrom
Hello everyone,

I have written some proof-of-concept code on how SDL 2 windows and
renderers may be incorporated into the Pygame Python API. Here is the
latest incarnation of a previous post
(http://archives.seul.org/pygame/users/Mar-2017/msg00139.html) as a
pygame.example program:

"""Render an image to a window
This is adapted from the SDL 2 example at
<http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world>.
"""

import pygame
from pygame.display import RendererWindow
import os


def get_resource_path():
     my_dir = os.path.dirname(os.path.abspath(__file__))
     return os.path.join(my_dir, 'data')


def run():
     pygame.display.init()
     title = "Hello World!"
     rect = (100, 100, 640, 480)
     flags = RendererWindow.SHOWN
     with RendererWindow(title, rect, flags) as win:
         ren = win.renderer
         flags = (ren.ACCELERATED  |
                  ren.PRESENTVSYNC   )
         ren.open(flags)
         image_path = os.path.join(get_resource_path(), 'hello.bmp')
         bmp = pygame.image.load(image_path)
         tex = ren.new_texture_from_surface(bmp)

         for i in range(3):
             ren.clear()
             tex.copy_to_renderer()
             ren.update()
             pygame.time.delay(1000)
     pygame.quit()

if __name__ == '__main__':
run()


A window with renderer and a window with surface are implemented as
distinct subclasses of a standard Window extension type. Each Window
instance is an open window on the display. Window updates are perform by
methods on the corresponding renderer or surface. Window and renderer
specific constants, such as SDL_WINDOW_SHOWN and
SDL_RENDERER_ACCELERATED are class attributes, though they could also be
included in pygame.locals.

This is preliminary design work, so feedback is not only welcome but
also necessary.

Lenard Lindstrom

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Ian Mallett-2
On Thu, Apr 13, 2017 at 3:25 PM, Lenard Lindstrom <[hidden email]> wrote:
"""Render an image to a window
This is adapted from the SDL 2 example at
<http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world>.
"""

​Heh, I'm friends with Will. We're at the same university.​

import pygame
from pygame.display import RendererWindow
import os


def get_resource_path():
    my_dir = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(my_dir, 'data')


def run():
    pygame.display.init()
    title = "Hello World!"
    rect = (100, 100, 640, 480)
    flags = RendererWindow.SHOWN
    with RendererWindow(title, rect, flags) as win:
        ren = win.renderer
        flags = (ren.ACCELERATED  |
                 ren.PRESENTVSYNC   )
        ren.open(flags)
        image_path = os.path.join(get_resource_path(), 'hello.bmp')
        bmp = pygame.image.load(image_path)
        tex = ren.new_texture_from_surface(bmp)

        for i in range(3):
            ren.clear()
            tex.copy_to_renderer()
            ren.update()
            pygame.time.delay(1000)
    pygame.quit()

if __name__ == '__main__':
run()


A window with renderer and a window with surface are implemented as distinct subclasses of a standard Window extension type. Each Window instance is an open window on the display. Window updates are perform by methods on the corresponding renderer or surface. Window and renderer specific constants, such as SDL_WINDOW_SHOWN and SDL_RENDERER_ACCELERATED are class attributes, though they could also be included in pygame.locals.

This is preliminary design work, so feedback is not only welcome but also necessary.

​Is it possible to combine the renderer with the window? I don't see why the renderer needs to be pulled out of the pygame.draw module, and indeed, this could be confusing for existing code.

For maximum backcompatibility, something like the following would seem to fit better with the existing API:

surf1 = pygame.display.Window(rect1,flags)
surf2 = pygame.display.Window(rect2,flags)
#...
surf1.blit(...)
surf2.blit(...)
#...
pygame.display.flip()

I don't recall what was decided about the feasibility of implementing SDL2-style or hardware-accelerated rendering, but I'd hazard that this sort of API wouldn't map well to it. OTOH, I don't think the decision to implement a modern graphics interface was decided in the first place (just that we're currently adding some SDL2 stuff).

It's worth noting that switching the graphics context between windows (to do hardware draws) isn't free, and simple code (that e.g. draws a bunch of things on two windows, switching every draw call for code clarity) might not run very well. Perhaps the API should discourage this somehow, especially if full HW drawing is encouraged.

Lenard Lindstrom
 
​Ian​
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by Lenard Lindstrom
Hi Ian,

Thanks for replying.

On 17-04-16 01:43 AM, Ian Mallett wrote:

> On Thu, Apr 13, 2017 at 3:25 PM, Lenard Lindstrom <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     """Render an image to a window
>     This is adapted from the SDL 2 example at
>     <http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world
>     <http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world>>.
>     """
>
>
> ​Heh, I'm friends with Will. We're at the same university.​
>
>     import pygame
>     from pygame.display import RendererWindow
>     import os
>
>
>     def get_resource_path():
>         my_dir = os.path.dirname(os.path.abspath(__file__))
>         return os.path.join(my_dir, 'data')
>
>
>     def run():
>         pygame.display.init()
>         title = "Hello World!"
>         rect = (100, 100, 640, 480)
>         flags = RendererWindow.SHOWN
>         with RendererWindow(title, rect, flags) as win:
>             ren = win.renderer
>             flags = (ren.ACCELERATED  |
>                      ren.PRESENTVSYNC   )
>             ren.open(flags)
>             image_path = os.path.join(get_resource_path(), 'hello.bmp')
>             bmp = pygame.image.load(image_path)
>             tex = ren.new_texture_from_surface(bmp)
>
>             for i in range(3):
>                 ren.clear()
>                 tex.copy_to_renderer()
>                 ren.update()
>                 pygame.time.delay(1000)
>         pygame.quit()
>
>     if __name__ == '__main__':
>     run()
>
>
>     A window with renderer and a window with surface are implemented
>     as distinct subclasses of a standard Window extension type. Each
>     Window instance is an open window on the display. Window updates
>     are perform by methods on the corresponding renderer or surface.
>     Window and renderer specific constants, such as SDL_WINDOW_SHOWN
>     and SDL_RENDERER_ACCELERATED are class attributes, though they
>     could also be included in pygame.locals.
>
>     This is preliminary design work, so feedback is not only welcome
>     but also necessary.
>
>
> ​Is it possible to combine the renderer with the window? I don't see
> why the renderer needs to be pulled out of the pygame.draw module, and
> indeed, this could be confusing for existing code.
>
I don't quite understand. The renderer associated with the
RendererWindow instance is returned by the window's renderer property.

Why are the window and the renderer separate objects? There is a
one-to-one relation between a window and its renderer or a display
surface. And a window cannot have both. To avoid duplicating a bunch of
window specific methods I created a Window class, with RendererWindow
and SurfaceWindow (not shown) as subclasses. Also, a surface can have a
renderer, and a combined surface-renderer object makes no sense. Still,
I haven't ruled out renderer-window and surface-window types yet.
However it is done, I don't see an elegant representation of the
relationships among SDL windows, surfaces, renders, and textures.

> For maximum backcompatibility, something like the following would seem
> to fit better with the existing API:
>
> surf1 = pygame.display.Window(rect1,flags)
> surf2 = pygame.display.Window(rect2,flags)
> #...
> surf1.blit(...)
> surf2.blit(...)
> #...
> pygame.display.flip()
>
> I don't recall what was decided about the feasibility of implementing
> SDL2-style or hardware-accelerated rendering, but I'd hazard that this
> sort of API wouldn't map well to it. OTOH, I don't think the decision
> to implement a modern graphics interface was decided in the first
> place (just that we're currently adding some SDL2 stuff).
The user can choose either a renderer or a display surface for a window.
And pixels can be copied between textures and surfaces. So hardware
accelerated rendering is available, as shown in the example.

As for set_mode(), flip(), and update(), they remain in Pygame SDL 2.
Keeping as much of the Pygame SDL 1 API in Pygame SDL 2 is a priority.
This example explores how new SDL 2 specific capabilities can be added
to Pygame. It uses a Python feature unavailable when Pygame was created,
the new-style class.

>
> It's worth noting that switching the graphics context between windows
> (to do hardware draws) isn't free, and simple code (that e.g. draws a
> bunch of things on two windows, switching every draw call for code
> clarity) might not run very well. Perhaps the API should discourage
> this somehow, especially if full HW drawing is encouraged.

Again I don't understand. Given a window, its renderer, and a bunch of
textures: render the textures to various locations on the window, update
(expose) the renderer, then repeat. How is this not hardware drawing.
What am I missing?

SDL 2 supports multiple open windows. Pygame will too. Let the designer
choose how many windows are open, and if hardware acceleration is
appropriate. Not all Pygame applications need be fast-paced games.

Lenard Lindstrom


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Ian Mallett-2
On Mon, Apr 17, 2017 at 12:01 AM, Lenard Lindstrom <[hidden email]> wrote:
​Is it possible to combine the renderer with the window? I don't see why the renderer needs to be pulled out of the pygame.draw module, and indeed, this could be confusing for existing code.

I don't quite understand. The renderer associated with the RendererWindow instance is returned by the window's renderer property.

Why are the window and the renderer separate objects? There is a one-to-one relation between a window and its renderer or a display surface. And a window cannot have both. To avoid duplicating a bunch of window specific methods I created a Window class, with RendererWindow and SurfaceWindow (not shown) as subclasses. Also, a surface can have a renderer, and a combined surface-renderer object makes no sense. Still, I haven't ruled out renderer-window and surface-window types yet. However it is done, I don't see an elegant representation of the relationships among SDL windows, surfaces, renders, and textures.

​I guess I'm asking why they have to be separate objects. At the OS level, there's a region of the screen which is backed either by a software buffer and managed by the compositor or a GPU buffer managed by the compositor via the graphics context. It's a buffer either way, and the difference is sortof only where it lives and what operations are fast on it.

So, it's not really clear to me what a "renderer" is (I guess it's supposed to wrap the graphics context?).

Separately, I was thinking also that anything that does "rendering" ought to be combined with pygame.draw, because principle of least astonishment. However, this sortof depends on the new drawing API, and whether it can/should remain backward compatible with pygame.draw.

For maximum backcompatibility, something like the following would seem to fit better with the existing API:

surf1 = pygame.display.Window(rect1,flags)
surf2 = pygame.display.Window(rect2,flags)
#...
surf1.blit(...)
surf2.blit(...)
#...
pygame.display.flip()

I don't recall what was decided about the feasibility of implementing SDL2-style or hardware-accelerated rendering, but I'd hazard that this sort of API wouldn't map well to it. OTOH, I don't think the decision to implement a modern graphics interface was decided in the first place (just that we're currently adding some SDL2 stuff).
The user can choose either a renderer or a display surface for a window. And pixels can be copied between textures and surfaces. So hardware accelerated rendering is available, as shown in the example.

As for set_mode(), flip(), and update(), they remain in Pygame SDL 2. Keeping as much of the Pygame SDL 1 API in Pygame SDL 2 is a priority. This example explores how new SDL 2 specific capabilities can be added to Pygame. It uses a Python feature unavailable when Pygame was created, the new-style class.

​My point was more that the proposed API substantially changes the way programming in pygame feels. I don't know; maybe this is necessary.​

It's worth noting that switching the graphics context between windows (to do hardware draws) isn't free, and simple code (that e.g. draws a bunch of things on two windows, switching every draw call for code clarity) might not run very well. Perhaps the API should discourage this somehow, especially if full HW drawing is encouraged.

Again I don't understand. Given a window, its renderer, and a bunch of textures: render the textures to various locations on the window, update (expose) the renderer, then repeat. How is this not hardware drawing. What am I missing?

​Mmm I realize I was not very clear. Let me try again: whenever you transition from HW drawing in one window to HW drawing into another, the windowing system (SDL, SDL2, etc.) needs to internally call something like:

wglMakeCurrent(window,context); //(on Windows)
glXMakeCurrent(display,window,context); //(on X11)
//Other platforms similar

This call does a bunch of bureaucratic stuff, mainly to rebind the GPU's destination framebuffer onto the new window's HW surface. To the point, that call is actually fairly expensive, and if you did something in a revamped pygame like:

for i in range(100):
    window1.draw(lines[i])
    window2.draw(lines[i])

Then the windowing system needs to insert 199 calls to it.

There are two options that occur to me:

1: Set up a graphics context that will be shared by all windows created. Draw calls go to a per-window hardware buffer. Then display.flip() iterates through all extant windows, binds to the window, and draws the hardware buffer into it. This adds the overhead of a second pass, but would perform okay. (It is critical that the graphics context be shared, or else draws will incur the cost of binds also and we're back to square 0. It's not hard to make graphics contexts shared, but IDK if/what SDL2 does.)

2: Discourage this pathological situation in the pygame API "somehow".

Lenard Lindstrom
​Ian​
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by Lenard Lindstrom
Hi again,

On 17-04-17 07:59 AM, Ian Mallett wrote:

> On Mon, Apr 17, 2017 at 12:01 AM, Lenard Lindstrom <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>         ​Is it possible to combine the renderer with the window? I
>         don't see why the renderer needs to be pulled out of the
>         pygame.draw module, and indeed, this could be confusing for
>         existing code.
>
>     I don't quite understand. The renderer associated with the
>     RendererWindow instance is returned by the window's renderer property.
>
>     Why are the window and the renderer separate objects? There is a
>     one-to-one relation between a window and its renderer or a display
>     surface. And a window cannot have both. To avoid duplicating a
>     bunch of window specific methods I created a Window class, with
>     RendererWindow and SurfaceWindow (not shown) as subclasses. Also,
>     a surface can have a renderer, and a combined surface-renderer
>     object makes no sense. Still, I haven't ruled out renderer-window
>     and surface-window types yet. However it is done, I don't see an
>     elegant representation of the relationships among SDL windows,
>     surfaces, renders, and textures.
>
>
> ​I guess I'm asking why they have to be separate objects. At the OS
> level, there's a region of the screen which is backed either by a
> software buffer and managed by the compositor or a GPU buffer managed
> by the compositor via the graphics context. It's a buffer either way,
> and the difference is sortof only where it lives and what operations
> are fast on it.
>
I agree that a window and its renderer or a window and its display
surface belong together as a single object. And I am looking at doing
that now. It is just I am now running into the limitations of Python and
Cython. Extension types only support single inheritance. To add full
window support—title, hiding, resizing, brightness, and more—to both a
Surface subclass and a Renderer subclass means duplicating all that
window specific code for both subclass declarations. If Cython supported
mixins (and I thought it could, but no such luck), it would be easy. It
just seemed safer avoid code duplication with a Window class instead.

> So, it's not really clear to me what a "renderer" is (I guess it's
> supposed to wrap the graphics context?).
According to the SDL Wiki, a renderer is for "2D accelerated
rendering"[1]. It "[s]upports easy rotation, scaling and alpha blending,
all accelerated using modern 3D APIs".[2] I guess it uses the GPU to
manipulate textures loaded into video memory. At least that is what the
C api suggests. And I don't see how it can be made to resemble surface
blits.

>
> Separately, I was thinking also that anything that does "rendering"
> ought to be combined with pygame.draw, because principle of least
> astonishment. However, this sortof depends on the new drawing API, and
> whether it can/should remain backward compatible with pygame.draw.
A SDL 2 renderer has little to do with pygame.draw. A renderer is a
collection of textures and some functions to draw them to a window.

>
>         For maximum backcompatibility, something like the following
>         would seem to fit better with the existing API:
>
>         surf1 = pygame.display.Window(rect1,flags)
>         surf2 = pygame.display.Window(rect2,flags)
>         #...
>         surf1.blit(...)
>         surf2.blit(...)
>         #...
>         pygame.display.flip()
>
>         I don't recall what was decided about the feasibility of
>         implementing SDL2-style or hardware-accelerated rendering, but
>         I'd hazard that this sort of API wouldn't map well to it.
>         OTOH, I don't think the decision to implement a modern
>         graphics interface was decided in the first place (just that
>         we're currently adding some SDL2 stuff).
>
>     The user can choose either a renderer or a display surface for a
>     window. And pixels can be copied between textures and surfaces. So
>     hardware accelerated rendering is available, as shown in the example.
>
>     As for set_mode(), flip(), and update(), they remain in Pygame SDL
>     2. Keeping as much of the Pygame SDL 1 API in Pygame SDL 2 is a
>     priority. This example explores how new SDL 2 specific
>     capabilities can be added to Pygame. It uses a Python feature
>     unavailable when Pygame was created, the new-style class.
>
>
> ​My point was more that the proposed API substantially changes the way
> programming in pygame feels. I don't know; maybe this is necessary.​
It will if using a renderer and textures or opening multiple windows.
But the old display surface api will remain. Also, Pygame's Python API
is old. A class based approach adds more flexibility.

>
>         It's worth noting that switching the graphics context between
>         windows (to do hardware draws) isn't free, and simple code
>         (that e.g. draws a bunch of things on two windows, switching
>         every draw call for code clarity) might not run very well.
>         Perhaps the API should discourage this somehow, especially if
>         full HW drawing is encouraged.
>
>
>     Again I don't understand. Given a window, its renderer, and a
>     bunch of textures: render the textures to various locations on the
>     window, update (expose) the renderer, then repeat. How is this not
>     hardware drawing. What am I missing?
>
>
> ​Mmm I realize I was not very clear. Let me try again: whenever you
> /transition/ from HW drawing in one window to HW drawing into another,
> the windowing system (SDL, SDL2, etc.) needs to internally call
> something like:
>
> wglMakeCurrent(window,context); //(on Windows)
> glXMakeCurrent(display,window,context); //(on X11)
> //Other platforms similar
>
> This call does a bunch of bureaucratic stuff, mainly to rebind the
> GPU's destination framebuffer onto the new window's HW surface. To the
> point, that call is actually fairly expensive, and if you did
> something in a revamped pygame like:
>
> for i in range(100):
> window1.draw(lines[i])
> window2.draw(lines[i])
>
> Then the windowing system needs to insert 199 calls to it.
>
> There are two options that occur to me:
>
> 1: Set up a graphics context that will be shared by all windows
> created. Draw calls go to a per-window hardware buffer. Then
> display.flip() iterates through all extant windows, binds to the
> window, and draws the hardware buffer into it. This adds the overhead
> of a second pass, but would perform okay. (It is /critical/ that the
> graphics context be shared, or else draws will incur the cost of binds
> also and we're back to square 0. It's not hard to make graphics
> contexts shared, but IDK if/what SDL2 does.)
I don't see anything in SDL 2 for binding contexts. Maybe SDL does that
for you. I don't know. If there is a way to do this in the SDL api, it
will get exposed in the Pygame API at some point. The OpenGL stuff will
also be added at some point.

>
> 2: Discourage this pathological situation in the pygame API "somehow".
>
Multiple windows is a feature of SDL 2. But it also works with just one,
or none.

[1] https://wiki.libsdl.org/CategoryRender

[2] https://wiki.libsdl.org/Introduction


Lenard Lindstrom

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Ian Mallett-2
On Mon, Apr 17, 2017 at 4:28 PM, Lenard Lindstrom <[hidden email]> wrote:
I agree that a window and its renderer or a window and its display surface belong together as a single object. And I am looking at doing that now. It is just I am now running into the limitations of Python and Cython. Extension types only support single inheritance. To add full window support—title, hiding, resizing, brightness, and more—to both a Surface subclass and a Renderer subclass means duplicating all that window specific code for both subclass declarations. If Cython supported mixins (and I thought it could, but no such luck), it would be easy. It just seemed safer avoid code duplication with a Window class instead.

​Unfortunately, I know next to nothing about interfacing Python with C, so I cannot suggest anything useful.​

        It's worth noting that switching the graphics context between
        windows (to do hardware draws) isn't free, and simple code
        (that e.g. draws a bunch of things on two windows, switching
        every draw call for code clarity) might not run very well.
        Perhaps the API should discourage this somehow, especially if
        full HW drawing is encouraged.


    Again I don't understand. Given a window, its renderer, and a
    bunch of textures: render the textures to various locations on the
    window, update (expose) the renderer, then repeat. How is this not
    hardware drawing. What am I missing?


​Mmm I realize I was not very clear. Let me try again: whenever you /transition/ from HW drawing in one window to HW drawing into another, the windowing system (SDL, SDL2, etc.) needs to internally call something like:

​​
wglMakeCurrent(window,context); //(on Windows)
glXMakeCurrent(display,window,context); //(on X11)
//Other platforms similar

This call does a bunch of bureaucratic stuff, mainly to rebind the GPU's destination framebuffer onto the new window's HW surface. To the point, that call is actually fairly expensive, and if you did something in a revamped pygame like:

for i in range(100):
window1.draw(lines[i])
window2.draw(lines[i])

Then the windowing system needs to insert 199 calls to it.

There are two options that occur to me:

1: Set up a graphics context that will be shared by all windows created. Draw calls go to a per-window hardware buffer. Then display.flip() iterates through all extant windows, binds to the window, and draws the hardware buffer into it. This adds the overhead of a second pass, but would perform okay. (It is /critical/ that the graphics context be shared, or else draws will incur the cost of binds also and we're back to square 0. It's not hard to make graphics contexts shared, but IDK if/what SDL2 does.)
I don't see anything in SDL 2 for binding contexts. Maybe SDL does that for you. I don't know. If there is a way to do this in the SDL api, it will get exposed in the Pygame API at some point. The OpenGL stuff will also be added at some point.

I think you misunderstand. This isn't a feature to be exposed; it's a syscall fundamental to how windowing systems work. SDL (or any other HW-drawing-supporting library) categorically must do this, because this is simply how the GPU writes to the screen.

In SDL 1.2.15, you'll find "wglMakeCurrent(...)" in "src/video/wincommon/SDL_wingl.c" and in SDL 2.0.5, in "src/video/windows/SDL_windowsopengl.c". I don't offhand know the equivalents for Direct3D / Vulkan / GLES / Metal / Mantle / etc., but I guarantee that they exist and are called, iff interfacing to the GPU through that API on that platform is supported. As the documentation for e.g. "SDL_CreateRenderer(...)" hints, a renderer is (apparently) a hardware graphics context (possibly) tied to a target window.

When you use a windowing system, you shouldn't need to call this yourself, because the whole point of a windowing system is that it handles adjudicating the OS's compositor against the GPU for you. However, I bring it up because certain use cases will lose performance because of it, if one is unaware this is happening behind your back.

It boils down to figuring out (or testing) what SDL does. Something like seeing whether this:
for i in range(100):
    window1.hw_draw(lines[i])
    window2.hw_draw(lines[i])
...is as fast as this:
for i in range(100):
    window1.hw_draw(lines[i])
for i in range(100):
    window2.hw_draw(lines[i])
If it is, no problem. If it isn't, then the above is why.

The TL;DR of this whole discussion, I guess, is simply:

Repeatedly switching the target window for draw calls during the frame is slow. However, if SDL's implementation anticipates this (and someone should check that), or if such can be configured during SDL setup, it will be less bad. Maybe we can sidestep investigating by exposing a different API.

Ian
bw
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

bw
In reply to this post by Lenard Lindstrom
Hi, Leonard,

If you're talking HW textures (which require a hardware display context), one can have multiple renderers; and it can be beneficial to do so. The renderer determines blend mode and other aspects. It could be more manageable and preferable to have a renderer for every occasion, so to speak.

Textures are not very compatible with the surface paradigm. It would behoove us to examine these side by side, and figure out a way to foster both. Surface code will likely just drop in if you keep the same API, but working with textures is a departure from the surface workflow. We do not want to try and make textures behave like surfaces, or vice versa. E.g. one does not blit a texture, and one does not flip the screen buffer. It requires one to be cognizant of what data structure one is dealing with.

IMO, support for textures should not be an afterthought. They are a premiere feature of SDL2, and will likely be appreciated and preferred as people delve into them. You folks are probably already realizing this at least a little bit. If so, then good. :)

Respectfully,
Gumm


On Sun, Apr 16, 2017 at 11:01 PM, Lenard Lindstrom <[hidden email]> wrote:
Hi Ian,

Thanks for replying.

On 17-04-16 01:43 AM, Ian Mallett wrote:
On Thu, Apr 13, 2017 at 3:25 PM, Lenard Lindstrom <[hidden email] <mailto:[hidden email]>> wrote:

    """Render an image to a window
    This is adapted from the SDL 2 example at
    <http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world
    <http://www.willusher.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world>>.
    """


​Heh, I'm friends with Will. We're at the same university.​

    import pygame
    from pygame.display import RendererWindow
    import os


    def get_resource_path():
        my_dir = os.path.dirname(os.path.abspath(__file__))
        return os.path.join(my_dir, 'data')


    def run():
        pygame.display.init()
        title = "Hello World!"
        rect = (100, 100, 640, 480)
        flags = RendererWindow.SHOWN
        with RendererWindow(title, rect, flags) as win:
            ren = win.renderer
            flags = (ren.ACCELERATED  |
                     ren.PRESENTVSYNC   )
            ren.open(flags)
            image_path = os.path.join(get_resource_path(), 'hello.bmp')
            bmp = pygame.image.load(image_path)
            tex = ren.new_texture_from_surface(bmp)

            for i in range(3):
                ren.clear()
                tex.copy_to_renderer()
                ren.update()
                pygame.time.delay(1000)
        pygame.quit()

    if __name__ == '__main__':
    run()


    A window with renderer and a window with surface are implemented
    as distinct subclasses of a standard Window extension type. Each
    Window instance is an open window on the display. Window updates
    are perform by methods on the corresponding renderer or surface.
    Window and renderer specific constants, such as SDL_WINDOW_SHOWN
    and SDL_RENDERER_ACCELERATED are class attributes, though they
    could also be included in pygame.locals.

    This is preliminary design work, so feedback is not only welcome
    but also necessary.


​Is it possible to combine the renderer with the window? I don't see why the renderer needs to be pulled out of the pygame.draw module, and indeed, this could be confusing for existing code.

I don't quite understand. The renderer associated with the RendererWindow instance is returned by the window's renderer property.

Why are the window and the renderer separate objects? There is a one-to-one relation between a window and its renderer or a display surface. And a window cannot have both. To avoid duplicating a bunch of window specific methods I created a Window class, with RendererWindow and SurfaceWindow (not shown) as subclasses. Also, a surface can have a renderer, and a combined surface-renderer object makes no sense. Still, I haven't ruled out renderer-window and surface-window types yet. However it is done, I don't see an elegant representation of the relationships among SDL windows, surfaces, renders, and textures.

For maximum backcompatibility, something like the following would seem to fit better with the existing API:

surf1 = pygame.display.Window(rect1,flags)
surf2 = pygame.display.Window(rect2,flags)
#...
surf1.blit(...)
surf2.blit(...)
#...
pygame.display.flip()

I don't recall what was decided about the feasibility of implementing SDL2-style or hardware-accelerated rendering, but I'd hazard that this sort of API wouldn't map well to it. OTOH, I don't think the decision to implement a modern graphics interface was decided in the first place (just that we're currently adding some SDL2 stuff).
The user can choose either a renderer or a display surface for a window. And pixels can be copied between textures and surfaces. So hardware accelerated rendering is available, as shown in the example.

As for set_mode(), flip(), and update(), they remain in Pygame SDL 2. Keeping as much of the Pygame SDL 1 API in Pygame SDL 2 is a priority. This example explores how new SDL 2 specific capabilities can be added to Pygame. It uses a Python feature unavailable when Pygame was created, the new-style class.


It's worth noting that switching the graphics context between windows (to do hardware draws) isn't free, and simple code (that e.g. draws a bunch of things on two windows, switching every draw call for code clarity) might not run very well. Perhaps the API should discourage this somehow, especially if full HW drawing is encouraged.

Again I don't understand. Given a window, its renderer, and a bunch of textures: render the textures to various locations on the window, update (expose) the renderer, then repeat. How is this not hardware drawing. What am I missing?

SDL 2 supports multiple open windows. Pygame will too. Let the designer choose how many windows are open, and if hardware acceleration is appropriate. Not all Pygame applications need be fast-paced games.

Lenard Lindstrom



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Leif Theden
The renderer should have its own class, and for simplicity, I think it should be instanced by calling a method on the window that contains it.  Just preference.

Renderer does not below with the draw module, because it is not for drawing lines, and primitives on software surface.  It is a cross-platform and simple API for high-speed accelerated graphics with textures and includes some facilities for drawing primitives.

==============================================================
What about something like this?


import pygame as pg

window = pg.display.new_window()        # new Window class method
screen = pg.display.set_mode(...)       # creates a new window, return surface

renderer = window.create_renderer()     # renderer, yay!
renderer = pg.renderer.Renderer(window) # alternative. "window" optional


surf = pg.image.load(filename)
texture = renderer.create_texture(surface=surf)       # clean syntax?
texture = pg.texture.from_surface(surface, renderer)  # alternative, "renderer" optional


while running:

   renderer.clear()                        # you should do this each frame

   for tex, rect in textures:
      renderer.render_copy(tex, rect)      # this is analogous to "blit", but is HW accel'd

   renderer.present()                      # like display.flip()


==============================================================
# texture sprites

sprite = pg.sprite.TextureSprite()
sprite.texture = tex
sprite.rect = text.get_rect()
sprite.origin = 0, 0      # where the origin of texture is
sprite.rotation = 76      # rotation of the sprite

group = renderer.create_group(all_the_sprites, flags=0xDEADBEEF)  # clean?
group = pg.sprite.TextureSpriteGroup(renderer)                    # alternative

==============================================================
# sample of a SpriteGroup
# Group.add

if hasattr(sprite, 'texture'):
   raise ICannotDoThatDaveError   # legacy group will not render a texture sprite


# TextureSpriteGroup.draw
for sprite in self._hw_sprites:
   renderer.render_copy_ex(sprite.tex,
                           None,
                           sprite.rect,
                           sprite.rotation,
                           sprite.origin,
                           sprite.flipped)

The group module should become simplified.  Choose a group type that works well for software sprites, and develop a new one for Renderers.  Add some checks to legacy groups to prevent Sprites with textures from being added.

==============================================================

# pygame.display will be an alias for a Window


pygame.init()
window = pygame.display.get_window(0)   # return instance of created window

>>> window is pygame.display
True


==============================================================
# Consider the following


  • When a renderer is created for a window, the window will raise an exception if a blit or draw is attempted on it.
  • All windows are py1 until a renderer is created on it.
  • Once renderer is created, leave window in renderer mode. (or not?)
  • Blits between software surfaces will always work, regardless of the window mode.
screen = pg.display.set_mode(...)  # automatic py1 window
screen.blit(legacy_cruft)          # works!

renderer = pg.display.create_renderer()  # works b/c display is alias to first window
renderer = pg.renderer.Renderer()        # implicit 1st window as target of renderer

screen.blit(oops)                      # raise ThouShaltNotBlitError
pg.draw.lines(screen, ...)             # raise ThouShaltNotDrawUponThyScreenError

==============================================================
 

There is no way forward to give old pygame apps free performance.  New pygame apps will need to choose to use the accelerated graphics API, or not.



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by Lenard Lindstrom
Hi Gumm,

Renderers and textures will be a part of Pygame. They will be new
features rather than disguised as blits to a display surface. SDL 2
supports display surface as well, so Pygame will continue to do so as
well. My intention is add all this, plus multi-window support, with the
addition of new classes to what already exists in Pygame.

An SDL Window can have only one rendering context, or renderer. Now a
renderer can have multiple textures, with render mode a per-texture
feature. All that will be supported.

Lenard Lindstrom

On 17-04-17 04:17 PM, B W wrote:

> Hi, Leonard,
>
> If you're talking HW textures (which require a hardware display
> context), one can have multiple renderers; and it can be beneficial to
> do so. The renderer determines blend mode and other aspects. It could
> be more manageable and preferable to have a renderer for every
> occasion, so to speak.
>
> Textures are not very compatible with the surface paradigm. It would
> behoove us to examine these side by side, and figure out a way to
> foster both. Surface code will likely just drop in if you keep the
> same API, but working with textures is a departure from the surface
> workflow. We do not want to try and make textures behave like
> surfaces, or vice versa. E.g. one does not blit a texture, and one
> does not flip the screen buffer. It requires one to be cognizant of
> what data structure one is dealing with.
>
> IMO, support for textures should not be an afterthought. They are a
> premiere feature of SDL2, and will likely be appreciated and preferred
> as people delve into them. You folks are probably already realizing
> this at least a little bit. If so, then good. :)
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by bw
Hi Leif,

On 17-04-18 09:10 AM, Leif Theden wrote:
> The renderer should have its own class, and for simplicity, I think it
> should be instanced by calling a method on the window that contains
> it.  Just preference.
>
Having both a Window and a Renderer class makes sense if renderers are
cheap to create and discard. For practical purposes, a window's renderer
will live as long as it's window. If a Window class has a
create_renderer() method, then what happens when it is called more then
once. Also, what happens to the renderer instance when the window is
closed. Does the renderer keep a reference to the Window? Does the
Window keep a reference to the renderer? How is a reference cycle prevented?

To complicate matters, a window can have a display surface instead of a
renderer. So we add a create_surface() method. Now the Window class must
track whether it has a renderer or a surface. And a Pygame Surface does
not know about windows. So if we want the Surface instance to reference
a window we need a new WindowSurface subclass.

My thinking is if we need a WindowSurface to reference a window, then it
can directly manage the SDL window as well. The same goes for a
WindowRenderer Renderer subclass. Everything relating to a particular
window is in one convenient place. And when the window is closed, there
is only one, not two, dead objects lying around.

Now I have experimented with separate Window and Renderer. I found a
somewhat acceptable solution to the problems mentioned above. But it
still felt clunky. Then, when I combined the window and renderer into on
class, much of the complexity went away. The only real downside is that
the window management code, the window method definitions, will be
duplicated in both the WindowRenderer and WindowSurface classes. But
then that is just cut and paste, provide one remembers to do it.

Lenard Lindstrom

> Renderer does not below with the draw module, because it is not for
> drawing lines, and primitives on software surface.  It is a
> cross-platform and simple API for high-speed accelerated graphics with
> textures and includes some facilities for drawing primitives.
>
> ==============================================================
> What about something like this?
>
>
> import pygame as pg
>
> window = pg.display.new_window()        # new Window class method
> screen = pg.display.set_mode(...)       # creates a new window, return
> surface
>
> renderer = window.create_renderer()     # renderer, yay!
> renderer = pg.renderer.Renderer(window) # alternative. "window" optional
>
>
> surf = pg.image.load(filename)
> texture = renderer.create_texture(surface=surf)       # clean syntax?
> texture = pg.texture.from_surface(surface, renderer)  # alternative,
> "renderer" optional
>
>
> while running:
> renderer.clear()                        # you should do this each frame
>
>    for tex, rect in textures:
> renderer.render_copy(tex, rect)      # this is analogous to "blit",
> but is HW accel'd
>
> renderer.present()                      # like display.flip()
>
>
> ==============================================================
> # texture sprites
>
> sprite = pg.sprite.TextureSprite()
> sprite.texture = tex
> sprite.rect = text.get_rect()
> sprite.origin = 0, 0      # where the origin of texture is
> sprite.rotation = 76      # rotation of the sprite
>
> group = renderer.create_group(all_the_sprites, flags=0xDEADBEEF)  # clean?
> group = pg.sprite.TextureSpriteGroup(renderer) # alternative
>
> ==============================================================
> # sample of a SpriteGroup
> # Group.add
>
> if hasattr(sprite, 'texture'):
> raise ICannotDoThatDaveError   # legacy group will not render a
> texture sprite
>
>
> # TextureSpriteGroup.draw
> for sprite in self._hw_sprites:
> renderer.render_copy_ex(sprite.tex,
> None,
> sprite.rect,
> sprite.rotation,
> sprite.origin,
> sprite.flipped)
>
> The group module should become simplified.  Choose a group type that
> works well for software sprites, and develop a new one for Renderers.  
> Add some checks to legacy groups to prevent Sprites with textures from
> being added.
>
> ==============================================================
>
> # pygame.display will be an alias for a Window
>
>
> pygame.init()
> window = pygame.display.get_window(0)   # return instance of created
> window
>
> >>> window is pygame.display
> True
>
>
> ==============================================================
> # Consider the following
>
>   * When a renderer is created for a window, the window will raise an
>     exception if a blit or draw is attempted on it.
>   * All windows are py1 until a renderer is created on it.
>   * Once renderer is created, leave window in renderer mode. (or not?)
>   * Blits between software surfaces will always work, regardless of
>     the window mode.
>
> screen = pg.display.set_mode(...)  # automatic py1 window
> screen.blit(legacy_cruft) # works!
>
> renderer = pg.display.create_renderer()  # works b/c display is alias
> to first window
> renderer = pg.renderer.Renderer()        # implicit 1st window as
> target of renderer
>
> screen.blit(oops) # raise ThouShaltNotBlitError
> pg.draw.lines(screen, ...)             # raise
> ThouShaltNotDrawUponThyScreenError
>
> ==============================================================
>
>
> There is no way forward to give old pygame apps free performance.  New
> pygame apps will need to choose to use the accelerated graphics API,
> or not.
>
>
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Daniel Foerster

On 04/19/2017 01:16 AM, Lenard Lindstrom wrote:
>
> Now I have experimented with separate Window and Renderer. I found a
> somewhat acceptable solution to the problems mentioned above. But it
> still felt clunky. Then, when I combined the window and renderer into
> on class, much of the complexity went away. The only real downside is
> that the window management code, the window method definitions, will
> be duplicated in both the WindowRenderer and WindowSurface classes.
> But then that is just cut and paste, provide one remembers to do it.

Why cut and paste when you can factor it out into a WindowBase class?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Leif Theden
In reply to this post by Lenard Lindstrom
While I can understand why you wouldn't like the create_XXXX syntax, I'm not convinced that combining the window and the renderer makes sense for the API.  As was mentioned, a window can have multiple renderers (or none at all!), so I'm not sure what combining them together grants for pygame users.


> Does the renderer keep a reference to the Window? Does the Window keep a reference to the renderer? How is a reference cycle prevented?

I don't believe that you would need to keep references to a parent window for renderers, or that you would need them for windows.  The SDL2 API will take care of those details.  (hopefully?)

I don't agree that separate renderers and windows should feel clunky.  Pygame's API is rife with the pattern of creating objects for something, then setting attributes and using them.  Why would it be any different if you create a Renderer?

My last point about Windows tracking if they have a renderer or not (and raising exceptions when using the old surface api) was simply a way to allow the pygame API to remain backwards compatible and also use the renderer api, if desired....Without resorting to different window classes, as your API demo suggests.


On Wed, Apr 19, 2017 at 1:16 AM, Lenard Lindstrom <[hidden email]> wrote:
Hi Leif,

On 17-04-18 09:10 AM, Leif Theden wrote:
The renderer should have its own class, and for simplicity, I think it should be instanced by calling a method on the window that contains it.  Just preference.

Having both a Window and a Renderer class makes sense if renderers are cheap to create and discard. For practical purposes, a window's renderer will live as long as it's window. If a Window class has a create_renderer() method, then what happens when it is called more then once. Also, what happens to the renderer instance when the window is closed. Does the renderer keep a reference to the Window? Does the Window keep a reference to the renderer? How is a reference cycle prevented?

To complicate matters, a window can have a display surface instead of a renderer. So we add a create_surface() method. Now the Window class must track whether it has a renderer or a surface. And a Pygame Surface does not know about windows. So if we want the Surface instance to reference a window we need a new WindowSurface subclass.

My thinking is if we need a WindowSurface to reference a window, then it can directly manage the SDL window as well. The same goes for a WindowRenderer Renderer subclass. Everything relating to a particular window is in one convenient place. And when the window is closed, there is only one, not two, dead objects lying around.

Now I have experimented with separate Window and Renderer. I found a somewhat acceptable solution to the problems mentioned above. But it still felt clunky. Then, when I combined the window and renderer into on class, much of the complexity went away. The only real downside is that the window management code, the window method definitions, will be duplicated in both the WindowRenderer and WindowSurface classes. But then that is just cut and paste, provide one remembers to do it.

Lenard Lindstrom

Renderer does not below with the draw module, because it is not for drawing lines, and primitives on software surface.  It is a cross-platform and simple API for high-speed accelerated graphics with textures and includes some facilities for drawing primitives.

==============================================================
What about something like this?


import pygame as pg

window = pg.display.new_window()        # new Window class method
screen = pg.display.set_mode(...)       # creates a new window, return surface

renderer = window.create_renderer()     # renderer, yay!
renderer = pg.renderer.Renderer(window) # alternative. "window" optional


surf = pg.image.load(filename)
texture = renderer.create_texture(surface=surf)       # clean syntax?
texture = pg.texture.from_surface(surface, renderer)  # alternative, "renderer" optional


while running:
renderer.clear()                        # you should do this each frame

   for tex, rect in textures:
renderer.render_copy(tex, rect)      # this is analogous to "blit", but is HW accel'd

renderer.present()                      # like display.flip()


==============================================================
# texture sprites

sprite = pg.sprite.TextureSprite()
sprite.texture = tex
sprite.rect = text.get_rect()
sprite.origin = 0, 0      # where the origin of texture is
sprite.rotation = 76      # rotation of the sprite

group = renderer.create_group(all_the_sprites, flags=0xDEADBEEF)  # clean?
group = pg.sprite.TextureSpriteGroup(renderer) # alternative

==============================================================
# sample of a SpriteGroup
# Group.add

if hasattr(sprite, 'texture'):
raise ICannotDoThatDaveError   # legacy group will not render a texture sprite


# TextureSpriteGroup.draw
for sprite in self._hw_sprites:
renderer.render_copy_ex(sprite.tex,
None,
sprite.rect,
sprite.rotation,
sprite.origin,
sprite.flipped)

The group module should become simplified.  Choose a group type that works well for software sprites, and develop a new one for Renderers.  Add some checks to legacy groups to prevent Sprites with textures from being added.

==============================================================

# pygame.display will be an alias for a Window


pygame.init()
window = pygame.display.get_window(0)   # return instance of created window

>>> window is pygame.display
True


==============================================================
# Consider the following

  * When a renderer is created for a window, the window will raise an
    exception if a blit or draw is attempted on it.
  * All windows are py1 until a renderer is created on it.
  * Once renderer is created, leave window in renderer mode. (or not?)
  * Blits between software surfaces will always work, regardless of
    the window mode.

screen = pg.display.set_mode(...)  # automatic py1 window
screen.blit(legacy_cruft) # works!

renderer = pg.display.create_renderer()  # works b/c display is alias to first window
renderer = pg.renderer.Renderer()        # implicit 1st window as target of renderer

screen.blit(oops) # raise ThouShaltNotBlitError
pg.draw.lines(screen, ...)             # raise ThouShaltNotDrawUponThyScreenError

==============================================================


There is no way forward to give old pygame apps free performance.  New pygame apps will need to choose to use the accelerated graphics API, or not.





Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by Lenard Lindstrom
Hello,

On 17-04-19 04:26 PM, Leif Theden wrote:
> While I can understand why you wouldn't like the create_XXXX syntax,
> I'm not convinced that combining the window and the renderer makes
> sense for the API.  As was mentioned, a window can have multiple
> renderers (or none at all!), so I'm not sure what combining them
> together grants for pygame users.

No, a window can have only one renderer at a time. And a renderer will
have only one window in its lifetime.

However, after a bit of experimenting I find a window can have both a
renderer and a display surface. This does support a separate window
object. Whether or not it is useful, I don't know.

Anyway, I am still getting a handle on SDL 2, so don't favor any
particular approach yet.


Lenard Lindstrom

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Leif Theden
While I have not personally tested it, there seems to be more evidence that windows can contain (use?  manage?) more than one Renderer:
I'll just stop the back-and-forth and say that I don't support RendererWindow, but I support separate Window and Renderer objects.

On Wed, Apr 19, 2017 at 11:12 PM, Lenard Lindstrom <[hidden email]> wrote:
Hello,

On 17-04-19 04:26 PM, Leif Theden wrote:
While I can understand why you wouldn't like the create_XXXX syntax, I'm not convinced that combining the window and the renderer makes sense for the API.  As was mentioned, a window can have multiple renderers (or none at all!), so I'm not sure what combining them together grants for pygame users.

No, a window can have only one renderer at a time. And a renderer will have only one window in its lifetime.

However, after a bit of experimenting I find a window can have both a renderer and a display surface. This does support a separate window object. Whether or not it is useful, I don't know.

Anyway, I am still getting a handle on SDL 2, so don't favor any particular approach yet.


Lenard Lindstrom


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Greg Ewing
In reply to this post by Lenard Lindstrom
Lenard Lindstrom wrote:
> Extension type WindowSurface would add an SDL window C pointer to its
> pygame.Surface parent. This window pointer cannot be factored out into a
> separate WindowBase parent class. And any methods which access that
> pointer will be specific to WindowSurface's C structure type.

And consequently, it would be impossible to write code that
generically works with either type of window at the C level
without going through Python method or property dispatch.

> * Cython has an include statement. Unfortunately, include statements are
> not allowed in class declarations.

Even if it worked, the effect would be no different from
writing out a copy of the code in each class. You would still
have two unrelated sets of fields with different offsets.

Splitting it into two objects sounds like the best solution
to me. Then you can have a Window object with the same interface
whether it has a Renderer or a Surface attached, and a Renderer
with the same interface whether it's attached to a Window
or something else.

--
Greg
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Greg Ewing
In reply to this post by Lenard Lindstrom
Lenard Lindstrom wrote:
> However, after a bit of experimenting I find a window can have both a
> renderer and a display surface.

In that case, I'd suggest the Window object should have
'renderer' and 'surface' attributes. If the Renderer or
Surface keeps a reference back to the window, it should
probably be a weak reference, so that they won't keep
each other alive.

If code that uses the Renderer or Surface obtains it
from the Window when needed and doesn't store a reference
to it long-term, then dropping the Window will cause
the whole lot to disappear.

--
Greg


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Greg Ewing
In reply to this post by Leif Theden
Leif Theden wrote:
> While I have not personally tested it, there seems to be more evidence
> that windows can contain (use?  manage?) more than one Renderer:

If that's true, then it might make sense for the Renderer to have
a 'window' attribute. The Renderer would then be the thing you
keep a long-term reference to, and you would obtain the Window
from it when needed.

--
Greg
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Ian Mallett-2
​Hi,

I dug around in the SDL 2 source (mostly "src/render/*"). As I suspected, for hardware renderers, a renderer is essentially a graphics context. This means that:

1: A renderer is more-or-less decoupled from a window. Each window can be bound to up to one renderer, and each renderer can be bound to up to one window.
2: There can be many renderers and many windows.

On Thu, Apr 20, 2017 at 12:30 AM, Greg Ewing <[hidden email]> wrote:
If that's true, then it might make sense for the Renderer to have
a 'window' attribute. The Renderer would then be the thing you
keep a long-term reference to, and you would obtain the Window
from it when needed.

​I like this idea a lot, modulo that you should also store the reference to the window.

If draws are done through the renderer, then to change the window, you need to change the renderer's pointer. This makes the problem I described a few days ago less hidden to the user. Exposing things in this way feels somehow "right" to me.

Ian
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re[2]: [pygame] Pygame for SDL 2, and how it may look.

Marcus von Appen
In reply to this post by Greg Ewing


On 4/20/2017 8:13:22 AM, "Greg Ewing" <[hidden email]>
wrote:

>Lenard Lindstrom wrote:
>>However, after a bit of experimenting I find a window can have both a
>>renderer and a display surface.
>
>In that case, I'd suggest the Window object should have
>'renderer' and 'surface' attributes. If the Renderer or
>Surface keeps a reference back to the window, it should
>probably be a weak reference, so that they won't keep
>each other alive.

You (not necessarily pointed towards Greg) definitely should dig deeper
into the SDL renderer API.

Renderers can be created for windows, surfaces (and window surfaces).
You can retrieve a renderer for a window (via SDL_GetRenderer()).

Avoid pythonic OO pitfalls, which will create a reference mess. Keep
both, renderers and windows separate and use dynamic properties
(if necessary) instead.

Personally, I'd leave it up to the user code instead of getting in the
way.

Cheers
Marcus

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pygame for SDL 2, and how it may look.

Lenard Lindstrom
In reply to this post by Lenard Lindstrom
Thanks for the link. I had not even thought of OpenGL yet. OpenGL was
something to be tackled later.

One thing to note though, a programming choice in C may not make sense
in a higher level language such as Python. C encourages choices based on
physical data representations. Python types and objects allow for
abstractions independent of physical representation. So Classes can be
designed around what you want to do, not what you are actually working
on. Too me, if there was a strict one-to-one relation between a window
and a renderer, then why not have an object that can be both a renderer
and a window.

But yes, if a separate Window and Renderer is more intuitive to most
people, then that is the way to go. Anyway, the complicated, and unclear
to me, window/renderer relationship makes a combined object a
questionable choice.

Lenard Lindstrom

On 17-04-19 10:54 PM, Leif Theden wrote:

> While I have not personally tested it, there seems to be more evidence
> that windows can contain (use?  manage?) more than one Renderer:
>
> https://forums.libsdl.org/viewtopic.php?t=10187&postdays=0&postorder=asc&start=15&sid=3fe959dc04bb7cd484c3ee453df8f5de
>
>
> I'll just stop the back-and-forth and say that I don't support
> RendererWindow, but I support separate Window and Renderer objects.
>
> On Wed, Apr 19, 2017 at 11:12 PM, Lenard Lindstrom <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     Hello,
>
>     On 17-04-19 04:26 PM, Leif Theden wrote:
>
>         While I can understand why you wouldn't like the create_XXXX
>         syntax, I'm not convinced that combining the window and the
>         renderer makes sense for the API. As was mentioned, a window
>         can have multiple renderers (or none at all!), so I'm not sure
>         what combining them together grants for pygame users.
>
>
>     No, a window can have only one renderer at a time. And a renderer
>     will have only one window in its lifetime.
>
>     However, after a bit of experimenting I find a window can have
>     both a renderer and a display surface. This does support a
>     separate window object. Whether or not it is useful, I don't know.
>
>     Anyway, I am still getting a handle on SDL 2, so don't favor any
>     particular approach yet.
>
>
>     Lenard Lindstrom
>
>

12
Loading...