A quick sanity check regarding how shaders work

My problem was a huge lack of tutorials. There are tutorials for complete newbies that go up to the point where they apply textures and some also add phong lighting. But from there there’s absoultely zero tutorials/examples I could find apart from very complex stuff which you have no way of understanding if you only finished the basic tutorial.

The maths gets written funny usually. Using multiply / add / divide (MAD) to save instructions. So a simple division by 2 becomes a multiple of .5 - and kind of seems confusing until you understand why.

Which raises the question: What is faster on GPUs? *= 2 or << 1?

1 Like

If you mean bit shifting I would have to say that. As far as I know it’s virtually free? I don’t know if it means the same thing in glsl.

1 Like

My guess would be that in 99.99% of the usecases there would be no measurable difference.

Most of the new features added to the silicon are targeting memory bandwith / random access, so i guess that is usually the limiting factor

@zissis Thanks! Ok. That does sort it out a bit more as well. Seems that the whole ball of wax leverages rasterization and interpolation to figure out what is displayed where and how… Tonight I hope to actually get cracking on with this extra information now and try out the tutorials but with better understanding thanks to everyone here! :smiley:

@nehon So I might be able to answer that one since that’s pretty much where I am (although attempting to forge ahead). When I was taught Object Oriented Programming in college absolutely nothing clicked whatsoever and we were being taught Java. Now I have no issues with Java (clearly). The issues aside from the teacher speaking as loud as a mouse in a auditorium was that the language she used was almost foreign entirely so following along was rather difficult if you don’t already understand what was being said before. I found that in the case of a lot of the stuff I read on Shaders there was that similar issue of language used in articles.

Let’s give an example that isn’t programming related.

The Lord of the Rings trilogy doesn’t start off exceptionally heavy at all. In fact it starts off in a very familiar setting. A small town filled with happy (but boring) people and they’re about to have a party. Cool. From there it builds into the whole Epic. This is easy to follow.

Now… If you were exposing someone to this would you start them off with these books starting at either the Hobbit or The Fellowship of the Ring or would you start them like this “Yo. There’s some Hobbits and a ring (don’t worry about that right now) and they’re going to go for a bit of a walk. Now. Read the Silmarillion.”

I found that the tutorials I was coming across would either start super low and easy to follow but then jump in difficulty without really building on the previous lesson or just start right at the beginning with heavy math but without explaining how that math is utilized or even coded properly.

Basically as @zissis was saying there isn’t so much a difficulty curve for some people more like a curve that happens to have a gully along the path without any clear way to cross it.

But armed with the information everyone has given here I think I might be able to cross that gully.

2 Likes

@nehon Actually I just found a good example of the weird little “leap” that a lot of tutorials do with the article you wrote on the Wiki: https://jmonkeyengine.github.io/wiki/jme3/advanced/jme3_shaders.html#simple-example-rendering-a-solid-color-on-an-object

Up to this point it’s been talking about matrices, variables, and what a shader “is”. The example you give there (which I now understand loads better) . Why do we need a vertex and fragment shader for this? I mean… it really doesn’t seem that gl_position contributes anything to the fragment shader. I don’t see it being used there… Do you?

The engine passes the object space coordinates to the vertex shader. We need to compute its position in projection space.

Why do we have to do that?

//- gl_Position is the standard GLSL variable holding projection space
//position. It must be filled in the vertex shader

Why?

I get it now (I think) but like programming in Java usually goes

Make a class that does a thing. Put in functions to break the thing down into small bite size chunks. Functions that need data from another function need to pass that data either by calling it with those variables in the call or via a global.

Everything is very plain to see this way. Shader’s however have a buncha “stuff” going on that you can access and in some cases “need” to access upon pain of death.

That’s probably where people are getting lost. Or at least that’s where I got lost repeatedly.

re: math, for years (decades?) a bit shift in user-level code has not been faster than a mult… but that’s especially true in floating point.

