Multithreading & video

Hi,

The FAQ says: you should not access video functions from a thread.
Now I am wondering: does this also apply if you ONLY access video
functions from thread B(!), and only do event/audio-functions from
thread A?

Folkert van Heusden–
MultiTail is a versatile tool for watching logfiles and output of
commands. Filtering, coloring, merging, diff-view, etc.
http://www.vanheusden.com/multitail/

Phone: +31-6-41278122, PGP-key: 1F28D8AE, www.vanheusden.com

Nope, in the 1.2 versions of SDL you must do event processing and video
functions (rendering, flipping,…) in the same thread and that must be the
main thread of the application.On Tue, Aug 5, 2008 at 7:43 AM, Folkert van Heusden wrote:

Hi,

The FAQ says: you should not access video functions from a thread.
Now I am wondering: does this also apply if you ONLY access video
functions from thread B(!), and only do event/audio-functions from
thread A?

Folkert van Heusden


MultiTail is a versatile tool for watching logfiles and output of
commands. Filtering, coloring, merging, diff-view, etc.
http://www.vanheusden.com/multitail/

Phone: +31-6-41278122, PGP-key: 1F28D8AE, www.vanheusden.com


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

What video functions are that?

In our game, we do a lot of asynchron blitting and other pixel-wise
manipulations on surfaces (of course with locking/unlocking them) at the
same time.

We even have started to do the SDL_Flip in an own thread as in some
situations, SDL_Flip is very slow.On Tue, 2008-08-05 at 09:58 -0500, Bob Pendleton wrote:

Nope, in the 1.2 versions of SDL you must do event processing and
video functions (rendering, flipping,…) in the same thread and that
must be the main thread of the application.

On Tue, Aug 5, 2008 at 7:43 AM, Folkert van Heusden wrote:
Hi,

    The FAQ says: you should not access video functions from a
    thread.
    Now I am wondering: does this also apply if you ONLY access
    video
    functions from thread B(!), and only do event/audio-functions
    from
    thread A?
    
    
    Folkert van Heusden
    
    --
    MultiTail is a versatile tool for watching logfiles and output
    of
    commands. Filtering, coloring, merging, diff-view, etc.
    http://www.vanheusden.com/multitail/
    ----------------------------------------------------------------------
    Phone: +31-6-41278122, PGP-key: 1F28D8AE, www.vanheusden.com
    _______________________________________________
    SDL mailing list
    SDL at lists.libsdl.org
    http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

The behaviour of doing that is undefined. Undefined includes such
behaviour as “works perfectly”, “appears to work perfectly” and
"crashes horribly". Moving between platforms, or possibly even to a
different configuration on the same platform, could break your program
and force you to make large structural modifications to the code to
change it to work with the documented API.On Tue, Aug 5, 2008 at 4:05 PM, Albert Zeyer <albert.zeyer at rwth-aachen.de> wrote:

What video functions are that?

In our game, we do a lot of asynchron blitting and other pixel-wise
manipulations on surfaces (of course with locking/unlocking them) at the
same time.

We even have started to do the SDL_Flip in an own thread as in some
situations, SDL_Flip is very slow.

Which other possibilities are there to do asynchronous blitting?On Tue, 2008-08-05 at 17:10 +0100, Brian wrote:

The behaviour of doing that is undefined. Undefined includes such
behaviour as “works perfectly”, “appears to work perfectly” and
"crashes horribly". Moving between platforms, or possibly even to a
different configuration on the same platform, could break your program
and force you to make large structural modifications to the code to
change it to work with the documented API.

On Tue, Aug 5, 2008 at 4:05 PM, Albert Zeyer <@Albert_Zeyer> wrote:

What video functions are that?

In our game, we do a lot of asynchron blitting and other pixel-wise
manipulations on surfaces (of course with locking/unlocking them) at the
same time.

We even have started to do the SDL_Flip in an own thread as in some
situations, SDL_Flip is very slow.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Any chance that this will change in the future? Because I have an
application for which 2 seperate threads (on seperate cores of course)
will benefit a lot (an emulator which displays 50 frames a second).

