Amiga.org

Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: marcus256 on May 12, 2003, 10:17:52 PM

Title: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 12, 2003, 10:17:52 PM
Hi everybody!

I'm new here, but I thought it's the best place to drop this info and get some feedback...

Anyway, I'm the developer of a portable OpenGL framework (or toolkit, if you like), called GLFW. It started out under Windows, and quickly got ported to Unix/X11. Now, when the API & code has matured a bit I thought it was apropriate to do an AmigaOS port too (after all, I'm an old AmigaOS fan!).

My problem is that I'm a bit rusty, so I would very much like to get some help with some things. Also, I'm conducting all development under WinUAE (since my A3000 does not fit in my tiny computer cabinet, unfortunately), so 68k only and no HW OpenGL support - speed is tremendous though (like 200-300 MHz '040).

Primarily I'm looking for some testers/users that are intererested in using and possibly aiding in the development of GLFW.

Short intro...

GLFW = OpenGL FrameWork

Window management (normal/fullscreen), keyboard/mouse/joystick input, timer (high precision - microsecond class), multi threading support, texture file loading support (TGA).

Of course, everything is 100% portable. Some of the supported OS:es are: Windows 9x/NT/2k/XP, Linux, IRIX, Solaris, QNX, Mac OS X and AmigaOS.

URL = http://glfw.sourceforge.net/

I'm especially interested in AmigaOS 4.0 / MorphOS compability, and support for different GL/Mesa implementations (I currently use StormMesa).
Title: Re: GLFW port for AmigaOS
Post by: JoannaK on May 13, 2003, 02:03:52 AM
I'm not much of  a coder, but I'm sure there will be increased need for this kind of libraries as soon as these OS:s have their 3D support nicely up and running.

Title: Re: GLFW port for AmigaOS
Post by: Billsey on May 13, 2003, 02:16:41 AM
Welcome to the asylum, marcus! :-D

Have you thought about supporting AmigaOS4 and/or MorphOS? They both involve new machines.
Title: Re: GLFW port for AmigaOS
Post by: Karlos on May 13, 2003, 03:13:59 AM
Hi there,

I have something that might interest you. I have written a C++ based portability layer (still in development) that encapsulates many things useful for your project

1) Applet based startup (your application is a class and you don't need to define main() anymore). It gets instansiated once all the critical OS initialisation is done.
You can inherit components of the portability system that way (or use a compositional design pattern if you prefer).

2) High performance memory class

3) Abstract input handling - you inherit InputFocus and override only those virtual functions you require as input handlers.

4) Kernel service classes, eg: Thread class, Lockable class, Timers, MilliClock etc.

5) Graphics abstraction layer - Colour, Surface, Display, Rasterizer (using Warp3D), and other classes such as input focus to get input back from a display etc. as well as standard subclasses, eg Window, Screen etc..

6) Audio classes (fell a bit behind there).

For example, if you wanted to write an application that uses a double buffered screen (with input handling)

class MyApplication : private AppBase, FullscreenDB {

};

Does 90% of the work for you :-)

The project is aimed at supporting a lot of platforms though the Amiga68K version is the one most in deveopment just now.

If youre interested, drop me an email...

-edit-

Oh, and the whole thing uses pretty lightweight interfaces because I designed it for multimedia / gaming rather than building in tons of excess bloat in the event some of it might be useful :-)

Title: Re: GLFW port for AmigaOS
Post by: marcus256 on May 13, 2003, 08:11:38 AM
> Have you thought about supporting AmigaOS4
> and/or MorphOS? They both involve new machines.