In the pentium era, an integer multiply was down to 2 ticks… and that was because it was shunted over to the floating point pipeline and back. Floating point multiply was 1 tick. (By the way, I’m pretty sure this is one of the reasons RISC lost ground to CISC on desktop architectures… once 90% of the instructions already operate in one tick, RISC isn’t quite as attractive on the performance side, only the cost side [smaller die])

Anyway, it would surprise me very very much if a bit shift is faster than a mutiply in a shader… and since 99% of the math you do in a shader is floating point, I don’t even know what a bit shift would mean in that case.

Shaders are optimized to do floating point math. It’s their reason to exist, really.

I also don’t expect /2 to be any slower, either. And if it is then the shader compiler would likely already convert that to * 0.5 for you.

Even sqrt() seems not as slow as one might expect… though I still instinctively avoid it of possible. When it was 200+ ticks, you learned not to touch the fire.

You’re actually saying to the GPU “hey my vertex is here on screen, now send all my varying to the pixels in this area and do your magic interpolation thingy”.

1 Like

This is also why it’s best to start with the simplest shader possible and then add stuff. All of the “must be wired” stuff is already there and it should be simpler to understand what leaving it out will do.

I can’t stress enough the break-fix-break approach to learning (just about anything really)… and JME is really nice for being able to quickly iterate on stuff like this. I guess online sites like shader toy are even better for that… but JME was all I had back then.

1 Like

Oh yeah, that was a long journey…

When I first started learning about shaders I already had visited several lectures about computer graphics (how projection from a frustum to screen coordinates is done and what rasterization and z-buffer means, what the difference is between the rasterization pipeline of graphics cards and the raytracing stuff on the other hand. Also, we had a math class about the matrix and vector stuff and how to invert a matrix or transpose a matrix - and what multiplying matrices in 3D means (it’s quite the starting point).

Then I first came across the Red Book (“OpenGL Programming Guide”) which is nice to understand how OpenGL used to work before the invention of GLSL. Then the Orange Book (“OpenGL Shading Language”) shed some light on how shaders work.

So it’s quite a journey and still today I’m amazed by what people on “shader toy” did or the things from the old “GPU gems” (which are free online books since quite a while) or what the “OpenGL 4.0 Shading Language Cook Book” has to offer. I’m not fully into tesselation and have not much time for 3D graphics today.

But yeah, everybody learns in a different way. I hope you learn what you want to learn. I think both @nehon and @pspeed have interesting ways - either start where the movie begins and follow it sequentially -or- toy around, see what happens - both interesting ways. I used a mix of these to learn Blender and the movie-way to learn OpenGL+GLSL. Also, the “break-fix-repeat” is a great idiome when you want to do visual debugging (which is what effectively helps you to fix a broken or buggy shader - you need a way to understand what is wrong and it’s often the fastest way to make it in that way, that check-visuals and toy-around way). :slight_smile:

1 Like

@nehon,

Great point!!!

For CPU cores are doubling every 3-4 years whereas GPU cores as in CUDA cores are popping at a huge rate, I think currently it’s 4096 cores. So GPU’s IMO will be the “go to” place for processing as in Physics. A few years back I heard about the PPU (Physics Processing Unit) coming to the front but now see that can be and is done on the GPU.

So yep, learning can be scary but once learned WOW was that worth it!!!

We are in a transitional world between *PU’s and the smell is yummy!

This topic thread has been really good!!!

Cheers!

Adam

From an EE standpoint a “shift” operation is always faster than a multiply but if a compiler notices that *=2 is effectively <<1 then it should do a “left shift”.

Can someone else that understands IEEE floating point tell me how a bit shift can perform a float multiply?

(Hint: you can’t)

It’s so exceedingly rare to use ints in a shader.

1 Like

Your right about floating points don’t SHIFT…I was just referencing the “good ol days” when we had to count cycles (got a great one for sqrt for a 6502, 6800 series thats whopping fast) and map memory then tell marketing “this is the map, what do you want to chuck?”…Sure was fun riding the horse bareback when I did 7 games for commodore C-64/Amiga but the new stuff with the GPUs give me a familiar buzz of the Good Ol Days!

So with that…my SHIFT is over :wink:

2 Likes