objarni's picture

Some OpenAL reflections

Hi there!

I tried out the new AL API of OpenTK tonight, it stopped when downloading alut.dll was not enough to kickstart a simple Alut.Init()/OpenTK0.9 windows forms application.

I'm new to OpenAL, so I'm approaching the AL API with a "C#/OpenTK"-mindset.

Sorry if I sound rant-ish! I just want to express my opinion. Here we go:

1. AL.GenBuffers(out uint bufferid): maybe GenBuffer without 's' is better name..? Same with GenSources(out uint sourceid) and DeleteSources(..)
2. IntelliSense-documentation refers to "ALuint"'s and not uint, which are used in reality. In general,
the IntelliSense seems more "c-ish" than "OpenTK-ish" to me :)
3. Is it really necessary to error-check everything all the time..? Could we not have some kind of exception system? I think error-polling is so tedious, it gets really tempting to either
a) skip it altogether (not good)
b) write a thin AL-wrapper around the OpenTK-AL class (not nice either)
4. Alut.Init() returns a strange enum type called "AL.Bool" -- why not use .NET's bool type instead?
5. Why does AL.DeleteSources() take a ref to an uint instead of just an uint? If I want to set the id to 0, I'll rather do it myself.
6. I would like GenSource() to take no out parameter, just return a uint.
7. I would like GenSources(int) to take the number of source id's to generate, and return a uint[].
8. 6-7 applies to Buffers too. This is more C#-idiomatic, out and ref feel very C-idiomatic.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

1. Why overloads ? Is there a technical reason the old ones should be left ?

The core GL.cs is generated by a tool. You'd place your hand-written functions in GLHelper.cs, so they'd technically be overloads until/unless I update the generator to suppress these functions.

Unfortunately it's not possible to update the generator to create these functions automatically... (it would have been easy otherwise)

2. Nothing. Just execute "Build.exe vs" from the commandline to create a Visual Studio project (Build.exe can be found in the Build/ folder).

3. VS2005 is fine.

For OpenGL I can think lists, textures, buffers, shaders and programs on the top of my head. For OpenAL it's Buffers, Sources and (I think) Effects.

Edit: Actually it's be best if the overloads were left in. There are programs that rely on those, and it's the most common API (identical between Tao, OpenTK, CsGL etc). You'd never see them anyway, if you don't want them (intellisense displays the functions with the fewest parameters first) :)

Inertia's picture

AL: Sources, Buffers
Efx: Effects, AuxiliaryEffectSlots, Filters
GL: Buffers, Lists, Queries, Textures

It's not so much the problem of doing it, more the insight why it's necessary. I'll keep using ref/out, because they are the way I understand telling the API about locations in memory.

Edit: Shaders only return 1 Handle I think. GL.Arb.GenPrograms is missing tho

DeleteBuffer(ref int);
DeleteBuffer(int);  // this should actually be faster :)

Why should it be faster? Because you typed less?

the Fiddler's picture

The argument for these, is that they'd fit the managed world better - there's this strange aversion regarding memory locations and pointers and the ref/out overloads remind people of these :p

Edit: arguable the first is a little cleaner/nicer to read:

int[] buffers = GL.GenBuffers(10);
// -- vs --
int[] buffers = new int[10];
GL.GenBuffers(buffers.Length, buffers);

Even if the first just calls the latter internally:

public static int[] GenBuffers(int n)
{
    int[] buffers = new int[n];
    GL.GenBuffers(buffers.Length, buffers);
    return buffers;
}
Inertia's picture

Mhmm actually I think the ref/out keywords are one of the best things about C#. At least the 'out' makes it very clear in which direction the data is used. I'd like to see an 'in' keyword too (compiler could check if you make any modification inside the method to it and complain), because it is very expressive about the direction.

Vector3.Add( in V1, in V2, out V3 );
V3=Vector3.Add( V1, V2 );

Regardless of performance, the 1st version is more like the machine understands the operation, while the 2nd is more human-readable. The 2nd version can easily lead to bugs with just a small slip:

V3-=Vector3.Add( V1, V2 );