Yes, of course. I know these are new machines, but I believe that they are virtually 100% sourcecode compatible (of course I'm using pure OS friendly coding, no HW access, special assumptions etc) - and GLFW is distributed as source code. I read up on MorphOS, so I have actually included some MorphOS specifics regarding task creation (though I have not tested it myself).

I think both platforms are very interesting targets - especially when they get HW 3D support (that is a must for a system to be successful today, IMO). OS4 is rumored to get Mesa 5.0 (OpenGL 1.4 compliant). Does anyone know about HW support? Will it be through some new Warp3D interface?
Title: Re: GLFW port for AmigaOS
Post by: marcus256 on May 13, 2003, 08:38:16 AM
> I'm sure there will be increased need for this kind
> of libraries as soon as these OS:s have their 3D
> support nicely up and running.

Yes. I'd like to think of GLFW as a foundation for writing portable interactive 3D applications (most notably: games!). There is already one major application that uses GLFW as its "core", check out http://www.orkysquad.org/main - a very cool game.

The wording goes "Orky can be ported to any platform with GLFW support".

Personally, I think tools like this is absolutely necessary for a small market such as AmigaOS, since very few coders/companies are willing to spend time on supporting a "minority platform". By using portable technologies (OpenGL, GLFW, libMikMod etc), the hazzle of porting to AmigaOS is nearly negligable.

Title: Re: GLFW port for AmigaOS
Post by: marcus256 on May 13, 2003, 08:57:47 AM
Hi Karlos,

> I have written a C++ based portability layer (still in
> development) that encapsulates many things
> useful for your project

I believe we are doing pretty much the same thing (at least we have similar goals). GLFW is: portable, minimalist, very compact (a 68k Amiga executable is usually ~25 KB, the Windows DLL is 30 KB), extremely easy to use & powerful.

The major difference, as I see it, is that I use pure C, not C++. I don't like C++ for these kinds of things, since:

1) It's not as portable as C (no, not yet at least)
2) It's quite difficult to turn a C++ interface into a shared library
3) You can't use C++ interfaces from alternate languages (such as Borland Delphi, Visual Basic, Fortran, Python etc)

Maybe we can exchange experiences? You are of course free to "rip" the GLFW code if there is something that you find useful (the GLFW license is extremely liberal).

If you don't feel like downloading the whole pack, you can always browse the Sourceforge CVS tree: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/glfw/


> class MyApplication : private AppBase, FullscreenDB {
>
> };
>
> Does 90% of the work for you

In GLFW you usually do:

------------------------------------------------
glfwInit();
glfwOpenWindow( 640, 480, 8,8,8,0, 24,0, GLFW_FULLSCREEN );
do
{
    glfwSwapBuffers();
    running = !glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED );
}
while( running );
glfwTerminate();
------------------------------------------------

That's a complete GLFW application with input, double buffering and a "main loop" (you can do it differently too, e.g. with callback functions for input etc). I agree, not very OO, but I believe that it's not too ugly to write a C++ class on top of GLFW, if that suits your project better than the programmatic C interface.

> 6) Audio classes (fell a bit behind there).

Recommendation: stay away from audio! People tend to underestimate the complexity of audio. You have two choices:

1) Make a fullfeatured, complete audio interface (sound samples, MP3, mixing, 3D aureal emulation, music playback, CD music handling etc)

2) Ditch it and use a 3rd party toolkit (libMikMod, FMOD, OpenAL etc)

If you make a simplistic interface (a-la SDL), professional people will not want to use it anyway, rendering your effort useless and the interface bloated.
Title: Re: GLFW port for AmigaOS
Post by: Karlos on May 13, 2003, 12:59:44 PM
Ah well, I see you have your stuff covered nicely. It was just a thought since we were obviously going for the same goals (nearly)...

As for portability, my layer does work nicely on other platforms (but as I said theyre slow to catch up because I don't work on them much) principally because it doesn't use any 'wobbly' C++ features internally, namely

namespaces
exceptions (you should see the problems that gave in a multithreaded environment)
RTTI
templates

Actually there are some *very* simple templates (things like protected inegers), nothing that didn't compile everywhere I tried.

However, it is a link library so I don't get quite the compactness you do. I am thinking to make a shared library implementation of the internals that will shrink the link library to a stub but that will take some work (and redesign of the class internals).

Creating an application is extremely simple and fairly robust - if some essential stuff cant be set up, your actual application is never even created.

Anybody whos ran my tests for the 3D card has already used it...twice :-)
Title: Re: GLFW port for AmigaOS
Post by: marcus256 on May 13, 2003, 02:19:23 PM
> However, it is a link library so I don't get quite the compactness you do.

Actually, my lib is a static link library too. Under Windows I made it a DLL too (so you can select what suits your project the best). The 25 KB Amiga executable includes the GLFW static link library.