Nope, in the 1.2 versions of SDL you must do event processing and video
functions (rendering, flipping,…) in the same thread and that must be the
main thread of the application.

The FAQ says: you should not access video functions from a thread.
Now I am wondering: does this also apply if you ONLY access video
functions from thread B(!), and only do event/audio-functions from
thread A?

Folkert van Heusden–
MultiTail is a versatile tool for watching logfiles and output of
commands. Filtering, coloring, merging, diff-view, etc.
http://www.vanheusden.com/multitail/

Phone: +31-6-41278122, PGP-key: 1F28D8AE, www.vanheusden.com

Brian wrote:

The behaviour of doing that is undefined. Undefined includes such
behaviour as “works perfectly”, “appears to work perfectly” and
"crashes horribly". Moving between platforms, or possibly even to a
different configuration on the same platform, could break your program
and force you to make large structural modifications to the code to
change it to work with the documented API.

Since we’re talking about multi-threading, it could even crash randomly
on the same platform and configuration where you thought it was working
perfectly. Threading errors are notoriously difficult to catch.–
Rainer Deyke - rainerd at eldwood.com

Brian wrote:

The behaviour of doing that is undefined. Undefined includes such
behaviour as “works perfectly”, “appears to work perfectly” and
"crashes horribly". Moving between platforms, or possibly even to a
different configuration on the same platform, could break your program
and force you to make large structural modifications to the code to
change it to work with the documented API.

Since we’re talking about multi-threading, it could even crash randomly
on the same platform and configuration where you thought it was working
perfectly. Threading errors are notoriously difficult to catch.

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?On Wed, 2008-08-06 at 02:28 -0600, Rainer Deyke wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

A good article about this is Bob Pendleton’s “Animation in SDL:
Hardware Surfaces” ->
http://www.linuxdevcenter.com/pub/a/linux/2003/08/07/sdl_anim.html?page=1

