<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Shaders - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Shaders - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 27 Jun 2026 11:24:05 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/shaders/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to use WebGL shaders in WebAssembly ]]>
                </title>
                <description>
                    <![CDATA[ By Dan Ruta WebAssembly is blazing fast for number crunching, game engines, and many other things, but nothing can quite compare to the extreme parallelization of shaders, running on the GPU. This is especially so if you’re looking to do some image p... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-webgl-shaders-in-webassembly-1e6c5effc813/</link>
                <guid isPermaLink="false">66c355f2e9895571912a0c99</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Shaders ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WebAssembly ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WebGL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 28 Dec 2017 18:26:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*wJXxr-2-89FQ2O1wVXBD8w.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dan Ruta</p>
<p>WebAssembly is blazing fast for <a target="_blank" href="https://ai.danruta.co.uk/webassembly">number crunching</a>, <a target="_blank" href="http://webassembly.org/demo/">game engines</a>, and many other things, but nothing can quite compare to the extreme parallelization of shaders, running on the GPU.</p>
<p>This is especially so if you’re looking to do some image processing. Usually, on the web, this is done through WebGL, but how would you access its APIs when using WebAssembly?</p>
<h3 id="heading-setting-up">Setting up</h3>
<p>We’ll very briefly go through setting up an example project, then we’ll look at how an image can be loaded as a texture. Then, in a separate context, we’ll apply an edge detection GLSL shader to the image.</p>
<p>All the code is in a repo <a target="_blank" href="https://github.com/DanRuta/webassembly-webgl-shaders">here</a>, if you’d prefer to jump straight to that. Note that you have to serve your files via a server for WebAssembly to work.</p>
<p>As a prerequisite, I’m going to assume you already have your WebAssembly project set up. If not, you can check out the article <a target="_blank" href="https://medium.com/statuscode/setting-up-the-ultimate-webassembly-c-workflow-6484efa3e162">here</a> on how to do it, or just fork the repo linked above.</p>
<p>For demoing the below code, I’m using a basic html file which serves only to load an image, get its imageData, and pass it to the WebAssembly code using <a target="_blank" href="https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97">the <em>ccallArrays</em> function</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*zJIvrPP5Q_-JqJSSAH738g.png" alt="Image" width="342" height="464" loading="lazy">
<em>The HTML file with the preview input image</em></p>
<p>As for the C++ code, there is an emscripten.cpp file which manages and routes method calls to context instances created in the Context.cpp file. The Context.cpp file is structured as follows:</p>
<h3 id="heading-compilation">Compilation</h3>
<p>WebGL is based on and follows the OpenGL ES (Embedded Systems) spec, which is a subset of OpenGL. When compiling, emscripten will map our code to the WebGL API.</p>
<p>There are a couple of different versions we can target. OpenGL ES 2 maps to WebGL 1, whereas OpenGL ES 3 maps to WebGL 2. By default you should target WebGL 2, as it comes with <a target="_blank" href="https://github.com/kripken/emscripten/blob/incoming/site/source/docs/optimizing/Optimizing-WebGL.rst#which-gl-mode-to-target">some free optimizations and improvements</a>.</p>
<p>To do this, we must add <a target="_blank" href="https://kripken.github.io/emscripten-site/docs/porting/multimedia_and_graphics/OpenGL-support.html#webgl-friendly-subset-of-opengl-es-2-0-3-0">the <code>USE_WEBGL2=1</code> flag</a> to the compilation.</p>
<p>If you are planning to use some OpenGL ES features not present in the WebGL spec, you can use t<a target="_blank" href="https://kripken.github.io/emscripten-site/docs/porting/multimedia_and_graphics/OpenGL-support.html#opengl-es-2-0-3-0-emulation">he <code>FULL_ES2=1</code> and/or <code>FULL_ES3=1</code> flags</a>.</p>
<p>To be able to handle large textures/images, we can also add <a target="_blank" href="https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html#memory-growth">the <code>ALLLOW_MEMORY_GROWTH=1</code> flag</a>. This removes the memory limit of the WebAssembly program, at the cost of some optimizations.</p>
<p>If you know ahead of time how much memory you’ll need, you can instead use the <code>TOTAL_MEMORY=X</code> flag, where X is the memory size.</p>
<p>So we’re going to end up with something like this:</p>
<p><code>emcc -o ./dist/appWASM.js ./dev/cpp/emscripten.cpp -O3 -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1 -std=c++1z</code></p>
<p>Finally, we need the following imports, in our code:</p>
<pre><code>#include &lt;emscripten.h&gt;#include &lt;string&gt;#include &lt;GLES2/gl2.h&gt;#include &lt;EGL/egl.h&gt;extern <span class="hljs-string">"C"</span> {       #include <span class="hljs-string">"html5.h"</span> <span class="hljs-comment">// emscripten module}</span>
</code></pre><h3 id="heading-implementation">Implementation</h3>
<p>If you have previous experience with WebGL or OpenGL, then this bit may seem familiar.</p>
<p>When writing OpenGL, the API will not work until you create a context. This is normally done using platform specific APIs. However, the web is not platform bound, and we can instead use an API integrated into OpenGL ES.</p>
<p>The majority of the legwork, however, can be more easily implemented using emscripten’s APIs in <a target="_blank" href="http://kripken.github.io/emscripten-site/docs/api_reference/html5.h">the html5.h file</a>. The functions we’re interested in are:</p>
<ul>
<li>_emscripten_webgl_create<em>context</em> — This will instantiate a context for the given canvas and attributes</li>
<li>_emscripten_webgl_destroy<em>context</em> — This is needed for cleaning up memory when destructing context instances</li>
<li>_emscripten_webgl_make_context<em>current</em> — This will assign and switch which context WebGL will render to</li>
</ul>
<h4 id="heading-create-the-context">Create the context</h4>
<p>To start implementing, you have to first create the canvas elements in your JavaScript code. Then, when using the <code>emscripten_webgl_create_context</code> function, you pass the id of the canvas as the first parameter, with any configurations as the second. The <code>emscripten_webgl_make_context_current</code> function is used to set the new context as the one currently in use.</p>
<p>Next, the vertex shader (to specify coordinates) and the fragment shader (to calculate the colour at each pixel) are both compiled, and the program is built.</p>
<p>Finally, the shaders are attached to the program, which is then linked, and validated.</p>
<p>Though that sounds like a lot, the code for this is as follows:</p>
<p>The shader compilation is done within the <code>CompileShader</code> helper function which performs the compilation, printing out any errors:</p>
<h4 id="heading-create-the-shader">Create the shader</h4>
<p>The shader code for this example is minimal, and it just maps each pixel to itself, to display the image as a texture:</p>
<p>You can access the canvas’ context in JavaScript in addition to the context in the C++ code, but it must be of the same type, ‘webgl2’. While defining multiple context types does nothing when just using JavaScript, if you do it before creating the webgl2 context in WebAssembly, it will throw an error when the code execution gets there.</p>
<h4 id="heading-loading-the-texture">Loading the texture</h4>
<p>The first thing to do when applying the shader is to call the <code>emscripten_webgl_make_context_current</code>function to make sure that we are still using the correct context, and <code>glUseProgram</code>to make sure we are using the correct program.</p>
<p>Next, we get the indices of the GLSL variables (similar to getting a pointer) via the<code>glGetAttribLocation</code>and <code>glGetUniformLocation</code> functions, so we can assign our own values to those locations. The function used to do that depends on the value type.</p>
<p>For example, an integer, such as the texture location needs <code>glUniform1i</code>, whereas a float would need <code>glUniform1f</code>. <a target="_blank" href="https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glUniform.xhtml">This is a good resource</a> for seeing which function you need to use.</p>
<p>Next, we get the texture object via <code>glGenTextures</code>, assign it as the active texture, and load the imageData buffer. The vertex and indices buffers are then bound, to set the boundaries of the texture to fill the canvas.</p>
<p>Finally, we clear the existing content, define our remaining variables with data, and draw to the canvas.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*lICDL2HxpbsJ2RjvjfzCbg.png" alt="Image" width="479" height="455" loading="lazy">
<em>The texture being loaded</em></p>
<h4 id="heading-detect-edges-using-a-shader">Detect edges using a shader</h4>
<p>To add another context, where the edge detection is done, we load a different fragment shader (which applies the <a target="_blank" href="https://en.wikipedia.org/wiki/Sobel_operator">Sobel</a> filter), and we bind the width and height as extra variables, in the code.</p>
<p>To pick between different fragment shaders, for the different contexts, we just add an if-else statement in the constructor, like so:</p>
<p>And to load the width and height variables, we add the following to the run function:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*kfvsG8s4vRLbxPxZot8isg.png" alt="Image" width="700" height="455" loading="lazy"></p>
<p>If you run into an error similar to<code>ERROR: GL_INVALID_OPERATION : glUniform1i: wrong uniform function for type</code>, then there’s a mismatched assignment function for the given variable.</p>
<p>One thing to look out for when sending the imageData, is to use the correct heap, unsigned integer (the Uint8Array typed array). You can learn more about those <a target="_blank" href="https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97">here</a>, but if you’re using the ccallArray function, set the ‘<em>heapIn</em>’ config to “<em>HEAPU8</em>”, as seen above.</p>
<p>If the type is not correct, the texture will still load, but you’re going to be seeing strange renderings, like these:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*0_EmLybuEaLJnnd_JfobFg.png" alt="Image" width="706" height="466" loading="lazy"></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>We’ve gone through a mini “Hello World!”-style project to show how to load textures and apply GLSL shaders to them in WebAssembly. The complete code is hosted on GitHub <a target="_blank" href="https://github.com/DanRuta/webassembly-webgl-shaders">here</a>, for further reference.</p>
<p>For a real project, you may want to add some additional error handling. I omitted it here, for clarity.</p>
<p>It may also be more efficient (in the above example) to share data such as the imageData texture between contexts. You can read more about this and more <a target="_blank" href="https://blog.gvnott.com/some-usefull-facts-about-multipul-opengl-contexts/">here</a>.</p>
<p>For some further reading, you can check out <a target="_blank" href="https://www.khronos.org/opengl/wiki/Common_Mistakes">this link</a> for common mistakes, or you can look through some demo projects in emscripten’s <a target="_blank" href="https://github.com/kripken/emscripten/tree/incoming/tests/glbook">glbook</a> folder, on GitHub.</p>
<p>To see WebGL being used in a WebAssembly project, you can check out the <a target="_blank" href="https://github.com/DanRuta/jsNet/tree/dev">dev branch on jsNet</a>, a web based deep learning framework, where I’ll be working on moving heavier computations onto shaders, over the next few weeks (support for WebGL compute shaders via OpenGL ES 3.1 <a target="_blank" href="https://www.khronos.org/webgl/public-mailing-list/public_webgl/1706/msg00034.php">can’t come soon enough</a> ? ).</p>
<p><strong>Update</strong></p>
<p>To see what GPU compute using shaders would look like in WebAssembly, you can check out <a target="_blank" href="https://github.com/DanRuta/GPGPU">the repo for GPGPU</a>, a small library I’m working on, with both JavaScript and WebAssembly versions.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
