empaempa / GLOW

GLOW is a WebGL wrapper, which focuses on easy creation and use of shaders.
http://i-am-glow.com
MIT License
244 stars 28 forks source link

Using Float32Array slower than var #3

Open notlion opened 13 years ago

notlion commented 13 years ago

Hey! First of all thanks for the nice lib. I started on a similar low-level webgl wrapper but GLOW seems pretty clean so i'm giving a try.

I wonder though what is the reason for using Float32Arrays in your Vectors and Matrices? I did a little test, and operations are about 8-10x slower than var in Chrome, and 2x in Firefox:

http://bin.onecm.com/posts/testGLOWVector3/

This is tested on Chrome 13.0.782.41 beta and Firefox 4.0.1

empaempa commented 13 years ago

Hey! Thanks for trying it out - makes me very happy.

The only reason for using Float32Arrays is for cleaness and a hope for performance boost in typed arrays in the future. That said, it's pretty simple to change math objects in GLOW to your own or a modified version of GLOW's math objects. The key is to change the...

GLOW.Uniform.prototype.getNativeValue

...function to return a Float32Array with your math objects' data. For reference, please look at the Three compability code somewhere in the extras - I'm on vacation and don't have the code in front of me. When I come back I'll take a look and reconsider using Float32Array and add a GLOW.MatrixX.valueAsFloat32Array() - unless you've already updated this by then ;)

I'll be completely off the map til Wednesday, so please don't expect any answers the coming days.

BTW: automatically interleaved attribute data is coming next week along with some other goodies. We're also working on some exporters/parsers from Unity. Stay tuned!

notlion commented 13 years ago

Auto-interleaving is definitely exciting!

Unless you have some reason to believe Float32Array will receive some specific interpreter optimizations in the future, it seems that it will always incur a conversion cost, even if it's only the cast from double to float, and then there's the bounds checking and additional property-lookup associated with every read/write..

I found an interesting post on the topic of using Float32Array for vector representation here: http://www.jiglibjs.org/?p=116

empaempa commented 13 years ago

Auto-interleaving is up, please check it out. I'll write a post on the details tomorrow night at http://i-am-glow.com.

Did you change the math objects to use Array instead of Float32Array and added getDataAsFloat32Array()? If not, I'll look into that soon - it's a small fix. I've read the blog post you sent before and it's spot on, I think :)

Thanks for keeping me on my toes ;D

notlion commented 13 years ago

Hey thanks for the heads up. I'm testing it out now.. One problem I ran into was that InterleavedAttributes.js wasn't included in build.py. After fixing that it seems to work.

On an unrelated note, how do I create my own texture objects? Do i just need to have an object with .texture and .textureUnit? That doesn't seem to work..

empaempa commented 13 years ago

Sorry for that, it's updated now.

About texture objects: not really sure what you're trying to do? For example, if you like to have two textures to switch between (only one used at the same time) you should be able to create a...

var mySecondTexture = new GLOW.Texture( "secondTexture.jpg" ); mySecondTexture.init( myFirstTexture.textureUnit );

...and then to switch in the shader...

myShader.uniforms.samplerUniformName = mySecondTexture;

...haven't tried it, though ;)

empaempa commented 13 years ago

Hey again! Just updated so matrices use Array instead of Float32Array. Please try it out. The downside with this way is that you have to load from an Array into a Float32Array before loading the uniform into WebGL. In some cases this might be slower than having it as a Float32Array to start with (a projection matrix for example - as it never really changes).

Anyway, check it out :)

notlion commented 13 years ago

Hey thanks. Hrm I see. Since you set the uniforms automatically and there's no way of knowing if one has changed, they must all be set at least once per draw, and thus the reason to store them as Float32Arrays.

The texture question was regarding things defined outside the texture object built into GLOW. For example, I want to make a texture from a Canvas element, or a Float32Array. In that case I need to wrap it in something that mimics GLOW.Texture with a .texture, .textureUnit, and init() right?

empaempa commented 13 years ago

Float32Array: exactly, so I'm thinking of going back to Float32Array for the "cleanness"-reason. Another way I'm considering is using a .dirty flag to keep track of if it has been updated. The downside with this is that you need to set the dirty flag manually if you modify the matrix values directly (not using the built in functions).

Texture: yes, that should work. The init function gets the texture unit passed into it. The plan is to make support for canvas, Float32Array etc in the GLOW.Texture. The idea is that, instead of an URL, you pass an object into the constructor where you define either .url .canvas .image .video .array .width .height .color and these are used in a logical way. If you feel like it and it's urgent for you, please go ahead - it'll take some time before I get there myself :)

notlion commented 13 years ago

I think the combination of using vars like Matrix4.m01, m02, m03, Vector3.x, y, z and a dirty flag seems to be a good compromise. On one hand it adds an additional boolean set for every operation, but the speed boost from not using the values F32 array probably more than makes up for it. That means you also only need to make a Float32Array at most once a frame, and probably less if the matrix / vector isn't set dirty.. The downside like you said is that if you change x, y, z directly you'd need to know about the dirty flag :/

notlion commented 13 years ago

Just ran into a situation which broke in the getValueAsFloat32Array version. I'm setting a uniform to use a bare Float32Array:

kernel_power: { value: new Float32Array(kernel_power) }

with getValueAsFloat32Array I would need to use this:

kernel_power: { getValueAsFloat32Array: function(){ return new Float32Array(kernel_power) } }

which is a bit convoluted. I see why you made the choice to use F32A now. Maybe the thing to do is use a different vector library if you really need the speed?

empaempa commented 13 years ago

I just reverted back to using Float32Array, so if you like, just update and it's back to how it was. Using Array adds extra complexity, and I like to keep thing simple ;)

I'm thinking of writing a compatibility object for glMatrix, which is widely used. It's not really faster than the math objects in GLOW but many developers use it and like it.

empaempa commented 13 years ago

BTW: the texture problem might be that you don't have the .id, which the cache is using to keep track of what is set and what isn't. Try adding:

myOwnTexture.id = GLOW.uniqueId();

empaempa commented 13 years ago

Just updated the GLOW.Texture to support canvas, so now you can do...

var texture = new GLOW.Texture( { canvas: myCanvas } );

Please note that url is now passed like...

var texture = new GLOW.Texture( { url: "image.jpg" } );

You can also set magFilter, minFilter, wrapS, wrapT (or just wrap to set both) and mipmap (true/false). Haven't had time to really test all possibilities, so please let me know if you run into troubles.