All Bob’s articles are worth a read (http://www.oreillynet.com/pub/au/1205).

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

Hi,

I guess that the only safe way would be to do direct
pixel access, since the SDL graphics Api expects to be used
just from the main thread.–
Paulo

Quoting Albert Zeyer <albert.zeyer at rwth-aachen.de>:

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


This message was sent using IMP, the Internet Messaging Program.

There are, fundamentally, only really a couple of ways of doing multi-threaded programming.

Given that SDL currently has some restrictions on what you can and can’t thread, the best solution - if your really need to implement drawing from different threads - is to implement a message queue.

That is, rather than writing to the surface directly, you call a function that adds the drawing operation onto a list of things to do. Your main thread periodically executes the drawing operations in the queue (either automatically or when a function is called). This is, in a nutshell, how OpenGL works.

This actually has many advantages - it’s easier to get the locking semantics right, as you’re probably only having a couple of things actually accessed by multiple threads, especially if you pass data into the queue by value. The key disadvantage is the extra code required and, as you almost certainly WON’T be passing by value, you’ll still need to worry about (dead)locking and starvation.

All-in-all, it’s almost certainly better (more efficient, easier to understand, write and debug) to modify your design to only do drawing in a single place.

Eddy________________________________________
From: sdl-bounces@lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Albert Zeyer [albert.zeyer at rwth-aachen.de]
Sent: 06 August 2008 12:14
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Hi,

At what point did it expect that? At what possible other point could
there be an access to the surface? Except the event handling
(SDL_GetKeyState, SDL_GetMouseState, SDL_WaitEvent, SDL_PollEvent), I am
calling no other SDL functions in my main thread and I doubt that the
SDL event handling functions are related in any way to the surfaces (or
am I wrong here? but then there is a design flaw in SDL, 'cause
SDL_PollEvent() and friends should not do stuff with some surfaces).
Therefore, why does it matter if SDL_BlitSurface() and friends are
called from the main thread or all together from another thread?

And this situation:
Surface[4], Thread[2]

Thread[0]: Blit(Surface[1],Surface[0])
Thread[1]: Blit(Surface[3],Surface[2])

Why is that not possible? Is it because of bad code in Blit which
depends on static vars?

But even then, if I would assure somehow that there is only one Blit at
a time (for example by writing a Blit-Wrapper with a simple mutex), why
could it be a problem when I call it from different threads?

Or to do it in a more efficient way, I am thinking of implementing
something like this:

class Surface {
private:
SDL_Surface* s;
SDL_mutex* m;
list blits;
void forceUpdate() {
// do blits and other stuff
// force updates for all surfaces we depend on
}
public:
void blit(Surface* other) {
m.lock();
blits.add(other, params);
m.unlock();
}

// for direct pixel access
void lock() { m.lock(); forceUpdate(); }
void unlock() { m.unlock(); }

}

– AlbertOn Wed, 2008-08-06 at 14:58 +0200, Paulo Pinto wrote:

Hi,

I guess that the only safe way would be to do direct
pixel access, since the SDL graphics Api expects to be used
just from the main thread.


Paulo

Quoting Albert Zeyer <@Albert_Zeyer>:

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


This message was sent using IMP, the Internet Messaging Program.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I wouldn’t say ‘bad code’, I would say ‘code written to be efficient when used in a certain way’.

Threading is (still) one of the most difficult problems in computer science, even though the theory is almost all over 20 years old.

Using threads adds overhead. This overhead can be massive. The design of SDL is intended to be ‘Simple’; to give the best performance it can most of the time.

Most of the time, an (experience) game developer will do drawing in a single thread, therefore, the decision was made to optimise SDL’s drawing routines toward that use case.

Eddy________________________________________
From: sdl-bounces@lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Albert Zeyer [albert.zeyer at rwth-aachen.de]
Sent: 06 August 2008 15:09
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

Hi,

At what point did it expect that? At what possible other point could
there be an access to the surface? Except the event handling
(SDL_GetKeyState, SDL_GetMouseState, SDL_WaitEvent, SDL_PollEvent), I am
calling no other SDL functions in my main thread and I doubt that the
SDL event handling functions are related in any way to the surfaces (or
am I wrong here? but then there is a design flaw in SDL, 'cause
SDL_PollEvent() and friends should not do stuff with some surfaces).
Therefore, why does it matter if SDL_BlitSurface() and friends are
called from the main thread or all together from another thread?

And this situation:
Surface[4], Thread[2]

Thread[0]: Blit(Surface[1],Surface[0])
Thread[1]: Blit(Surface[3],Surface[2])

Why is that not possible? Is it because of bad code in Blit which
depends on static vars?

But even then, if I would assure somehow that there is only one Blit at
a time (for example by writing a Blit-Wrapper with a simple mutex), why
could it be a problem when I call it from different threads?

Or to do it in a more efficient way, I am thinking of implementing
something like this:

class Surface {
private:
SDL_Surface* s;
SDL_mutex* m;
list blits;
void forceUpdate() {
// do blits and other stuff
// force updates for all surfaces we depend on
}
public:
void blit(Surface* other) {
m.lock();
blits.add(other, params);
m.unlock();
}

    // for direct pixel access
    void lock() { m.lock(); forceUpdate(); }
    void unlock() { m.unlock(); }

}

– Albert

On Wed, 2008-08-06 at 14:58 +0200, Paulo Pinto wrote:

Hi,

I guess that the only safe way would be to do direct
pixel access, since the SDL graphics Api expects to be used
just from the main thread.


Paulo

Quoting Albert Zeyer <albert.zeyer at rwth-aachen.de>:

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


This message was sent using IMP, the Internet Messaging Program.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Yes, I understand that, but that does not directly answer my questions.

Also, despite that it is easier to have a single threaded application,
this is not really the way to go in future. You see it already, it is
normal to have at least 2 cores in a machine and it is becoming more and
more. Also the graphics card has a lot of cores. In a few years, you
will probably have 8, 16 or more cores in your computer. It is just not
possible anymore if you want your game to be efficient to just make
everything in one single thread.

And as all the software pixel operations do take far the most time in
most games, it is most important to do that multithreaded.On Wed, 2008-08-06 at 15:13 +0100, cullen e.a. (eac203) wrote:

I wouldn’t say ‘bad code’, I would say ‘code written to be efficient when used in a certain way’.

Threading is (still) one of the most difficult problems in computer science, even though the theory is almost all over 20 years old.

Using threads adds overhead. This overhead can be massive. The design of SDL is intended to be ‘Simple’; to give the best performance it can most of the time.

Most of the time, an (experience) game developer will do drawing in a single thread, therefore, the decision was made to optimise SDL’s drawing routines toward that use case.

Eddy


From: sdl-bounces at lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Albert Zeyer [@Albert_Zeyer]
Sent: 06 August 2008 15:09
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

Hi,

At what point did it expect that? At what possible other point could
there be an access to the surface? Except the event handling
(SDL_GetKeyState, SDL_GetMouseState, SDL_WaitEvent, SDL_PollEvent), I am
calling no other SDL functions in my main thread and I doubt that the
SDL event handling functions are related in any way to the surfaces (or
am I wrong here? but then there is a design flaw in SDL, 'cause
SDL_PollEvent() and friends should not do stuff with some surfaces).
Therefore, why does it matter if SDL_BlitSurface() and friends are
called from the main thread or all together from another thread?

And this situation:
Surface[4], Thread[2]

Thread[0]: Blit(Surface[1],Surface[0])
Thread[1]: Blit(Surface[3],Surface[2])

Why is that not possible? Is it because of bad code in Blit which
depends on static vars?

But even then, if I would assure somehow that there is only one Blit at
a time (for example by writing a Blit-Wrapper with a simple mutex), why
could it be a problem when I call it from different threads?

Or to do it in a more efficient way, I am thinking of implementing
something like this:

class Surface {
private:
SDL_Surface* s;
SDL_mutex* m;
list blits;
void forceUpdate() {
// do blits and other stuff
// force updates for all surfaces we depend on
}
public:
void blit(Surface* other) {
m.lock();
blits.add(other, params);
m.unlock();
}

    // for direct pixel access
    void lock() { m.lock(); forceUpdate(); }
    void unlock() { m.unlock(); }

}

– Albert

On Wed, 2008-08-06 at 14:58 +0200, Paulo Pinto wrote:

Hi,

I guess that the only safe way would be to do direct
pixel access, since the SDL graphics Api expects to be used
just from the main thread.


Paulo

Quoting Albert Zeyer <@Albert_Zeyer>:

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


This message was sent using IMP, the Internet Messaging Program.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I said “drawing in a single thread”.

Fundamentally, graphics hardware is still single-threaded - with OpenGL, you’re adding drawing operations to a list and that list is executed as quickly as possible. Without OpenGL, all you have is flat memory. If you’re updating flat memory, the most efficient way to do that is with a single DMA transfer. (Yes, I know this is a gross over-simplification, but it is close enough to the truth…) So, you’re not actually going to improve drawing performance by threading, because the most efficient way to draw is by using a single thread.

By drawing I actually mean rasterisation; the process of converting the image data into a signal that gets output to a display.

Just because your drawing is done in a single thread, doesn’t mean that your logic has to be too.

The most efficient way to manipulate sprites is to not manipulate them - buy performance by spending on memory; pre-render all your sprites as much as possible. Learn the lessons of 15 years ago, when game devs had 33Mhz and 4MB of RAM if they were lucky! (That is, in 1992/3, in the UK, ‘cutting edge’ was a 386 DX @ 33Mhz).________________________________________
From: sdl-bounces@lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Albert Zeyer [albert.zeyer at rwth-aachen.de]
Sent: 06 August 2008 15:33
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

Yes, I understand that, but that does not directly answer my questions.

Also, despite that it is easier to have a single threaded application,
this is not really the way to go in future. You see it already, it is
normal to have at least 2 cores in a machine and it is becoming more and
more. Also the graphics card has a lot of cores. In a few years, you
will probably have 8, 16 or more cores in your computer. It is just not
possible anymore if you want your game to be efficient to just make
everything in one single thread.

And as all the software pixel operations do take far the most time in
most games, it is most important to do that multithreaded.

On Wed, 2008-08-06 at 15:13 +0100, cullen e.a. (eac203) wrote:

I wouldn’t say ‘bad code’, I would say ‘code written to be efficient when used in a certain way’.

Threading is (still) one of the most difficult problems in computer science, even though the theory is almost all over 20 years old.

Using threads adds overhead. This overhead can be massive. The design of SDL is intended to be ‘Simple’; to give the best performance it can most of the time.

Most of the time, an (experience) game developer will do drawing in a single thread, therefore, the decision was made to optimise SDL’s drawing routines toward that use case.

Eddy


From: sdl-bounces at lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Albert Zeyer [albert.zeyer at rwth-aachen.de]
Sent: 06 August 2008 15:09
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

Hi,

At what point did it expect that? At what possible other point could
there be an access to the surface? Except the event handling
(SDL_GetKeyState, SDL_GetMouseState, SDL_WaitEvent, SDL_PollEvent), I am
calling no other SDL functions in my main thread and I doubt that the
SDL event handling functions are related in any way to the surfaces (or
am I wrong here? but then there is a design flaw in SDL, 'cause
SDL_PollEvent() and friends should not do stuff with some surfaces).
Therefore, why does it matter if SDL_BlitSurface() and friends are
called from the main thread or all together from another thread?

And this situation:
Surface[4], Thread[2]

Thread[0]: Blit(Surface[1],Surface[0])
Thread[1]: Blit(Surface[3],Surface[2])

Why is that not possible? Is it because of bad code in Blit which
depends on static vars?

But even then, if I would assure somehow that there is only one Blit at
a time (for example by writing a Blit-Wrapper with a simple mutex), why
could it be a problem when I call it from different threads?

Or to do it in a more efficient way, I am thinking of implementing
something like this:

class Surface {
private:
SDL_Surface* s;
SDL_mutex* m;
list blits;
void forceUpdate() {
// do blits and other stuff
// force updates for all surfaces we depend on
}
public:
void blit(Surface* other) {
m.lock();
blits.add(other, params);
m.unlock();
}

    // for direct pixel access
    void lock() { m.lock(); forceUpdate(); }
    void unlock() { m.unlock(); }

}

– Albert

On Wed, 2008-08-06 at 14:58 +0200, Paulo Pinto wrote:

Hi,

I guess that the only safe way would be to do direct
pixel access, since the SDL graphics Api expects to be used
just from the main thread.


Paulo

Quoting Albert Zeyer <albert.zeyer at rwth-aachen.de>:

On Wed, 2008-08-06 at 11:37 +0100, Brian wrote:

What are SDL_LockSurface/SDL_UnlockSurface for if multithreaded access
to surfaces is not supported?

This is a common misconception. Locking a surface has nothing to do
with threading, it has to do with hardware surfaces. If a hardware
surface is currently residing on video memory, it can be inaccessible
to your program. LockSurface maps the surface data to system memory
(and possibly does other things, such as undoing any RLE compression
on the surface I think). UnlockSurface will copy the data (presumably
having been changed) back to hardware memory.

Oh, we did indeed understood that wrong.

Which ways are there to do multithreaded surface access (when we force
them to SDL_SWSURFACE)?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


This message was sent using IMP, the Internet Messaging Program.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I said “drawing in a single thread”.

Fundamentally, graphics hardware is still single-threaded - with
OpenGL, you’re adding drawing operations to a list and that list is
executed as quickly as possible. Without OpenGL, all you have is flat
memory. If you’re updating flat memory, the most efficient way to do
that is with a single DMA transfer. (Yes, I know this is a gross
over-simplification, but it is close enough to the truth…) So,
you’re not actually going to improve drawing performance by
threading, because the most efficient way to draw is by using a single
thread.

OK, that explains at least the case when OGL is used. Though for pure
software surfaces, I still don’t understand why it should not work.

Btw., that still does not explain why the graphic stuff can only be done
from the main thread and not from another thread. Why is it important to
do it really from the main thread?On Wed, 2008-08-06 at 15:57 +0100, cullen e.a. (eac203) wrote:

This note may not be appropriate, but I wanted to suggest this option:

SDL_ASYNCBLIT
Enables the use of asynchronous updates of the display surface. This will usually slow down blitting on single CPU machines, but may provide a speed increase on SMP systems.

Just in case it can help …

Cheers

Julien_____________________________________________________________________________
Envoyez avec Yahoo! Mail. Une boite mail plus intelligente http://mail.yahoo.fr

I said “drawing in a single thread”.

Fundamentally, graphics hardware is still single-threaded - with
OpenGL, you’re adding drawing operations to a list and that list is
executed as quickly as possible. Without OpenGL, all you have is flat
memory. If you’re updating flat memory, the most efficient way to do
that is with a single DMA transfer. (Yes, I know this is a gross
over-simplification, but it is close enough to the truth…) So,
you’re not actually going to improve drawing performance by
threading, because the most efficient way to draw is by using a single
thread.

OK, that explains at least the case when OGL is used. Though for pure
software surfaces, I still don’t understand why it should not work.

Indeed, it might work for software surfaces. You would need to study the
code to find out if it is thread safe. If it is not then you could take on
the project of making it thread safe. As you have implied, it could be
possible to do soft blits in separate threads.

Btw., that still does not explain why the graphic stuff can only be done
from the main thread and not from another thread. Why is it important to
do it really from the main thread?

Access to hardware acceleration is provided by OpenGL. An OGL context is
usually? Often? (it depends on the OS) bound to a single thread. And, that
thread is the one that created the context. The SDL 1.x libraries create
the context during initialization so the context is bound to the initial
thread. In 2.0 you will be able to create multiple OGL contexts and may be
able (I can not guarantee it) to do OGL calls in multiple threads. But, they
will likely have to be attached to separate windows.

Hardware acceleration is highly parallelized. But, that does not mean you
can process multiple calls using the same OGL context at once. It means that
processing OGL primitives can be parallelized to an astonishing degree. For
example, if you send a large triangle strip to OGL the hardware can
transform dozens (or hundreds) of vertices at the same time. And, once at
least points are transformed the hardware can rasterize dozens (or hundreds)
of triangles at the same time. Primitive rendering can be highly
parallelized.

OTOH, if two commands can be carried out at once, the hardware/OGL may try
to carry them out in parallel. It all depends on the hardware and the
driver. But, not all OGL commands can be run in parallel. Many graphics
effects require that a sequence of primitives must be rendered in the order
they were sent to OGL. Think about alphablending and depth queueing,
rendering primitives out of order can cause weird visual effects.

It is wrong to lump all SDL graphics operations together. Hardware graphics
has one set of problems, software graphics has another.

BTW, the easiest way to do two blits as fast as they can be done is to use
hardware surfaces and call OGL to do the blits. Even though you send the
blit commands sequentially, they may be done in parallel. They may be done
in parallel on a large number of processors. Once the first blit is started
the hardware will try to start the second blit. (You do have to flush the
OGL command queue to make sure they get started.)

Bob PendletonOn Wed, Aug 6, 2008 at 11:35 AM, Albert Zeyer <albert.zeyer at rwth-aachen.de>wrote:

On Wed, 2008-08-06 at 15:57 +0100, cullen e.a. (eac203) wrote:


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Hi,

Just to be clear, what I meant when I said that accessing hardware is sequential, is that accessing the interface to hardware is sequential (order is VITAL when using OGL) - which Bob pointed out, but didn’t say explicitly. Again, this goes back to what I was saying about most people doing drawing from a single thread.

Okay. In order to implement fully parallelized access to a video surface:

  1. Add support for a list of mutexes to the surface.
  2. For every drawing operation:
    a. Test to see that the area being updated is NOT locked by checking EVERY mutex in the list of mutexes.
    i. If lock found, sleep, busy-wait or whatever and try again from 2.a.
    ii. if no lock found, try to acquire the mutex on the mutex list.
    1. if cannot get mutex on list of mutexes, sleep, busy-wait or whatever and return to 2.a (yes, you must recheck all mutexes).
    2. Now that list-lock is aquired, add mutex for the region being updated.
    b. Do blit
    c. Try to acquire list-mutex.
    i. If unable to aquire list mutex, sleep, busy-wait or whatever and return to 2.c.
    ii. Now that you have list-mutex, remove the mutex from the list.
    d. Return from drawing function.

Now, granted, this is a scheme I knocked up in 10 minutes and there are a number of techniques available to improve average performance and reduce worst-case scenario, you’re still going to get a bottleneck around the list-mutex (you just can’t avoid it!).

Compare that to the sequential case where you’ve told the user that they MUST only draw from one thread (i.e., you’ve told them it’s not thread safe):

  1. Do blit.

Given:

a. The amount of memory and processing overhead involved in implementing this (not to mention the code and debugging!).

and

b. You only get the most benefit out of it when your updates to the drawing surface are small and therefore quite quick anyway.

This reinforces the point I made about “experienced developers” just doing drawing from a single thread.

Eddy________________________________________
From: sdl-bounces@lists.libsdl.org [sdl-bounces at lists.libsdl.org] On Behalf Of Bob Pendleton [bob at pendleton.com]
Sent: 07 August 2008 14:16
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] multithreading & video

