Live data from Hacker News

Weep for Graphics Programming

adriansampson.net

81–90 of 162 posts

Re: Weep for Graphics Programming

#81
post #64
post #26

What we really need is a project to do for GPUs what RISC-V[0] is about to do for CPUs. It's high time we as a society broke away from the stranglehold proprietary companies such as Nvidia and Intel have over us. It's time for a completely open computing platform for all of us to use to the fullest advantage of society. [0] https://en.m.wikipedia.org/wiki/RISC-V

That sounds great. Are you going to pay for it? That isn't an attempt at snark--RISC-V is interesting. It isn't competitive . GPU technology is very interesting. This, without dump trucks of cash, won't be competitive, either. There is a question of cui bono here, and you need to answer that to make what you advocate make sense.

dump trucks of cash

How about $30,000[0]? Seriously, it's not the 90s anymore. The cost of making a chip is not insane and it's going to go down every year. As Moore's Law slows to a halt, we enter the golden age of computer architecture[1].

[0] http://www.eetimes.com/author.asp?doc_id=1327291

[1] https://www.youtube.com/watch?v=mD-njD2QKN0

Re: Weep for Graphics Programming

#82
post #54

Earlier quoted context omitted.

> When writing my first OpenGL code, I was stunned by the amount of boilerplate required. Huh, actually the amount of boilerplate required for getting a triangle to the screen with OpenGL is minimal. - Create a context - fill a buffer with the triangle vertex data - load buffer to OpenGL - create vertex shader implementing vertex to position transformation - create vertex shader implementing pixel coloirization - iss…

And yet you've just described a decent amount of boilerplate. The fact that future iterations of OpenGL and OpenGL ES have nuked the fixed function pipeline is sort of annoying. I'm not saying there should be more codepaths in the implementation, but if there were a default compiled fixed function vertex shader and fragment shader, it would be helpful. What you've just described for rendering one primitive includes c…

> when this task used to be as simple as:

a) Immediate Mode has been out of fashion for since before the turn of the century. Even the good old NVidia GeForce2 of 1998 already had OpenGL extensions that are essentially vertex buffer objects; you can in fact use the GL_ARB_vertex_buffer_object extension on a GeForce2. If you don't believe me, I'm currently headed to my mother's and I have a old box stored in her cellar with a GeForce2 in it; I could give interested parties a SSH into it (you just have to live with a old Gentoo installation that I didn't touch for some 10 years or so).

