WebGL and OpenGl

Lately, you’ve probably heard a lot about WebGL and how it is transforming graphics rendered in a web browser. The consortium definition is quoted below. As highlighted in the quotation, here I will try to show the similarities between desktop OpenGL and browser WebGL.

WebGL is a cross-platform, royalty-free web standard for a low-level 3D graphics API based on OpenGL ES 2.0, exposed through the HTML5 Canvas element as Document Object Model interfaces. Developers familiar with OpenGL ES 2.0 will recognize WebGL as a Shader-based API using GLSL, with constructs that are semantically similar to those of the underlying OpenGL ES 2.0 API. It stays very close to the OpenGL ES 2.0 specification, with some concessions made for what developers expect out of memory-managed languages such as JavaScript.

If you are not familiar with some of the terminology, review these pages.
OpenGL – Then and Now
Programmable pipeline with VBOs and Shaders

You can access the code at https://github.com/cognitivewaves/OpenGL-Render .
Desktop OpenGL : main.cpp
Browser WebGL : webgl/main.html

As you will see in the snapshots of code snippets, most of differences are in the programming language constructs of C/C++ vs JavaScript. Hope it provides some insight into how OpenGL and WebGL are more similar than different.

Shader Code

OpenGL and WebGL Shader code differences

Shader Initialization

OpenGL and WebGL Initialize shaders code differences

Draw

OpenGL and WebGL draw code differences

Shared Responsibility Fulfilled

Most people, including myself, agree to the idea of our shared responsibility towards the systems and software that are made available to us for “free”. We all understand that there is cost (monetary, manpower, administration, etc.) and hence it is not free in the true sense. Someone, somewhere is paying for it. Someone has taken up the burden of our missing contribution, however minuscule it may be.

Yet, when it comes to acting on it, we defer, procrastinate and finally pass on it, expecting and hoping that someone else will sustain it. I was no exception. I would go places, spend on food and drinks which was more expensive that it was worth, but didn’t make the much needed contribution. It is not that the monetary contribution has to be much and yet we don’t. This is bystander apathy, a very regressive attitude for a society.

Finally in November 2013, I committed myself to make a contribution as little as USD 5 to a few of the software123 that I use regularly. I did not go bankrupt (obviously) and life is better now that I have fulfilled my shared responsibility. Having taken that first step, I am now committed to contributing every year.

If all our past donors simply gave again today, we wouldn’t have to worry about fundraising for the rest of the year – Jimmy Wales, Wikipedia

If everyone reading this chipped in $3, we would be supported for another year – Mozilla Firefox

I promise you, take that first step and make that contribution. It will give you a sense of satisfaction.

OpenGL-compatible

OpenGL – Then and Now

I had spent a fair amount of time on OpenGL about 10 years back, though I wouldn’t call myself an expert. Over these 10 years, I noticed OpenGL evolving and kept pace with it from the outside. Then came WebGL and wanted to get my hands dirty. That’s when I realized that I was way out of touch. As they say, the devil is in the details. All the terminology and jargon just wasn’t adding up. So I went back to basics.

Here is an attempt to summarize the evolution and status of OpenGL. It’s not meant to be an introduction to OpenGL but more for those who want to go from “then” to “now” in one page. For more details, see OpenGL – VBO, Shader, VAO.

Background

Traditionally, all graphics processing was done in the CPU which generated a bitmap (pixel image) in the frame buffer (a portion in RAM) and pushed it to the video display. Graphics Processing Unit (GPU) changed that paradigm. It was specialized hardware to do the heavy graphics computations. The GPU provided a set of “fixed” functions to do some standard operations on the graphics data, which is referred to as the Fixed Function Pipeline (FFP). Though the Fixed Function Pipelline was fast and efficient, it lacked flexibility. So GPUs introduced the Programmable Pipeline, the programmable alternative to the “hard coded” approach.

OpenGL

OpenGL 1.0 (Classic OpenGL) provided libraries to compute on the CPU and interfaced with the Fixed Function Pipeline. OpenGL 2.0 (and higher) adds Programmable Pipeline API.