On Wed, Aug 6, 2008 at 11:35 AM, Albert Zeyer <albert.zeyer at rwth-aachen.de<mailto:albert.zeyer at rwth-aachen.de>> wrote:

On Wed, 2008-08-06 at 15:57 +0100, cullen e.a. (eac203) wrote:

I said “drawing in a single thread”.

Fundamentally, graphics hardware is still single-threaded - with
OpenGL, you’re adding drawing operations to a list and that list is
executed as quickly as possible. Without OpenGL, all you have is flat
memory. If you’re updating flat memory, the most efficient way to do
that is with a single DMA transfer. (Yes, I know this is a gross
over-simplification, but it is close enough to the truth…) So,
you’re not actually going to improve drawing performance by
threading, because the most efficient way to draw is by using a single
thread.

OK, that explains at least the case when OGL is used. Though for pure
software surfaces, I still don’t understand why it should not work.

Indeed, it might work for software surfaces. You would need to study the code to find out if it is thread safe. If it is not then you could take on the project of making it thread safe. As you have implied, it could be possible to do soft blits in separate threads.

Btw., that still does not explain why the graphic stuff can only be done
from the main thread and not from another thread. Why is it important to
do it really from the main thread?

Access to hardware acceleration is provided by OpenGL. An OGL context is usually? Often? (it depends on the OS) bound to a single thread. And, that thread is the one that created the context. The SDL 1.x libraries create the context during initialization so the context is bound to the initial thread. In 2.0 you will be able to create multiple OGL contexts and may be able (I can not guarantee it) to do OGL calls in multiple threads. But, they will likely have to be attached to separate windows.