b) There's a certain complexity cutoff where the whole shader loading boilerplate plus shader code is less, than what it takes to setup an equivalent fixed function pipeline setup. Making an educated estimation I'd say, that the break even point is, when enabling a register combiner on two textures, one a cube map, the other a normal+shininess map, setting DOT3 combining of normal with vertex secondary color (for normal mapping), directing the normal map into the cubemap texture coordinate lookup and fading between reflection and dull shader based on shininess. Sounds complex? Indeed it is, but keep in mind that this kind of thing was already possible with the GeForce3 (at least, I think it may even work on the GeForce2, but after over 14 years since writing the last time a program targeting it, I'm a bit shaky on the details).

Anyway, to set up this kind of register combining you'd need between 4 to 5 calls of glTexEnvi per texture. Another 3 glTexEnvi calls for setting up the secondary color muxing mode and another 3 calls for setting the final stage fading mode. Add to that the hours of twisting your brain to figure trying to wrap your mind around all the relevant state switches in the register combiners.

With shaders you simply write down what you want.

Re: Weep for Graphics Programming

#83
post #66
post #17

I spent a lot of time making toy engines with XNA and carried much of its lessons to my toy engines in C++. If your asset can be built, then your asset should be built. Content pipelines. > Shaders are Strings If you're using Vulkan, compile your shaders to SPIR-V alongside your project. If you're using OpenGL you're mostly out of luck - but there's still no reason to inline the shaders even with the most rudimentary…

You can technically make shader binaries with OpenGL, the problem is Khronos never standardized a bytecode for it so you are basically shipping three binaries, one for each GPU vendors own intermediary (if they even have one, I only know AMD does): https://www.opengl.org/sdk/docs/man/html/glShaderBinary.xhtm...

Noooo, please don't do that. That is not the intention of that API at all!

The API was built so that the cost of compilation by the driver would only be done once (likely at install, or at driver update time). So the idea is that when you are installing your PC game, it is compiling all the shaders against the current driver rev and hardware in your machine. Then when you play the game, it just loads the locally compiled binaries so your game doesn't hitch at random times when the driver compiler decides to kick off a compilation pass.

However, the binary is very sensitive to the driver version (as it owns the compiler), and the hardware itself. The binaries will differ across vendors, vendor architectures, and even sub-revisions inside of a single architecture.

Bonus: This API was provided as part of the GL_ARB_ES2_compatibility extension, in order to ease porting from OpenGL ES 2 to (big) OpenGL. OpenGL has a different API/extension, glProgramBinary, that is preferred for OpenGL. glShaderBinary might not even really work on any desktop implementation.

Probably the best source for this, though this information is relatively...obfuscated: https://community.amd.com/thread/160440

Re: Weep for Graphics Programming

#84
post #58

It seems unlikely that any of this will change, because control is in the hands of a relatively few powerful organizations who honestly have no interest in making life easier for software engineers working on graphics programming; and those engineers who do have to put up with it have long since given up or chalk it up to experience; and those developers would probably resist any changes now simply because change req…

> who honestly have no interest in making life easier

Hrm...I've thought about this a lot, and I don't think it's as much as not having interest, as much as not having time. Or at least...not being able to monetarily demonstrate to their employers that it would be worth the engineers time to generate educational resources and better tools.

I do think AMD is trying to get better in this area with their GPUOpen stuff, though of course, you never know what might happen if AMD suddenly becomes top dog.

Re: Weep for Graphics Programming

#85
post #54

Earlier quoted context omitted.

And yet you've just described a decent amount of boilerplate. The fact that future iterations of OpenGL and OpenGL ES have nuked the fixed function pipeline is sort of annoying. I'm not saying there should be more codepaths in the implementation, but if there were a default compiled fixed function vertex shader and fragment shader, it would be helpful. What you've just described for rendering one primitive includes c…

> when this task used to be as simple as: a) Immediate Mode has been out of fashion for since before the turn of the century. Even the good old NVidia GeForce2 of 1998 already had OpenGL extensions that are essentially vertex buffer objects; you can in fact use the GL_ARB_vertex_buffer_object extension on a GeForce2. If you don't believe me, I'm currently headed to my mother's and I have a old box stored in her cella…

Yes, I'm aware of how both immediate mode and vertex arrays work in OpenGL.

The problem, and this is even getting away from what the article addresses, is that a green developer approaching the application must learn an entirely new language (shaders) before drawing a single primitive. In mattbee's example, what is the beginner supposed to think of the line "#version 410" or "in vec3 vp" which is not even C code?

I'm also not saying that all of the legacy functions from the fixed-function pipeline should be maintained, with all of their specific parameters, but that those attributes should be bound with a default shader that supports all of the same capabilities. So, using GLSL attribute accessors with each platform having the same default shader (and default parameter names). Then, wrap the IM example in arrays, call a few binds, and make a draw call. That's much simpler than writing two embedded programs inside your first program. I think it would have been very beneficial if OpenGL ES had been rolled out with a design like this.

Maybe it's because graphics programming is so feature focused that it creates a problem. For me, the issue is the obstacles between getting shapes on the screen, especially in contexts like WebGL or mobile.

Re: Weep for Graphics Programming

#86

Earlier quoted context omitted.

I've also been really impressed with glium. I don't think I've ever had as nice of a blank editor -> quad on the screen experience in a long while. At least since the days of fixed-function. I say this as someone who's written ~2 commercial renderers from some various degrees from scratch. Normally it's 1-2 days to just setup all the various infra for handling shaders/uniforms/etc.

To expand on this a tad, here's the intro code for glium, getting a triangle on the screen is just one page of text: https://github.com/tomaka/glium/blob/master/examples/tutoria... That includes: Window creation and event handling, fragment shader, vertex shader, varying declaration and binding. Uniforms are pretty trivial on top of this(also done via macros so there's no raw strings). The whole tutorial is really so…

But still, just one page of code? Ideally, drawing a quad should be a one-liner.

Re: Weep for Graphics Programming

#87

Earlier quoted context omitted.

To expand on this a tad, here's the intro code for glium, getting a triangle on the screen is just one page of text: https://github.com/tomaka/glium/blob/master/examples/tutoria... That includes: Window creation and event handling, fragment shader, vertex shader, varying declaration and binding. Uniforms are pretty trivial on top of this(also done via macros so there's no raw strings). The whole tutorial is really so…