OpenGL-ES (GLES)

OpenGL ES is OpenGL for Embedded Systems for mobile phones, PDAs, and video game consoles, basically for devices with limited computation capability. It consists of well-defined subsets of desktop OpenGL. Desktop graphics card drivers typically did not support the OpenGL-ES API directly. However, as of 2010 graphics card manufacturers introduced ES support in their desktop drivers and this makes the ES term in the specification confusing. OpenGL ES 2.0 is based on OpenGL 2.0 with the fixed function API removed.

WebGL

WebGL is a Programmable Pipeline API, with constructs that are semantically similar to those of the underlying OpenGL ES 2.0 API. It stays very close to the OpenGL ES 2.0 specification, with some concessions made for what developers expect with memory-managed languages such as JavaScript.

Programmable Pipeline, Shaders and GLSL

The Programmable Pipeline requires a Program which is “equivalent” to the functions provided by the Fixed Function Pipeline. These programs are called Shaders. The programming language for the shaders used to be assembly language but as the complexity increased, high-level languages for GPU programming emerged, one of which is called OpenGL Shading Language (GLSL). Like any program, the Shader program needs to be compiled and linked. However, the Shader code is loaded to the GPU, compiled and linked at runtime using APIs provided by OpenGL.

Conclusion

So, modern OpenGL is great, except it makes learning graphics programming harder (much harder). It is generally easier to teach new graphics programmers using the Fixed Function Pipeline. Ideas behind Shaders are pretty complicated and the minimum required knowledge in basic 3D programming (vertex creation, transformation matrices, lighting etc.) is substantial. There is a lot more code to write and many more places to screw up. A classic fixed function OpenGL programmer was oblivious to most of these nasty details.

“Then” was Fixed Function Pipeline and “Now” is Programmable Pipeline. Much of what was learned then must be abandoned now. Programmability wipes out almost all of the fixed function pipeline, so the knowledge does not transfer well. To make matters worse, OpenGL has started to deprecate fixed functionality. In OpenGL 3.2, the Core Profile lacks these fixed-function concepts. The compatibility profile keeps them around.

The transition in terms of code and philosophy is detailed in OpenGL – VBO, Shader, VAO.

Shared Responsibility

You buy “stuff”1 everyday. Some are essential, but many others that you probably don’t need. In any case, imagine two scenarios.

Scenario 1

You go to a store to buy and like the look and feel of it. You pick it up and head out of the store. No payment, no receipt, no credit card swipe. Then one day, when you have used it enough and feel that it was worth it, you pay for it, and you pay what you think it was worth. No price tag, no time limits, no collection calls, just your moral obligation.

Scenario 2

You are enticed, cajoled, convinced or fooled into buying it. Pay for it upfront with limited warranty on the product, no guarantee of satisfaction and very few options of getting your money back.

Which one would you chose? Obviously scenario 1, isn’t it?
Not just because it is free until you decide to pay for it, but also because YOU are always in control.

Does it sound too idealistic? Are there even such products and services?
Yes, and many that you are likely using quite regularly too but may not even be aware of it.

Open source software is modeled exactly on the first scenario. Furthermore, many of these are ad-free. Do you rely on Wikipedia, or use Mozilla Firefox or prefer Linux (more accurately GNU/Linux) or any of the thousands of “free” software out there?

Such ecosystems can only exist and sustain with voluntary collective contributions. There are many ways to participate but financial contribution is important. The ball is in your court. Participate in any way possible and fulfill your shared responsibility.

NULL pointer – to check or not to check is the question

The question of ‘should I add a null pointer check?‘ is a very simple and obvious ‘YES’ to the majority of software developers. Their reasoning is equally simple.

  • It can’t do any harm
  • It will help prevent a crash

These are valid statements, but the answer is not that simple. Though a crash indicates a poor quality software, an absence of it is no guarantee for good quality. The primary goal of any software is to provide functionality in a reliable and efficient manner. Not crashing, though good, is useless (and often detrimental in engineering applications) if the behaviour is incorrect.