Ah, there's a question: How do you handle things like double floats as input/output arguments in an AmigaOS shared library??? I remember the ieeedoubbas libraries using dual 32-bit integer registers for passing 64-bit floats, which I don't find too appealing. Can't you mandate using the FPU registers? (the lib will probably not be used on non FPU-equipped CPUs anyway). How are the GL/Mesa shared libraries implemented under AmigaOS (they too use doubles)?
Title: Re: GLFW port for AmigaOS
Post by: Karlos on May 13, 2003, 03:14:32 PM
Yup, this is a problem, but only for 68K libraries as far as I know.

The problem is that standard library interfaces work (as I'm sure you know) by passing arguments in registers, either d0-d7 for ints etc and a0-a3 for pointers.

Passing FPU stuff in fp0-fp7 isn't supported IIRC.

The simplest approach is to pass floats / doubles by reference.

-edit-

I think you can also pass 32-bit floats in registers d0-d7 too. Youd need something like

void myfunc(REGD0 float fval);

where REGD0 is some convenient macro abstraction for specifying a register argument using d0...

-endi edit-

This only affects your actual library interface to the outside world. Normal C conventions apply to internals so there's no reason why functions internal to your library can use floats/doubles as args normally.

-another edit-

Incidentally, are you using MesaGL? You may want to look at MiniGL for performance under current apps. It's a bit of a whopper static link library though...
Title: Re: GLFW port for AmigaOS
Post by: marcus256 on May 14, 2003, 01:59:50 PM
> Yup, this is a problem, but only for 68K libraries as far as I know.

So how are things supposed to work under OS4, for instance?

What shared library standards exist except the old AmigaOS style (D0-D7,A0-A3 - I though A5?).

> I think you can also pass 32-bit floats in registers d0-d7 too

Obviously. It's just  a calling method - the caller & procedure just have to agree on the conventions. As I said, the old double precision IEEE libraries used two 32-bit integer registers per 64-bit float.

I'm also considering using referenced arguments (e.g. A0 pointing to a double). That does not go well with the GLFW API specification, but I suppose I can make wrapper macros or whatever.

I just thought that some new standard might have emerged, since the AmigaOS style does not accomodated for:

1) Floating point values
2) 64-bit floats/ints
3) Many arguments (exceedeing the number of available processor registers)

> Incidentally, are you using MesaGL? You may want to look at MiniGL for performance under current apps.

Does MiniGL work with WinUAE (i.e. without HW 3D acceleration)?

Worth supporting though - since some people seem to prefer it. Just wondering if I can test it myself. I have #ifdef:ed everything that is specific to the GL/Mesa implementation (currently only StormMesa), so that support for different implementations is just a matter of a simple #define or compiler-switch.
Title: Re: GLFW port for AmigaOS
Post by: alx on May 14, 2003, 02:38:20 PM
Quote
So how are things supposed to work under OS4, for instance?


Here's an extract from the OS4 features list about the new library model:

Quote
New library model

ExecSG sports a new model for shared libraries. The old model will remain to support 68k libraries. PPC native libraries will be organized slightly different: The library base is still there (and looking the same as before) but the jump table only contains 68k functionality (for compatibility). PPC native functionality is provided by Interfaces:

 An Interface can be thought of as a separate jumptable, containing pointers to the actual library functions.

 An Interface can have its own data area in addition to that of the library base.

 An Interface can be shared among tasks (like a library) but may also be created as a private
instance, allowing instance data to be stored in it (similar to the old SAS/C method of duplicatingthe library base). A task can also create multiple instances of the same interface with each interface having its own data (essentially like real objects).

 Reference counting is used to work around stale pointer problems.

 A library can export any number of interfaces. For example, ExecSG exports the interfaces
"main", "utility" and "mmu", which represent the main API, the integrated utility.library and the
special MMU interface.

 A library can export the same interface in multiple versions thus allowing for full backward
compatibility.

 Interfaces can be modified with SetMethod (like SetFunction), allowing "morphing" interfaces
that can efficiently adapt to internal state changes. For example, expansion.library uses this in its PCI interface to adapt a PCI interface to the actual hardware.

 Interfaces can also be created in such a way that they are protected against patching. This is
essential for services like SSL (or any security-sensitive service).

 Interfaces can be used to write Object-oriented libraries.

 Interfaces are conceptually similar to component programming models.