Are you sure you would have found this slip in a larger mathematical calculation on 1st sight? Compiler will not complain about this, while any usage error to the 1st mentioned function will.

Edit:
int[] buffers = GL.GenBuffers(10);

does not allow:

int[] buffers = new int[10000];
GL.GenBuffers(5, out buffers[1234]);
the Fiddler's picture

A reason to keep both :)

Although this example isn't really useful for name generation (which is probably why they made the shader stuff generate only one name, and not an array).

I read recently a rather interesting post, which claimed that you do not need to generate a name before using it. According to the poster, this is not an error as the driver will allocate it as soon as you bind it. He was using this to define his own naming algorithm, which would allow him to avoid keeping a map of allocated resources.

Slightly off-topic, but interesting nonetheless.

objarni's picture

Fiddler/Inertia: I guess we have to agree that we disagree here, then.

I find ref/out just barely better than pointers, because pointers' is basically what they are, even if I agree separating the intensions are better than just passing a pointer. It's software engineering experience leaking through, I guess.

Also, there's less to parse for the brain the less letters there are on screen!

Regarding the syntax

V3 = Vector3.Add( V1, V2 );

.. I would really like to write it the way I write it on paper / read it in mathematics books:

V3 = V1 + V2; // I know we've been through this discussion already, just wanted to express the ideal

That is for me the cleanest syntax.

As a wise man said, "90% of a programmers life is reading code, 10% is typing".

int[] buffers = new int[10000];
GL.GenBuffers(5, out buffers[1234]);

Inertia: this example seems a little constructed to me ;)

Inertia's picture

My point was, you cannot enforce your preference on other users, no matter how much more elegant it might read. Someone might have use for generating a larger array than he required handles. (if the array is 10000 or 10 handles is just a detail here, if you only want to generate 5 at this point.)

I believe this is pretty much about how much you are willing to bend your mind to fit into the machine's way of understanding, or the other way around. Once you have taken a look at assembly language you will see that it's only an illusion trying to bend the machine's 'thinking', so you might aswell express your commands in a way it can understand efficiently.

objarni's picture

Inertia: please don't lecture me on assembly language! :)

I've done assembly from the Commodore 64 to Amiga to PC.. I've even built a couple of emulators!

When you've done enough programming, you recognise and appreciate languages and syntaxes that are suitable for humans, not machines.

If you like low-level stuff, why don't you program in C/Assembly..? C#/OpenTK is a different animal, IMHO.

Maybe you have a lot of code using Name-generation the way it looks right now in OpenTK, and don't want the additional work of changing this..? So let there be overrides, both convenient and inconvenient, at least for awhile. They could be marked "deprecated" and removed until OpenTK1.0, or just kept all along.

I'm trying to make the best of OpenTK, I hope you are too. I see no reason why the APIs need to be harder/uglier to use than is possible.

Is there no one else having an opinion about the Gen/Delete methods and their ref/out usage? Compare these two ways:

1.

uint name = AL.GenBuffer();
uint[] names = AL.GenBuffers(10);
AL.DeleteBuffer(name);
AL.DeleteBuffers(names);

2.

uint name;
AL.GenBuffers(out name);
uint[] names = new uint[10];
AL.GenBuffers(names.Length, out names[0])
AL.DeleteBuffers(ref name);
AL.DeleteBuffers(name.Length, ref names);
Mincus's picture

I'm quite happy with how the GL stuff currently works. I've not looked at the AL things too much yet. I'm waiting on the 0.9.1 release first.

Inertia's picture

I've changed the source code for 2. I'd like to point out that you're basically doing nothing else but merging declaration and initialization. This is not a common use case, you typically want your arrays to survive the exit of the current method.

>If you like low-level stuff, why don't you program in C/Assembly..?

Productivity. You spend far less time in the debugger with C#

>...don't want the additional work of changing this..?

Important is the fact that removing current GL.GenTextures overloads in favor of compacting 2 lines into 1 will break pretty much every app written in OpenTK so far. I don't see removal as an option, no matter how much you keep nagging. I see no problem adding your suggestion as an additional overload though.

>I see no reason why the APIs need to be harder/uglier to use than is possible.

It already is damn pretty compared to the alternatives.