But still, just one page of code? Ideally, drawing a quad should be a one-liner.

If you want to use a higher-level framework then one-liner might make sense.

For OpenGL you want control over state changes, uniforms and a slew of other things. Otherwise your performance/control will suffer significantly.

Look at the things I listed there, that's the bare minimum you need to do the above, and fitting that in one page is pretty impressive.

Re: Weep for Graphics Programming

#89
I think his conclusion is valid; compilers can now handle register assignment and other boilerplate pretty well (Metal does this superbly and SPIR-V seems very good).

My only qualm is that he treats these aspects that he deems outdated as unnecessary, which is just not true. For a long time there was no other alternative. Introducing High Level languages for programmable shading was a huge deal and it actually decreased a lot of complexity. In reality it simplified a lot of stuff that was quite difficult before GLSL/HLSL came along.

He seems to be making some kind of rallying call for change but the next generation is already here. We'll have to keep supporting that old approach for a while longer but the problem really has been solved (to some extent).

Also, old person rant: "Back in my day, we only had 8 register combiners and 4 blend states. And we liked it!"

Re: Weep for Graphics Programming

#90
I think the author has good intentions (don't we all), but I don't think he understands enough about graphics programming to make some of the proclamations/requests in the article. Not that I blame him...it's hard to get an understanding of GPU programming outside the scope of a game dev or IHV.

> To define an object’s appearance in a 3D scene, real-time graphics applications use shaders... Eh, the shaders are just a part of the GPU pipeline that transforms your vertices, textures, and shaders into something interesting on the screen.

This is already oversimplifying what GPUs are trying to do for the base case of graphics.

> the interface between the CPU and GPU code is needlessly dynamic, so you can’t reason statically about the whole, heterogeneous program.

Ok, so what is the proposed solution here? You have a variety of IHVs (NV, AMD, Intel, ImgTec, ARM, Samsung, Qualcomm, etc). Each vendor has a set of active architectures that each have their own ISA. And even then, there are sub-archs that likely require different accommodations in ISA generation depending on the sub-rev.

So in the author's view of just the shader code, you already have the large problem of unifying the varieties of ISA under some...homogenous ISA, like an x86. That's a non-trivial problem. What's the motivation here? How will you get vendors to comply?

I think right now, SPIR-V, OpenCL, and CUDA aren't doing a _bad_ job in trying to create a common programming model where you can target multiple hardware revs with some intermediate representation, but until all the vendors team up and agree on an ISA, I don't see how to fix this.

On top of that, that isn't even really the only important bit of programming that happens on GPUs. GPUs primarily operate on command buffers, of which, there is nary a mention of in the article. So even if we address the shader cores inside the GPU, what about a common model for programming command buffers directly? Good luck getting vendors to unify on that. Vulkan/DX12/Metal are good (even great) efforts in exposing the command buffer model. You couldn't even _see_ this stuff in OpenGL and pre-DX12 (though there were display lists and deferred contexts, which kinda exposed the command buffer programming model).

> To use those parameters, the host program’s first step is to look up location handles for each variable...

Ok, I don't blame the author for complaining about this model, but this is an introductory complaint. You can bind shader inputs to 'registers', which map to API slots. So with some planning, you don't need to query location handles if you specify them in the shader in advance. I think this functionality existed in Shader Model 1.0, though I can't find any old example code for it (2001?).

That being said, I certainly don't blame the author for not knowing this, as I think this is a common mistake made by introductory graphics programmers, because the educational resources are poor. I don't think I ever learned it in school...only in the industry was this exposed to me, to my great joy. Though I am certain many smarter engineers figured it out unprompted.

> OpenGL’s programming model espouses the simplistic view that heterogeneous software should comprise multiple, loosely coupled, independent programs.

Eh, I don't think I want a common programming model across CPUs and GPUs. They are fundamentally different machines, and I don't think it makes sense to try to lump them together. I don't think we just assume that we can use the same programming methodologies for a single vs multi-threaded program. I know that plenty tried, but I thought the best method of addressing the differences was education and tools. I'd advocate that most effective way that GPU programming will become more accessible will be education and tools. I have hope that the current architecture of the modern 'explicit' API will facilitate that movement.

Post reply on HN