That's not very detailed, and seeing as I've never done any programming on AmigaOS, I've no idea if that'll be any use to you.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 18, 2003, 08:43:26 PM
I suppose that's one way to go (at least for AOS4 it's probably the prefered way). Another way is to ignore  the way the 68k assembly interface looks: write a library interface with "nonsense" arguments (e.g. D0/D1 = 64-bit float, or A0 points at function return value, etc), and write a wrapper C language interface library (libglfwsh.a or glfwsh.lib - sh = shared) that hides the library interface from the programmer.

More questions: For the multi threading part of GLFW I had to use the tc_UserData field of the Task structure for each GLFW thread (including the main thread, which is the one calling glfwInit()).

I know this is not good practice, but I see no other solution (each thread requires a lot of state that I have to store somewhere, and I do it in a struct pointed to by tc_UserData). If the GLFW program only uses GLFW threads, and not any custom AmigaOS tasks/processes etc, this will be no problem. Can anyone think of a situation where it COULD  be a problem???
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: 4pLaY on May 18, 2003, 09:09:19 PM
 Considered a port to AROS? :).
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 18, 2003, 09:35:37 PM
Hi marcus,

The only problem would be if you mixed up a normal thread with one one of your GLFW ones and proceeded to use it as if it were.

My Threadable service class (base for all threaded objects, wraps a task) uses the same strategy as you describe.

On creation of the task I set tc_UserData to point to the actual Threadable class that encapsulates it.

To avoid problems in cases where other threads that use the same field for their own purposes, the Threadable class has an identifer member value inside used to identify it as a 'Threadable' class object. This is basically an integer which must match a defined value 'IS_THREADABLE'

So, to get the current Threadable object for which the code is executing uses a static function thus

Threadable* Threadable::getCurrent()
{
  Task* who = FindTask(NULL);
  if (who)
  {
    // this is the dodgy bit, we cast to Threadable and see if the id matches
    Threadable* thread = (Threadable*)(who->tc_UserData);
    if (thread && thread->identity == IS_THREADABLE)
      return thread;
  }
  return 0; // not a Threadable thread
}


I certianly haven't ran into any problems with this approach. You could just put a check like the one above use identifier field in your structure. If you ever do somehow handle a thread which is not one of your GLFW ones, it can be differentiated easily by seeing if the data pointed to has this identifier.

Works for me :-)
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 18, 2003, 10:21:54 PM
Incidentally, I should point out that I rarely need to determine the current thread using the method I mentioned since 99% of the time the task is running within the context of the Threadable object itself...

For code calls external to the Threadable object (and not given a reference to it) to the method described is essential and works a treat...
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 19, 2003, 08:49:06 AM
That's a good solution (at least as good as it gets, I suppose). Currently the interface is not very dependant on the custom GLFW thread structure, but I am planning to add support for multiple windows in a way that would require every single windowing function (event handling, window management etc) to access the thread private area.

Why? Thread aware window management!

The idea is very similar to OpenGL per thread rendering contexts (one context per thread - transparent from a coders point of view). For instance, I will have a function called glfwBindWindow(), which binds a window to the currently calling thread. All window operations will apply to that window. Since different threads can work on different windows, I need to store this "window binding" information in an easily accessible thread private area - my GLFW thread structure, pointed to by tc_UserData, is the obvious choice.

I can still use the "fool-proof" check that you described, but that means that using non-GLFW threads will limit the use of GLFW functions (e.g. you can't open a window from a non-GLFW thread).

I wish AmigaOS had something similar to POSIX pthread thread-specific data keys or Win32 thread local storage (TLS), which are basically indexed arrays of tc_UserData that you can dynamically allocate, per process. I suppose this does not work well without a  proper process class though...
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 19, 2003, 08:57:41 AM
> Considered a port to AROS? :)

Is it worth it?

How is OpenGL support under AROS?

How different is AROS from AmigaOS?  I need AmigaDOS processes, intuition,  graphics and input.device. The rest is quite easy to replace (timer.device/ReadEClock, gameport.device, StormMESA etc).

Can I run AROS on my PC (natively, or under Windows, Linux or WinUAE)?
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: T_Bone on May 19, 2003, 09:50:46 AM
Quote

marcus256 wrote:
> Considered a port to AROS? :)

Is it worth it?

How is OpenGL support under AROS?