Hardware acceleration is highly parallelized. But, that does not mean you can process multiple calls using the same OGL context at once. It means that processing OGL primitives can be parallelized to an astonishing degree. For example, if you send a large triangle strip to OGL the hardware can transform dozens (or hundreds) of vertices at the same time. And, once at least points are transformed the hardware can rasterize dozens (or hundreds) of triangles at the same time. Primitive rendering can be highly parallelized.

OTOH, if two commands can be carried out at once, the hardware/OGL may try to carry them out in parallel. It all depends on the hardware and the driver. But, not all OGL commands can be run in parallel. Many graphics effects require that a sequence of primitives must be rendered in the order they were sent to OGL. Think about alphablending and depth queueing, rendering primitives out of order can cause weird visual effects.

It is wrong to lump all SDL graphics operations together. Hardware graphics has one set of problems, software graphics has another.

BTW, the easiest way to do two blits as fast as they can be done is to use hardware surfaces and call OGL to do the blits. Even though you send the blit commands sequentially, they may be done in parallel. They may be done in parallel on a large number of processors. Once the first blit is started the hardware will try to start the second blit. (You do have to flush the OGL command queue to make sure they get started.)

Bob Pendleton


SDL mailing list
SDL at lists.libsdl.org<mailto:SDL at lists.libsdl.org>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+