This perspective comes from my experience in building software for engineers. It can simulate assembling and analyzing complex designs with hundreds and thousands of parts and assemblies. These component sizes could range from a large part to small hidden nuts and bolts, and it is visually impossible to confirm the accuracy of the model. There is no room for ‘possibly unknown’ error, as these components will eventually be manufactured and assembled. The cost of a manufacturing error (because of an inaccurate and unreliable software, though it never crashed) is much too great compared to a software crash and reworking the model.

Defensive programming (to prevent a crash) can easily lead to bad software development.

  1. Hides the root cause
    The basic principle of causal analysis is to find and fix the cause rather than treating symptoms (which seldom produces a lasting solution). A root cause is the basic reason why something happens and can be quite distant from the original effect. By addressing only the symptom, the true cause is hidden. It is bound to manifest itself in some other workflow at which point it will be impossible to trace back to the cause.
  2. Masks other potential issues
    In a large software, subsystems will interact with each other, and one sub-system may be incorrectly using another. By being tolerant to bad behaviour, we not only hide the problem but in fact encourage it because the consequences are not fatal.
  3. Code bloat
    It may not be looked upon as code bloat because it’s just a couple of lines. But consider these additional lines in every function and it certainly isn’t negligible. This is a catch 22 situation. There is a need for this null check to prevent a potential crash but the condition should never be hit as it should never happen. In fact you won’t be able to get any code coverage hit on these lines, and if you do, the cause should be fixed which essentially renders these checks as “dead” code.
  4. Artificially reduced severity
    Typically problems are reported based on their severity. So if you morph a crash with a less severe consequence, the user will not realize the significance and will either not report it or try to work around it which simply defers the problem to a later stage and can easily lead to data corruption.
  5. Sign of poor development
    Adding a line of code without knowing when and why it will be executed reflects poorly on the developer.

Some alternatives are generally suggested as it is very hard to accept a fatal error.

  • Asserts
    Asserts are used to test pre and post conditions but they are not enabled in release builds. No testing is ever done on debug builds (and for a good reason) except by developers (which is limited to a little more than unit testing). So it doesn’t serve as an alternate approach.
  • Report as errors and exceptions
    Error reporting is a means to inform the user of a problem so that it can be corrected. In these cases, the problem cannot be corrected because we don’t know the cause, and if we did, it should have been fixed in the first place. And because we don’t know the cause, it will have to be a generic error, which is telling the user that we don’t know what is happening in our own code. Error reporting should not be misused to fix coding mistakes.

NULL checks out of paranoia should be avoided. However, there are some legitimate uses of it.

  • A NULL can be used to indicate the initial state of an object or the termination of a linked list. In such cases, a null check is of functional value.
  • A dynamic cast or query interface used to check for an object type uses NULL as the return type. But it should not be misused to have excessive null check when just getting a interface pointer.
  • A heavily used core sub-sysem must be less tolerant to ‘unknown errors’ than one that is lightly exercised. So the core sub-system should have fewer or no paranoid null checks. This may seem very counter intuitive but the idea is that the core functionality should be stable, robust and reliable.

For the faint hearted who feel this approach as too radical, there is sort of a middle ground.

  • Don’t add any null checks in the initial implementation until the quality team finishes thorough testing. This way, any issues would get reported and fixed promptly.
  • Add any necessary defensive tactics at the very end of the release cycle. But if you are still seeing fatal errors at the end, unfortunately it is just poor quality software.

My recommendation is not to do defensive programming without a reason (which is usually rare). Keep in mind that every line of code is supposed to be hit at some point otherwise it is dead code. The bottom line… don’t fear the crash but leverage it.

Makefiles for Visual Studio Developers

If you develop software only on Windows using Visual studio, it’s a luxury. Enjoy it while it lasts. Sooner than later, you will come across Makefiles, maybe exploring some software on Linux or the misfortune of having a build system that uses make with Cygwin on Windows.