How different is AROS from AmigaOS?  I need AmigaDOS processes, intuition,  graphics and input.device. The rest is quite easy to replace (timer.device/ReadEClock, gameport.device, StormMESA etc).

Can I run AROS on my PC (natively, or under Windows, Linux or WinUAE)?


I don't know about OpenGL support in AROS, but it will run natively on a PC, and it will run hosted on Linux. other than that, it's pretty much source compatible with AmigaOS.

Definately worth checking out!


screenshot AROS (http://www.poweramiga.com/webarchive/arosshot.png)
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 19, 2003, 01:03:14 PM
Quote

marcus256 wrote:
That's a good solution (at least as good as it gets, I suppose).


Yeah. It's relatively simple and no way you can actually get access to a thread which isnt one of your own - the function just returns null if the thread that called it isn't one of your custom kind.

Quote

Why? Thread aware window management!

The idea is very similar to OpenGL per thread rendering contexts (one context per thread - transparent from a coders point of view). For instance, I will have a function called glfwBindWindow(), which binds a window to the currently calling thread. All window operations will apply to that window. Since different threads can work on different windows, I need to store this "window binding" information in an easily accessible thread private area - my GLFW thread structure, pointed to by tc_UserData, is the obvious choice.


That should work. According to the RKM, tc_UserData is entirely free for the programmer to use for pointing to task specific data that is meaningful to them. IIRC, exec pays it no attention whatsoever.

My only point is that multithreaded rendering doesn't do much performance wise since at the end of the day you only (usually) have one hardware rendering device that needs to be exclusively locked. I guess that's not your point anyway - most uses for multithreaded code are to simplify design rather than a speed optimisation.

Hwever, I did find one use. I made a Threadable Rasterizer class (still in development) that has a double buffered vertex array / command queue. The rendering calls fill one buffer whilst the previous one is being rendered by the internal thread.
In this instance there was an overall perfomance increase, principally because the rendering code often has to wait for the hardware to complete an operation before it begins a new one. By running it as a seperate task at a lower priority than the parent, when it's waiting the parent gets the cpu to continue working on other stuff realtively unimpeeded.

Quote

I can still use the "fool-proof" check that you described, but that means that using non-GLFW threads will limit the use of GLFW functions (e.g. you can't open a window from a non-GLFW thread).


I should point out that I do have a singleton MainThread class (derived from Threadable) that wraps the main thread of execution. That way the main process is seen as Threadable to the rest of the system.
You could probably manage something similar.

Quote

I wish AmigaOS had something similar to POSIX pthread thread-specific data keys or Win32 thread local storage (TLS), which are basically indexed arrays of tc_UserData that you can dynamically allocate, per process. I suppose this does not work well without a  proper process class though...


That's the beauty of Threadable. You can extend it however you wish :-)



But why not just create a structure thus...

typedef struct {
  long identity;
  size_t numDataHandles;
  void* dataHandles[1];
} GLFWThreadLocalStore;


...and allocate that dynamically with a function eg :


GLFWThreadLocalStore* CreateLocalStore(size_t numHandles)
{
  GLFWThreadLocalStore *tls = (GLFWThreadLocalStore*)malloc(sizeof(GLFWThreadLocalStore)+(numHandles-1)*sizeof(void*));
  if (tls)
  {
    size_t n;
    tls->identity = IS_GLFWTHREAD;
    tls->numDataHandles = numHandles;
    for (n=0; ntls->dataHandles[n] = 0;
    return tls;
  }
  return 0;
}


When you need to resize the TLS, you can basically use a standard library function like realloc() to preserve whats in there..

If youre interested I can send you the source code to my kernel classes that will allow you to see how I overcome some of the problems you describe.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 19, 2003, 01:04:31 PM
....er and I forgot to say make tc_UserData point to your GLFWThreadLocalStore object :-D
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 19, 2003, 05:16:04 PM
oops..wrong post
Title: Re: GLFW port for AmigaOS
Post by: PiR on May 19, 2003, 06:15:55 PM
Greetings Gentelmen!

Sorry for the delay, I should have looked at this thread earlier, but (stupid me) I thought it may be another boring mumbo-jumbo. ;-)

AFAIK using standard 68k libraries has ONLY TWO requirements uppon CPU registers:
A7 - stack
A6 - library base
The rest of it is free to arrange by the guy who implements the library.
Additionally remember that:
A0,A1,D0,D1,FP0, FP1are so-called trash register, so the library user is obliged not to rely on any data that were previously in them
A2-A5,D2-D7,FP2-FP7 are supposed to be unchanged by any function, so if the library programer decides to use any of it, he MUST remember to preserve and restore them.

So

It's up to you where you want your arguments, so why not to have them in FPU registers? However if you decide to use FPU I think it would be extemally good practice to check for the its existance in Open() library function. If no FPU discovered library should refuse to open.

Of course we're talking about old Amiga standards here.

Good luck
PiR
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 20, 2003, 12:24:06 PM
What I meant with TLS, is that it would be nice if AmigaOS had support for TLS natively, so that I can use it to realize some of the GLFW threading things with it.

tc_UserData works very much as TLS, but the problem is that there is no OS-friendly way of allocating/deallocating it (as you said - exec simply does not care), so if GLFW is to use it, the application (that uses GLFW) can not use it. If AmigaOS provided proper TLS support, GLFW could allocate a TLS "key" or "index" private to GLFW, and the application is free to allocate other keys, meaning that there are no potential conflict situations.

By the way, I solved the condition variable (signalling primitive) support by adding a field to the GLFW thread structure called "waiting_for" (or something similar), so that when a thread is to signal or broadcast a condition to any waiting thread(s), it loops through all the known GLFW threads and checks the waiting_for field, to see if it is waiting for this particular condition. If so, a signal (that is private to the waiting thread, and whose ID is stored in its thread structure) is generated. Of course, critical sections (Forbid/Permit) is used wherever necessary.

I think this is the most viable solution for broadcasting signals to multiple threads in the way that is required for condition variables to work (it should be quite cheap too, since mostly you don't have more than a couple of threads, perhaps 10 at most or so). Have you done anything similar?

> I made a Threadable Rasterizer class (still in
> development) that has a double buffered vertex
> array / command queue. The rendering calls fill
> one buffer whilst the previous one is being
> rendered by the internal thread.

In the GLFW distribution I have an example program that works this way. It's a particle system, where the particle physics is carried out in one thread, and the rendering/billboarding is done in another thread.

First I did a straight forward solution without double buffering (meaning potential stalls). It roughly gave a 100% of the speed of a single threaded implementation on a single processor system, and 105-150% on dual CPU systems.

Then I added double buffering, actually resulting in a performance drop (about 95% on the single processor system, and slightly degraded performance on the SMP systems compared to single buffering).

I reccon the reason is that:

A) OpenGL hardware already runs asynchronously on most decent implementations (at least under Windows and Linux), so that there is no gain in using separate threads on single processor systems

B) Double buffering means more cache trashing, effectively degrading CPU performance

I still think multi threading like this is a good thing if it does not cost performance for single processor systems. Future systems are very likely to have multiple CPU cores (either SMP or SMT), meaning that multi threaded programs will gain performace "for free" on those systems. And, as you said, in many situations it can help the design to use multiple threads.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 20, 2003, 12:25:32 PM
oops - dual post...
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 20, 2003, 11:18:39 PM
Hi marcus,

-edit-

Is it a problem that the application running on GLFW cant use the tc_UserData if you use it? I thought the point was to avoid system dependencies. Just use your own GLFW threads within a multthreaded GLFW program, surely. As I see it, your GLFW threads are an interface. If you add your own TLS to it then the users of your framework will just use that instead.
-end edit-

Signalling in my  system is realitvely straightforward. Since I have threadable objects, as opposed to just seperate threads running through some arbitrary code, I just perform a method for that object. If that method changes internal data, the thread will be aware of that automatically (having acces to the protected level internals). Methods which require synchronised access can simpy use a Lockable object that is bound to the internal thread (you can't lock it until the internal thread is done with it). Lockable is a service class that encapsulates the Semaphore mechanism.

The actual Amiga task, running within the context of the object, can always see the (protected) state information. Due to this, the only real signalling I need is to be able to go to sleep and wait for an event, or a time out. The theadable service provides a delay timer feature too, using the DelayTimer class (itse;f an encapsulation of the timer.device).

There is a sleep() method for theadable objects that actually uses the amiga Wait()/Signal() system.
So the internal thread can literally go to sleep. When you then kick the object by invoking the wake() method, the appropriate exec level signal is sent to the internal task which is then woken up and carry on.

So really I don't use a lot of different signalling, just sleeping and waking. All other state info is actually part of the object definition. There is also a shutdown signal defined which basically tells the internal thread to remove itself. The internal thread code can simply call the method that checks for a shutdown call and then do whatever is required to finish and exit.
It does this(cleanly) by a return from the run() method.
The thread which invoked the stop() method (which may be part of the destruction for example) is then forced to wait on the internal thread to finish.

The only other thing is that a call to shutdown() will wake up the thread if it is waiting for something already. This allows threads to respond quickly to getting told to finish up.

It's a robust system and the interface ensures that youd have to especially set out to break it in order to screw it up.

Quote

Of course, critical sections (Forbid/Permit) is used wherever necessary


Try to avoid this. If you can, use semaphore locking for shared resources, its much friendlier - especially if your going all multithreaded...
The only place I use this is inside the start() method that creates the task. With task switching momentarily disabled, I write the tc_UserData to point to the object and thats it.
I don't use it anywhere else and would rather avoid it all together. If you ever do a WarpOS version you'll see there is no ForbidPPC()/PermitPPC()...

-threaded graphics-

Agreed. In most cases a multithreaded approach to rendering on a single processor system is pointless.

However, the double buffered rasterizer I wrote works reasonably well because on the current hardware, rendering takes time and does force the calling code to wait (we are talking direct Warp3D level stuff here, not OpenGL). Only the simple pre-v4 Warp3D calls are asynchronous. The v4 vertex array calls (which I use for efficiency/flexibility reasons) are not (well there may be some parallelism at the hw level). The cache thrashing issue isn't much of a problem in my code since the buffers aren't very large anyway.

So, in my case whilst drawing isnt physically any faster, the setup stage can continue so time is not wasted. The threaded double buffering adds the asynchonicity you would expect from a 'decent' OpenGL implementation.

I don't have a high level 3D system apart from a simple transforamtion / shading engine. I have no interest in trying to compete with OpenGL :-)

Anyway, if you use multithreading under Windows, you'll love it on AmigaOS. Task switch times are miniscule :-)
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: marcus256 on May 21, 2003, 12:46:54 PM
Daarrrgh!!!!

I wrote a leeengthy reply to this mail - but it didn't get posted (login timeout?). Anyway, this will be more brief...

> -edit-
> [snip]
> -end edit-

I agree... ;)

I didn't quite understand your signalling policy. GLFW mimcs the POSIX pthread API (which rocks, IMHO), by supporting mutexes (AmigaOS signal semaphores) and condition variables (sleep/wake mechanism).

What's special about condition variables is that any numder of threads can be waiting for the same condition, and any numbder of threads can be signalling that condition (not knowing about which, if any, threads are waiting). Also, the condition variable does not maintain any state (it's like a strobe), so the actual condition has to be managed through mutex-protected shared variables. This means that the condition can be of arbitrary complexity (boolean, counter, combination of conditions etc).

The problem with AmigaOS is that each task has it's private set of allocated signals, and the signalling thread must know both which task to signal, and which signal ID that particular task is waiting for. That is why I need a loop to check each and every GLFW thread if it is waiting, and which signal ID it is waiting for (and of course, if the signal ID corresponds to the condition variable that is currently being signalled).

I actually don't use Forbid/Permit (I was confused with the joystick code I did recently, where joystick allocation needs Forbid/Permit). I use a global signal semaphore that protects all thread state (e.g. when a thread is added to the GLFW thread list).

Regarding task switch times: AmigaOS may be good, but Windows NT/2k/XP is really good! Windows 98 sucks big time though. I have a benchmark program in the GLFW example program collection which does forced context switching (two threads that signal/wait/signal/wait... in a loop). Here are some results:

AmigaOS (WinUAE, 68020 ~200 MHz): 50,000 switches/s
Windows 2000 (Athlon 700 MHz): 500,000 switches/s
Windows 98 (Athlon 700 MHz): 23,000 switches/s
Linux (Athlon 700 MHz): 160,000 switches/s
SunOS (6 x USPARC2 400 MHz): 120,000 switches/s
OSF/1 (1 x Alpha 21264 500 MHz): 130,000 switches/s
OSF/1 (2 x Alpha 21264 500 MHz): 40,000 switches/s