Now you figure out that Makefiles are text files and open it in an editor hoping to get some insight into its workings. But, what do you see? Lots of cryptic hard to understand syntax and expressions.

So, where do you start? Internet searches for make and Makefiles provide a lot of information but under the assumption that you come from a non-IDE Unix/Linux development environment. Pampered Visual Studio developers are never the target audience.

Here I will try to relate to the Visual Studio build system which will hopefully give an easier understanding of Makefiles. The goal is not provide yet another tutorial on makefiles (because there are plenty available on the internet) but to instill the concept by comparison.

See Makefiles and Visual Studio for a Visual Studio friendly introduction to the Make utility.

Cognitive Traps

A very interesting perspective into our typical thought process.

From “The Ascent of Money” by Niall Ferguson

Availability Bias, which causes us to base decision on information that is more readily available in our memories, rather than the data we really need.

Hindsight bias, which causes us to attach higher probabilities to events after they have happened (ex post) than we did before they happened (ex ante).

The problem of induction, which leads us to formulation general rules on the basis of insufficient information.

The fallacy of conjunction (or disjunction), which means we tend to overestimate the probability that seven event of the 90 percent probability will all occur, while underestimating the probability that at least one of =seven events of 10 percent probability will occur.

Confirmation bias, which inclines us to look for confirming evidence of an initial hypothesis, rather than falsifying evidence that would disprove it.

Contamination effects, whereby we allow irrelevant but promxiate information to influence a decision.

The affect heuristic, whereby preconceived value judgements interfere with our assessment of costs and benefits.

Scope neglect, which prevents us from proportionately adjusting what we should be willing to sacrifice to avoid harms of different orders of magnitude.

Overconfidence in calibration, which leads us to underestimate the confidence intervals within which our estimates will be robust (e.g.to conflate the ‘best case’ scenario with the ‘most probable’).

Bystander apathy, which inclines us to abdicate individual responsibility when in a crowd.

cmake-visualstudio

CMake for Visual Studio Developers

Visual Studio projects are not human readable as such with its excessive XML tags. The layout is more machine friendly. The UI (Project->Properties) to modify the project file is rather clunky too. Finding options in the various tabs and tree items can be a challenge. Very often, trying to figure out changes made as part of a commit in a source control tool is a nightmare. CMake on the other hand gives the flexibility to organize, and it being simple text, viewing commit differences is just like source code.

Compatibility between different versions of Visual Studio is quite messy too. Its high maintenance if you have to deal with multiple versions of Visual Studio. CMake provides a neutral interface independent of Visual Studio nuances between versions. It is not only useful to manage multiple versions of Visual Studio but is a good tool to create a cross platform build system.

However, for someone from a Windows only Visual Studio development environment (with not much experience with Linux and classic Makefile) CMake can be a little intimidating. The language is much more “friendly” to those familiar with Linux style scripting. The documentation though quite detailed, is difficult to parse until you know the basics and know what to look for. Being able to map the CMake commands to the Visual Studio IDE makes learning much easier.

Having spent some time to understand the fundamentals and the relation with Visual Studio, I’ve documented it with an example and will hopefully help other developers jump start using CMake.

See CMake and Visual Studio for more details.

Software Architecture – Art, Science and Engineering

Structural Architecture defines the outcome of a building to the world, so does Software Architecture to an application. It has a role from the very early stages of conception to the end of the development cycle.

It is like a painting that comes to life from a blank sheet of canvas. It begins with a concept on an empty page. Iterative changes and collaboration with other experts gives it an outline. Technological advances provides the opportunity for exploration while the same technology can limit the boundaries. The outline then evolves to well defined structure with tangible components. All this requires the skills of art, science and engineering.

Art is rather abstract and fluid. Such a mindset is critical in the early stages of defining a software architecture.

Science is often experimental and forward looking. These traits are essential to explore new frontiers in technology.

Engineering is a disciplined approach to adapting proven concepts. It is necessary to guarantee practical success.