The signalling involves both mutex locking and condition signalling. The GLFW implementation of course has some kind of overhead to it too. I think that under Mac OS X (pthread) the figure is somewhere in the range 10-20 kswicthes/s. IRIX 5.3 also sucked if I remember correctly.

Do you have any similar benchmarking figures? (it would be interesting to compare)

Oh, and I have unconditional sleep too. It uses Amiga's Delay() - is that any good? (gives me a minimum of 40 ms sleep time in average - funny, I thought it would be 1000/50 = 20 ms)

I still haven't solved timed conditional waits. I suppose I would have to use timer.device to set up a timeout signal and wait for that too.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: PiR on May 21, 2003, 01:25:49 PM
@marcus

I hesitated if I should write about it, however I decided I will.

I think you can improve you implementation of condition variables. As I understood till now you have your condition variables and each task has a waitfor field with address of the condition variable it waits for.
So every time any condition variable is signalled/broadcasted you have to check through all the tasks. The more tasks you have the more you have to look through.

If you like the POSIX way I think you should make the following modification:
'waitfor' should actually be a listnode, while inside condition variable should be a listheader. Linking/Unlinking to the condition variables (done due to waiting for and waking up) should be mutexed of course.

This is you code, so if I should keep my nose out of it just ignore it. I'm playing a lot of POSIX threads last few months.

Good luck
PiR
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Karlos on May 21, 2003, 02:39:36 PM
Hi marcus,

-edit-

Pity we are never online at the same time!

PiR is right - a linked list is more efficient for this, I would say...
-end edit-

About the signalling policy. What I mean is, most of the time, the thread is running inside the context of the threadable object. Like the Thread interface in java, for example.
So, say I write code for a threadable object that waits for a member of that object to change value. The code would be something like

void MyThreadableObject::waitForValueChange()
{
  int oldvalue = value;
  while (oldvalue == value)
    sleep(); // indefinate until wake() or stop() called
}

Note sleep() is a simpliication. The real method is idle(uint32 millisecs, bool ignoreWake, bool abortIdle, SysSignal trigger);

..but that confuses the example slighty. Using a delay time of 0 ms is forever...
This pethod is called by the internal thread. I may write a public method like this

void MyThreadableObject::setNewValue(int v)
{
  value = v;
  if (isSleeping())
    wake();
}

And thats it. As soon as I call setNewValue() and the value I pass is different from the internal one, the internal task, if already asleep, will woken up.

As for delays. Don't use Delay() - it's bobbins for accuracy.

Use the timer.device and wait on that. I have a DelayTimer which is derived from MilliClock. It gives millisecond delay accuracy. I could easily mmake this finer but the MilliClock implementation has to work on lots of platforms, not all of which have the microsec resolution available to the amiga.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: kamelito on May 18, 2016, 12:55:24 PM
13 years later is GLFW ported to the Amiga in the end?

Kamelito
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: Rob on May 18, 2016, 02:16:07 PM
Quote from: kamelito;808719
13 years later is GLFW ported to the Amiga in the end?

Kamelito


I'm assuming it got abandoned over a decade ago.  GLFW still exists and the last builds were in October 2015.  

http://www.glfw.org/

Daniel Müßener now has the OpenGL ES2 wrapper working with Warp3D Nova.

https://www.facebook.com/photo.php?fbid=1472166232809819&l=573a43d98a

Maybe if there's enough good open source software that uses the library we may see a port.
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: kamelito on May 18, 2016, 02:38:27 PM
Quote from: Rob;808722
I'm assuming it got abandoned over a decade ago.  GLFW still exists and the last builds were in October 2015.  

http://www.glfw.org/

Daniel Müßener now has the OpenGL ES2 wrapper working with Warp3D Nova.

https://www.facebook.com/photo.php?fbid=1472166232809819&l=573a43d98a

Maybe if there's enough good open source software that uses the library we may see a port.


This guy is a machine !

Kamelito
Title: Re: GLFW (OpenGL toolkit) port for AmigaOS
Post by: SnkBitten on May 18, 2016, 02:47:16 PM
Though this is in the changelogs..

Version 2.7
Released on September 3, 2010

Removed deprecated AmigaOS and DOS ports