1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="utf-8" /> 6 <link rel="icon" href="./favicon-32x32.png" type="image/png" /> 7 <link rel="icon" href="./favicon.svg" type="image/svg+xml" /> 8 <link rel="stylesheet" href="./katex.min.css" /> 9 <meta name="viewport" content="width=device-width" /> 10 <link href="./_app/immutable/entry/start.CE_5GFeA.js" rel="modulepreload"> 11 <link href="./_app/immutable/chunks/7auEqc31.js" rel="modulepreload"> 12 <link href="./_app/immutable/chunks/CyFDEGUj.js" rel="modulepreload"> 13 <link href="./_app/immutable/chunks/OA8UcISh.js" rel="modulepreload"> 14 <link href="./_app/immutable/chunks/CyvgFMmV.js" rel="modulepreload"> 15 <link href="./_app/immutable/entry/app.BlQISDEY.js" rel="modulepreload"> 16 <link href="./_app/immutable/chunks/FEW6feEw.js" rel="modulepreload"> 17 <link href="./_app/immutable/chunks/DvWOzhaq.js" rel="modulepreload"> 18 <link href="./_app/immutable/chunks/BVvrMIpa.js" rel="modulepreload"> 19 <link href="./_app/immutable/chunks/CeZsFwtm.js" rel="modulepreload"> 20 <link href="./_app/immutable/nodes/0.BBOCnqJl.js" rel="modulepreload"> 21 <link href="./_app/immutable/chunks/XUwVtqsD.js" rel="modulepreload"> 22 <link href="./_app/immutable/chunks/BIbQPtZm.js" rel="modulepreload"> 23 <link href="./_app/immutable/chunks/Kd0MEMOz.js" rel="modulepreload"> 24 <link href="./_app/immutable/nodes/3.CoB912yb.js" rel="modulepreload"> 25 <link href="./_app/immutable/chunks/CVKnVB-G.js" rel="modulepreload"> 26 <!--a30p0f--><!---->
26<script>!function(){try {var d=document.documentElement;var e=localStorage.getItem('theme');if("system"===e||(!e&&true)){var t="(prefers-color-scheme: dark)",m=window.matchMedia(t);if(m.media!==t||m.matches){d.setAttribute('data-theme', 'dark');document.documentElement.style.setProperty('color-scheme', 'dark')}else{d.setAttribute('data-theme', 'light');document.documentElement.style.setProperty('color-scheme', 'light')}}else if(e){ d.setAttribute('data-theme', e);document.documentElement.style.setProperty('color-scheme', e)}}catch(e){}}()</script>
26<!----><!----><!--38sjwj--><!--[-1--><!--]--> <meta property="og:site_name" content="Antonin Stefanutti"/> <meta property="og:title" content="Running OpenGL Shaders on the Raspberry Pi"/> <!--[-1--><!--]--><!----><title>Running OpenGL Shaders on the Raspberry Pi</title> 27 <link href="./_app/immutable/assets/0.ysVI55N1.css" rel="stylesheet"> 28 <link href="./_app/immutable/assets/ArticleMeta.Cs5SM1zT.css" rel="stylesheet"> 29 <link href="./_app/immutable/assets/Image.C0uFwRM4.css" rel="stylesheet"> 30</head> 31 32<body data-sveltekit-preload-data="hover"> 33 <div style="display: contents"><!--[--><!--[0--><!--[--><!----> <header class="navbar"><span><a href="/"><!--[-1--><span class="title small">ttt.io</span><!--]--></a> <span class="icons"><a class="icon" href="https://github.com/astefanutti"><!----><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg><!----></a> <a class="icon" href="https://fosstodon.org/@ttt"><!----><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg><!----></a> <a class="icon" href="https://fr.linkedin.com/in/astefanutti"><!----><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>LinkedIn</title><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg><!----></a></span></span> <fieldset class="toggle-group svelte-12qhfyh"><label class="svelte-12qhfyh"><input type="radio" name="color-scheme" id="color-scheme-light" value="light" data-sr="" class="svelte-12qhfyh"/> <!----><svg role="img" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"> 34 <path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"/> 35 <path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"/> 36 <path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"/> 37 <path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"/> 38 <path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"/> 39 <path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"/> 40 <path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"/> 41 <path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"/> 42 <path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"/> 43 </svg><!----></label> <label class="svelte-12qhfyh"><input type="radio" name="color-scheme" value="system" data-sr="" class="svelte-12qhfyh"/> <!----><svg role="img" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg"> 44 <path d="M27,14h-0.172c-0.478,0-0.904-0.337-0.98-0.809c-0.037-0.229-0.081-0.456-0.132-0.68c-0.106-0.464,0.158-0.933,0.597-1.115l0.156-0.065c0.51-0.211,0.753-0.796,0.541-1.307v0c-0.211-0.51-0.796-0.753-1.307-0.541l-0.16,0.066c-0.441,0.183-0.961,0.035-1.214-0.37c-0.122-0.196-0.25-0.388-0.384-0.576c-0.277-0.388-0.213-0.924,0.124-1.261l0.122-0.122c0.391-0.391,0.391-1.024,0-1.414l0,0c-0.391-0.391-1.024-0.391-1.414,0L22.656,5.93c-0.337,0.337-0.873,0.401-1.261,0.124c-0.188-0.134-0.38-0.262-0.576-0.384c-0.405-0.252-0.553
44-0.773-0.37-1.214l0.066-0.16c0.211-0.51-0.031-1.095-0.541-1.307c-0.51-0.211-1.095,0.031-1.307,0.541l-0.065,0.156c-0.182,0.439-0.651,0.703-1.115,0.597c-0.224-0.051-0.451-0.095-0.68-0.132C16.337,4.076,16,3.65,16,3.172V3c0-0.552-0.448-1-1-1s-1,0.448-1,1v0.172c0,0.478-0.337,0.904-0.809,0.98c-0.229,0.037-0.456,0.081-0.68,0.132c-0.464,0.106-0.933-0.158-1.115-0.597l-0.065-0.156c-0.211-0.51-0.796-0.753-1.307-0.541c-0.51,0.211-0.753,0.796-0.541,1.307l0.066,0.16C9.733,4.897,9.586,5.418,9.18,5.67C8.984,5.792,8.792,5.92,8.605,6.053C8.217,6.33,7.681,6.267,7.344,5.93L7.222,5.808c-0.391-0.391-1.024-0.391-1.414,0l0,0c-0.39,0.391-0.39,1.024,0,1.414L5.93,7.344C6.267,7.681,6.33,8.216,6.053,8.605C5.92,8.792,5.792,8.984,5.67,9.18C5.418,9.586,4.897,9.733,4.456,9.55l-0.16-0.066c-0.51-0.211-1.095,0.031-1.307,0.541v0c-0.211,0.51,0.031,1.095,0.541,1.307l0.156,0.065c0.439,0.182,0.703,0.651,0.597,1.115c-0.051,0.224-0.095,0.451-0.132,0.68C4.076,13.663,3.65,14,3.172,14H3c-0.552,0-1,0.448-1,1v0c0,0.552,0.448,1,1,1h0.172c0.478,0,0.904,0.337,0.98,0.809c0.037,0.229,0.081,0.456,0.132,0.68c0.106,0.464-0.158,0.933-0.597,1.115l-0.156,0.065c-0.51,0.211-0.753,0.796-0.541,1.307v0c0.211,0.51,0.796,0.753,1.307,0.541l0.16-0.066c0.441-0.183,0.961-0.035,1.214,0.37c0.122,0.196,0.25,0.388,0.384,0.576c0.277,0.388,0.213,0.924-0.124,1.261l-0.122,0.122c-0.391,0.391-0.391,1.024,0,1.414s1.024,0.391,1.414,0l0.122-0.122c0.337-0.337,0.873-0.401,1.261-0.124c0.188,0.134,0.38,0.262,0.576,0.384c0.405,0.252,0.553,0.773,0.37,1.214l-0.066,0.16c-0.211,0.51,0.031,1.095,0.541,1.307c0.51,0.211,1.095-0.031,1.307-0.541l0.065-0.156c0.182-0.439,0.651-0.703,1.115-0.597c0.224,0.051,0.451,0.095,0.68,0.132C13.663,25.924,14,26.35,14,26.828V27c0,0.552,0.448,1,1,1s1-0.448,1-1v-0.172c0-0.478,0.337-0.904,0.809-0.98c0.229-0.037,0.456-0.081,0.68-0.132c0.464-0.106,0.933,0.158,1.115,0.597l0.065,0.156c0.211,0.51,0.796,0.753,1.307,0.541c0.51-0.211,0.753-0.796,0.541-1.307l-0.066-0.16c-0.183-0.441-0.035-0.961,0.37-1.214c0.196-0.122,0.388-0.25,0.576-0.384c0.388-0.277,0.924-0.213,1.261,0.124l0.122,0.122c0.391,0.391,1.024,0.391,1.414,0s0.391-1.024,0-1.414l-0.122-0.122c-0.337-0.337-0.401-0.873-0.124-1.261c0.134-0.188,0.262-0.38,0.384-0.576c0.252-0.405,0.773-0.553,1.214-0.37l0.16,0.066c0.51,0.211,1.095-0.031,1.307-0.541v0c0.211-0.51-0.031-1.095-0.541-1.307l-0.156-0.065c-0.439-0.182-0.703-0.651-0.597-1.115c0.051-0.224,0.095-0.451,0.132-0.68C25.924,16.337,26.35,16,26.828,16H27c0.552,0,1-0.448,1-1v0C28,14.448,27.552,14,27,14z M15,23c-4.418,0-8-3.582-8-8s3.582-8,8-8s8,3.582,8,8S19.418,23,15,23z"/> 45 < rect x="15" y="14" width="9" height="2"/> 46 <rect x="8.25" y="10.103" transform="matrix(0.5 0.866 -0.866 0.5 15.9904 -5.4904)" width="9" height="2"/> 47 <rect x="8.125" y="17.681" transform="matrix(-0.5 0.866 -0.866 -0.5 35.4904 16.8708)" width="9.5" height="2"/> 48 <circle cx="15" cy="15" r="2"/> 49 </svg><!----></label> <label class="svelte-12qhfyh"><input type="radio" name="color-scheme" id="color-scheme-dark" value="dark" data-sr="" class="svelte-12qhfyh"/> <!----><svg role="img" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"> 50 <path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"/> 51 </svg><!----></label></fieldset></header> <!--[--><!----> <article><!--[-1--><h1 class="heading svelte-zkkrg4 large">Running OpenGL Shaders on the Raspberry Pi</h1><!--]--><!----> <p class="svelte-1ewd4uj"><!--[-1--><!--]--> <span class="date svelte-1ewd4uj">Mon Mar 08 2021</span></p><!----> <!--[--><figure class="fullwidth"><picture><!--[--><source srcset="/_app/immutable/assets/torus.BlyLgeT1.avif 600w, /_app/immutable/assets/torus.CnH_NoUn.avif 1000w, /_app/immutable/assets/torus.BjZTUTjF.avif 1400w" type="image/avif" sizes="100vw"/><source srcset="/_app/immutable/assets/torus.1Wl_jQlJ.webp 600w, /_app/immutable/assets/torus.C-P9bdv-.webp 1000w, /_app/immutable/assets/torus.Cj7Mt-SK.webp 1400w" type="image/webp" sizes="100vw"/><source srcset="/_app/immutable/assets/torus.CixJS_rj.jpeg 600w, /_app/immutable/assets/torus.B-T0WtkE.jpeg 1000w, /_app/immutable/assets/torus.NNVrZmhY.jpeg 1400w" type="image/jpeg" sizes="100vw"/><!--]--> <img src="/_app/immutable/assets/torus.NNVrZmhY.jpeg" width="1400" height="1050" alt="A shader running on the Raspberry Pi" loading="lazy" class="svelte-3ned59"/></picture><!----> <figcaption>A <a href="https://www.shadertoy.com/view/MsX3Wj">shader</a> from <a href="https://www.shadertoy.com">Shadertoy</a> running fullscreen on the Rapsberry Pi 52 official touchscreen</figcaption></figure> <p><span class="note marginnote"><strong>TL;DR:</strong> If you just want to try it, you can head to the <strong><a href="https://github.com/astefanutti/shaderbang" rel="nofollow">project repository</a>.</strong></span><span class="note sidenote"><span class="sidenote-number">1</span><em>âHow can it be that mathematics, being after all a product of human thought which is independent of experience, is so admirably appropriate to the objects of reality?â</em> â Albert Einstein.</span> As far as I can remember, Iâve always felt attracted by computer graphics. 53I guess I approach the field from the angle of my Mathematics background, as I see it as a universal language between machines, arts, and possibly, nature<span class="sidenote-number">1</span>.</p> <p><span class="note sidenote"><span class="sidenote-number">2</span>Shadertoy has been created by <em>Iñigo Quilez</em>, that publishes very interesting articles, tutorials, and other awesome resources at <a href="https://www.iquilezles.org" rel="nofollow">iquilezles.org</a>.</span>As a projection of that language, I find the <a href="https://en.wikipedia.org/wiki/OpenGL_Shading_Language" rel="nofollow">OpenGL Shading Language</a> an interesting case, at the intersection of computing and visual arts, thatâs concise and expressive enough to demonstrate human ingenuity and creativity. 54You can find me browsing for hours on <a href="https://www.shadertoy.com/" rel="nofollow">shadertoy.com</a><span class="sidenote-number">2</span>
54, mesmerized by the visuals.</p> <p><span class="note sidenote"><span class="sidenote-number">3</span>As crazy as it may sound, itâs possible to develop games in GLSL (click on the images to try it):<br/><a href="https://www.shadertoy.com/view/MddGzf" rel="nofollow"><picture><!--[--><source srcset="/_app/immutable/assets/arkanoid.DIR4QIxc.avif 400w, /_app/immutable/assets/arkanoid.DQdOKyQ3.avif 800w" type="image/avif" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><source srcset="/_app/immutable/assets/arkanoid.BT9xXsS_.webp 400w, /_app/immutable/assets/arkanoid.CaCbj1_0.webp 800w" type="image/webp" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><source srcset="/_app/immutable/assets/arkanoid.C2ogAoO0.png 400w, /_app/immutable/assets/arkanoid.CGGLE9Bb.png 800w" type="image/png" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><!--]--> <img src="/_app/immutable/assets/arkanoid.CGGLE9Bb.png" width="800" height="450" alt="Arkanoid" loading="lazy" class="svelte-3ned59"/></picture><!----></a><br/><a href="https://www.shadertoy.com/view/Ms3XWN" rel="nofollow"><picture><!--[--><source srcset="/_app/immutable/assets/pacman.0Vhzw8ZI.avif 400w, /_app/immutable/assets/pacman.CN-QzNLw.avif 800w" type="image/avif" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400pxâ"/><source srcset="/_app/immutable/assets/pacman.DVYT2GLV.webp 400w, /_app/immutable/assets/pacman.CZNo7N6Z.webp 800w" type="image/webp" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400pxâ"/><source srcset="/_app/immutable/assets/pacman.DpyUnhx7.png 400w, /_app/immutable/assets/pacman.Bt_YWxhm.png 800w" type="image/png" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400pxâ"/><!--]--> <img src="/_app/immutable/assets/pacman.Bt_YWxhm.png" width="800" height="450" alt="âPacmanâ" loading="lazy" class="svelte-3ned59"/></picture><!----></a><br/><a href="https://www.shadertoy.com/view/wllSRs" rel="nofollow"><picture><!--[--><source srcset="/_app/immutable/assets/space_invaders.C_BTcXyx.avif 400w, /_app/immutable/assets/space_invaders.C8BLujh2.avif 800w" type="image/avif" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><source srcset="/_app/immutable/assets/space_invaders.CIENde3N.webp 400w, /_app/immutable/assets/space_invaders.CzdFh2n0.webp 800w" type="image/webp" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><source srcset="/_app/immutable/assets/space_invaders.CSTIkmYL.png 400w, /_app/immutable/assets/space_invaders.BELMi2xv.png 800w" type="image/png" sizes="(max-width: calc(1.4 * 800px)) 25vw, 400px"/><!--]--> <img src="/_app/immutable/assets/space_invaders.BELMi2xv.png" width="800" height="450" alt="Space Invaders" loading="lazy" class="svelte-3ned59"/></picture><!----></a></span>Since I built my <a href="/anatomy-of-my-kubernetes-cluster">Kubernetes cluster with Rapsberry Pi</a> a year ago, Iâve kept somewhere in a corner of my head, the idea I could use the touchscreen monitor to play with OpenGL, making the coolest cluster ever, to begin with ð, and turning it eventually, into a small gaming device <span style="white-space: nowrap">ð¹ð¾</span><span class="sidenote-number">3</span>.</p> <p>So Iâve accepted the mission to run shaders from <em>Shadertoy</em>, on the Raspberry Pi!</p> <h2 id="the-linux-graphics-stack"><a class="anchor" aria-hidden="true" tabindex="-1" href="#the-linux-graphics-stack">
54<script context="module"> 55 export const metadata = {"title":"Running OpenGL Shaders on the Raspberry Pi","date":"2021-03-08T00:00:00.000Z","published":true,"image":"./torus.jpg","slug":"glsl-raspberry-pi","tags":["OpenGL","Raspberry Pi"]}; 56 const { title, date, published, image, slug, tags } = metadata; 57</script>
57 <svg viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a>The Linux Graphics Stack</h2> <p>I use a Raspberry Pi 4 as my clusterâs <em>main</em> node, thatâs connected to the touchscreen monitor. 58It runs the Lite version of <a href="https://www.raspberrypi.org/software/operating-systems" rel="nofollow">Raspberry Pi OS</a>, which means there is no windowing system available, like X11.</p> <p>I also have some Raspberry Pi 3, so I wanted to have a solution that would work on these as well, and possibly on any other Linux device with GPU hardware.</p> <p>The following diagram gives a good understanding of the Linux graphics stack:</p> <figure class="liquid"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 720"><!----><defs><marker id="g" orient="auto" overflow="visible" refX="0" refY="0"><path fill="green" fill-rule="evenodd" stroke="green" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="h" orient="auto" overflow="visible" refX="0" refY="0"><path fill="green" fill-rule="evenodd" stroke="green" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="o" orient="auto" overflow="visible" refX="0" refY="0"><path fill="navy" fill-rule="evenodd" stroke="navy" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="p" orient="auto" overflow="visible" refX="0" refY="0"><path fill="navy" fill-rule="evenodd" stroke="navy" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="m" orient="auto" overflow="visible" refX="0" refY="0"><path fill="navy" fill-rule="evenodd" stroke="navy" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="n" orient="auto" overflow="visible" refX="0" refY="0"><path fill="navy" fill-rule="evenodd" stroke="navy" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="q" orient="auto" overflow="visible" refX="0" refY="0"><path fill="green" fill-rule="evenodd" stroke="green" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="r" orient="auto" overflow="visible" refX="0" refY="0"><path fill="green" fill-rule="evenodd" stroke="green" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="e" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="f" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="s" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="t" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="d" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="c" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="v" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="u" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="b" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.
58154 0 1.73-1v2z"/></marker><marker id="a" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="j" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="i" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker><marker id="l" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m-1.154 0 1.73-1v2z"/></marker><marker id="k" orient="auto" overflow="visible" refX="0" refY="0"><path fill="#0197fd" fill-rule="evenodd" stroke="#0197fd" stroke-width=".2pt" d="m1.154 0-1.73 1v-2z"/></marker></defs><g transform="translate(254.908 370.066)"><rect width="740" height="75" x="285.092" y="-370.066" fill="#e9b96e" rx="18.031" ry="18.031"/><rect width="1280" height="70" x="-254.908" y="219.934" fill="#c1504f" rx="18.031" ry="18.031"/><rect width="660" height="150" x="180.092" y="-270.066" fill="#8e8ed7" rx="18.031" ry="18.031"/><rect width="290" height="140" x="545.092" y="-265.066" fill="#504fc1" rx="18.031" ry="18.031"/><rect width="280" height="80" x="550.092" y="-210.066" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="1280" height="25" x="-254.908" y="299.934" fill="#333" rx="0" ry="0"/><rect width="150" height="50" x="50.092" y="229.934" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="230" height="90" x="10.092" y="99.934" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="280" height="25" x="290.092" y="-325.066" fill="#504fc1" rx="10" ry="10"/><rect width="530" height="50" x="-254.908" y="-370.066" fill="#e9b96e" rx="18.031" ry="18.031"/><rect width="530" height="165" x="-254.908" y="-90.066" fill="#8ed78e" rx="18.031" ry="18.031"/><rect width="250" height="105" x="20.092" y="-85.066" fill="green" rx="18.031" ry="18.031"/><rect width="240" height="155" x="-229.908" y="-85.066" fill="green" rx="18.031" ry="18.031"/><rect width="130" height="40" x="-169.908" y="234.934" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="1280" height="25" x="-254.908" y="324.934" fill="#0197fd" rx="0" ry="0"/><rect width="280" height="25" x="740.092" y="-325.066" fill="#504fc1" rx="10" ry="10"/><rect width="130" height="20" x="881.663" y="327.434" fill="#0ff" rx="6.25" ry="6.25"/><rect width="280" height="37" x="550.092" y="-247.066" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="250" height="50" x="20.092" y="19.934" fill="green" rx="18.031" ry="18.031"/><rect width="150" height="50" x="476.791" y="229.826" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="280" height="140" x="185.092" y="-265.066" fill="#504fc1" rx="18.031" ry="18.031"/><rect width="150" height="100" x="310.092" y="-230.066" fill="#0197fd" rx="18.031" ry="18.031"/><rect width="160" height="140" x="865.092" y="-265.066" fill="#8e8ed7" rx="18.031" ry="18.031"/></g><g transform="translate(255 210)"><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#a)" marker-start="url(#b)" d="M125 239.931v15.137"/><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#c)" marker-start="url(#d)" d="M125 354.536v29.963"/><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#f)" marker-start="url(#e)" d="M544.054.019h-23.75v312.153H245.355"/><path fill="none" stroke="green" stroke-width="5" marker-end="url(#h)" marker-start="url(#g)" d="M10-153.8V63.431"/><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#i)" marker-start="url(#j)" d="M-105 227.477v158.381"/><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#k)" marker-start="url(#l)" d="M-105 440.19v39.286"/><path fill="none" stroke="navy" stroke-width="5" marker-end="url(#n)" marker-start="url(#m)" d="M415-135.985v21.97"/><path fill="none" stroke="navy" stroke-width="5" marker-end="url(#p)" marker-start="url(#o)" d="M793.582-133.605v21.97"/><path fill="none" stroke="green" stroke-width="5" marker-end="url(#r)" marker-start="url(#q)" d="M385.
58032-131.558v12.348H161.255V63.47"/><path fill="none" stroke="#0197fd" stroke-width="5" marker-end="url(#t)" marker-start="url(#s)" d="M551.699 46.395v337.047"/><path id="w" fill="none" stroke="#0197fd" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="5" marker-end="url(#u)" marker-start="url(#v)" d="M125 445.292v32.991" display="inline"/><path fill="none" stroke="green" stroke-width="5" marker-end="url(#r)" marker-start="url(#q)" d="M366.875 41.395v12.098H186.848v10.5"/><path fill="none" stroke="navy" stroke-width="5" marker-end="url(#p)" marker-start="url(#o)" d="M858.183-38.504h-16.366"/><use xlink:href="#w" width="1280" height="720" transform="translate(426.699 .994)"/></g><text x="27.248" y="-72.382" fill="#fff" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="27.248" y="-72.382" font-size="13"><tspan font-weight="700">Mesa</tspan>:APIs+DRI/Gallium3D driver</tspan><tspan x="27.248" y="-54.882" font-size="14" font-weight="700">libGL-mesa-swx11 <tspan font-weight="400">(libGL)</tspan></tspan><tspan x="27.248" y="-37.382" font-size="14" font-weight="700">libGL-mesa-glx</tspan><tspan x="27.248" y="-19.882" font-size="14" font-weight="700">libOpenVG-mesa</tspan><tspan x="27.248" y="-2.382" font-size="14" font-weight="700">libGLES-mesa</tspan><tspan x="27.248" y="15.118" font-size="14" font-weight="700">libEGL-mesa</tspan><tspan x="27.248" y="32.618" font-size="14" font-weight="700">libEGL-mesa-drivers <tspan font-weight="400">(Wayland)</tspan></tspan><tspan x="27.248" y="50.118" font-size="14" font-weight="700">libGBM</tspan><tspan x="27.248" y="67.618" font-size="14" font-weight="700">libGL-mesa-DRI <tspan font-weight="400">(Modules)</tspan></tspan></text><text x="620.536" y="-250.266" font-size="16" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="620.536" y="-250.266">X-server <tspan font-weight="600">(</tspan><tspan>X.Org)</tspan></tspan></text><text x="601.856" y="-191.913" fill="#fff" font-size="14" font-weight="400" letter-spacing="0" style="text-align:start;line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="601.856" y="-191.913" style="text-align:start">X.Org Server display driver</tspan><tspan x="601.856" y="-173.907" font-weight="700" style="text-align:start">xserver-xorg-video-nouveau</tspan><tspan x="601.856" y="-156.407" font-weight="700" style="text-align:start">xserver-xorg-video-nvidia</tspan><tspan x="601.856" y="-138.907" font-weight="700" style="text-align:start">xserver-xorg-video-radeon</tspan></text><text x="109.561" y="254.736" fill="#fff" font-size="14" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="109.561" y="254.736">DRM</tspan></text><text x="821.302" y="263.136" fill="#fff" font-size="22" font-weight="700" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="821.302" y="263.136">Linux kernel</tspan></text><text x="53.376" y="120.866" fill="#fff" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="53.376" y="120.866" font-weight="700" style="text-align:start">libDRM-intel</tspan><tspan x="53.376" y="140.866" font-weight="700" style="text-align:start">libDRM-radeon</tspan><tspan x="53.376" y="160.866" font-weight="700" style="text-align:start">libDRM-nouveau</tspan><tspan x="53.376" y="180.866" font-weight="700" style="text-align:start">libDRM-freedreno</tspan></text><text x="275.561" y="84.085" class="themed" font-size="14" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="275.561" y="84.085">hardware specific</tspan><tspan x="275.561" y="101.585">Userspace interface to</tspan><tspan x="275.561" y="119.085">hardware specific</tspan><tspan x="275.561" y="136.585">direct rendering manager</tspan></text><text x="85.209" y="317.33" fill="#fff" font-size="20" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="85.209" y="317.33" font-size="18">CPU & registers & L1 & L2 & L3 & L4 & main memory</tspan></text><text x="128.232" y="342.33" fill="#fff" font-size="20" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="128.232" y="342.33" font-size="18">GPU & registers & L1 & L2 (& graphic memory)</tspan></text><text x="655.565" y="-338.114" font-size="22" font-weight="700" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="655.565" y="-338.114">Applications</tspan><tspan x="655.565" y="-310.614">Toolkits</tspan></text><text x="-176.86" y="36.25" fill="#fff" font-size="16" font-weight="700" letter-spacing="0" style="line-height:125%" transform="rotate(-90 312.487 57.579)" word-spacing="0"><tspan x="-176.86" y="36.25" style="text-align:start">libDRM</tspan></text><text x="-92.018" y="-339.082" font-size="22" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="-92.018" y="-339.082">3D-game engine</tspan></text><text x="169.737" y="571.479" fill="#fff" font-size="16" font-weight="700" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="rotate(-90 312.487 57.579)" word-spacing="0"><tspan x="169.737" y="571.479" style="text-align:center">DDX-</tspan><tspan x="169.737" y="591.479" style="text-align:center">driver</tspan></text><text x="825.292" y="-307.524" fill="#fff" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="825.292" y="-307.524" font-size="14" font-weight="700">libX / libXCB</tspan></text><text x="-217.554" y="-21.17" fill="#fff" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="-217.554" y="-21.17" font-size="13">Proprietary OpenGL 4.2 driver</tspan><tspan x="-215.554" y="-3.67" font-size="14" font-weight="700">libGL-nvidia-glx</tspan><tspan x="-215.554" y="13.83" font-size="14" font-weight="700">libGL-fglrx-glx</tspan></text><text x="-15.782" y="-236.764" fill="green" font-size="16" font-weight="700" letter-spacing="0" style="line-height:125%" transform="rotate(-90 312.487 57.579)" word-spacing="0"><tspan x="-15.782" y="-236.764" style="text-align:start">"libGL"</tspan></text><text x="-9.819" y="-235.652" fill="green" font-size="16" font-weight="400" letter-spacing="0" style="text-align:end;line-height:125%" text-anchor="end" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="-4.725" y="-235.652">Rendering APIs: </tspan><tspan x="-9.819" y="-215.652"><tspan font-weight="700" style="text-align:end">OpenGL</tspan></tspan><tspan x="-9.819" y="-195.652"><tspan font-weight="700" style="text-align:end">OpenGL|ES</tspan></tspan><tspan x="-9.819" y="-175.652"><tspan font-weight="700" style="text-align:end">OpenVG</tspan></tspan></text><text x="808.684" y="-279.241" fill="navy" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="808.684" y="-279.241"><tspan font-weight="700">X 11R7.8</tspan></tspan></text><text x="-122.428" y="260.154" fill="#fff" font-size="14" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="-122.428" y="260.154">blob</tspan></text><text x="503.676" y="-201.222" fill="#fff" font-size="16" font-weight="700" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="503.676" y="-201.222" style="text-align:center">Display</tspan><tspan x="503.676" y="-181.222" style="text-align:center">server</tspan></text><text x="358.742" y="-308.324" fill="#fff" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="358.742" y="-308.324" font-size="14" font-weight="700">libwayland-client</tspan></text><text x="435.118" y="-278.714" fill="navy" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="435.118" y="-278.714"><tspan font-weight="700">Wayland 1.5</tspan></tspan></text><text x="898.837" y="342.654" font-size="16" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="898.837" y="342.654" font-size="14">framebuffer</tspan></text><text x="689.436" y="-222.601" fill="#fff" font-size="16" font-weight="700" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="689.436" y="-222.601" style="text-align:center">DIX driver</tspan></text><text x="53.503" y="270.901" font-size="22" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="53.503" y="270.901" fill="#fff" font-size="14">hardware-specific</tspan></text><path fill="none" stroke="#000" d="M.5 577.5h1279"/><text x="-255.957" y="-382.556" font-size="12" font-weight="400" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="-255.957" y="-382.556">by Shmuel Csaba Otto Traian; CC-BY-SA 4.0 intl; created 2013-08-24; last updated 2014-03-25</tspan></text><text x="538.587" y="251.409" fill="#fff" font-size="14" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="538.587" y="251.409">KMS</tspan></text><text x="552.125" y="270.839" font-size="22" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="552.125" y="270.839" fill="#fff" font-size="12" font-weight="400" style="text-align:center" text-anchor="middle">Kernel Mode Setting</tspan></text><text x="384.885" y="-205.651" fill="#ccc" font-size="16" font-weight="400" letter-spacing="0" style="text-align:center;line-height:125%" text-anchor="middle" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="384.885" y="-205.651" style="text-align:center">Wayland</tspan><tspan x="384.885" y="-185.651" style="text-align:center">obsoletes</tspan><tspan x="384.885" y="-165.651" style="text-align:center">2D drivers in</tspan><tspan x="384.885" y="-145.651" style="text-align:center">display server</tspan></text><text x="196.344" y="-250.519" font-size="16" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="196.344" y="-250.519">Wayland compositor</tspan></text><text x="150.628" y="-215.152" fill="green" font-size="16" font-weight="400" letter-spacing="0" style="text-align:end;line-height:125%" text-anchor="end" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="155.722" y="-215.152">API: </tspan><tspan x="150.628" y="-195.152" font-weight="700" style="text-align:end">EGL</tspan></text><text x="329.376" y="-85.119" fill="green" font-size="16" font-weight="400" letter-spacing="0" style="text-align:end;line-height:125%" text-anchor="end" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="334.469" y="-85.119">API: </tspan><tspan x="329.376" y="-65.119" font-weight="700" style="text-align:end">EGL</tspan></text><text x="875.229" y="-243.73" font-size="16" font-weight="700" letter-spacing="0" style="line-height:125%" transform="translate(254.908 370.066)" word-spacing="0"><tspan x="875.229" y="-243.73" font-weight="600">Window manager</tspan></text><text x="195.519" y="-214.337" font-size="16" font-weight="400" letter-spacing="0" style="text-align:start;line-height:125%" transform="translate(254.908 370.066)" word-spacing="-7.92"><tspan x="195.519" y="-214.337">KWin</tspan><tspan x="195.519" y="-194.337">Mutter</tspan><tspan x="195.519" y="-174.337">Weston</tspan><tspan x="195.519" y="-154.337">Enlightment</tspan></text><text x="895.201" y="-219.286" font-size="16" font-weight="400" letter-spacing="0" style="text-align:start;line-height:125%" transform="translate(254.908 370.066)" word-spacing="-7.92"><tspan x="895.201" y="-219.286">KWin</tspan><tspan x="895.201" y="-199.286">Compiz</tspan><tspan x="895.201" y="-179.286">OpenBox</tspan><tspan x="895.201" y="-159.286">Metacity</tspan><tspan x="895.201" y="-139.286">Mutter</tspan></text><!----></svg><!----> <figcaption>Illustration of the Linux graphics stack<br/><small>(by Shmuel Csaba Otto Traian, CC-BY-SA 4.0)</small></figcaption></figure> <p>With the requirement to run without any windowing system, like X or Wayland, this implies relying either on:</p> <ul><li>Proprietary device drivers (the <a href="https://en.wikipedia.org/wiki/Pro
58prietary_device_driver" rel="nofollow">binary blob</a> at the bottom,left-hand side of the illustration),</li> <li><span class="note sidenote"><span class="sidenote-number">4</span>The Mesa 3D Graphics Library, is an open source software implementation of the OpenGL specifications. The project also hosts the development of open-source device drivers for graphic chipsets.</span>Or, Mesa<span class="sidenote-number">4</span> open-source device drivers, using the <a href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager" rel="nofollow">DRM</a>/<a href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager#Kernel_Mode_Setting" rel="nofollow">KMS</a> Linux kernel sub-system, to implement <a href="https://en.wikipedia.org/wiki/Mode-setting" rel="nofollow">mode-setting</a> and <a href="https://en.wikipedia.org/wiki/Multiple_buffering#Page_flipping" rel="nofollow">page-flipping</a> operations.</li></ul> <p>While the latter option requires more development work, it promises to work across the <a href="https://docs.mesa3d.org/systems.html" rel="nofollow">range of GPUs</a> that have a Mesa driver available. 59It also brings the <em>a-priori</em> benefits of the open-source model, with community and freely accessible documentation.</p> <p>Now that the Linux stack is clearer, letâs continue on that mission, and find out what drivers exist for the Raspberry Pi â¦</p> <h2 id="the-raspberry-pi"><a class="anchor" aria-hidden="true" tabindex="-1" href="#the-raspberry-pi">
59<script context="module"> 60 export const metadata = {"title":"Running OpenGL Shaders on the Raspberry Pi","date":"2021-03-08T00:00:00.000Z","published":true,"image":"./torus.jpg","slug":"glsl-raspberry-pi","tags":["OpenGL","Raspberry Pi"]}; 61 const { title, date, published, image, slug, tags } = metadata; 62</script>
62 <svg viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a>The Raspberry Pi</h2> <p>The Raspberry Pi 3 Broadcom BCM2837 SoC includes the VideoCore IV GPU, which could initially be used with the corresponding proprietary driver, and closed-source implementation of the graphics libraries. 63While some portions of that stack was released as open-source in 2012, most of the work is still done in the closed-source runtime libraries and GPU code, as depicted in this diagram:</p> <figure><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="raspberrypi_video_api" viewBox="0 0 707.107 659.024" style="margin: 0 15px 0 60px;"><!----><defs><style>svg#raspberrypi_video_api text{font-size:27px}</style></defs><g id="layer1" transform="translate(-25.456 -45.442)"><g id="use4061" transform="translate(-51.476 -43.937)"><g id="g5352" transform="translate(13.636 -25.758)"><g id="g5354"><g id="g5356"><g id="g5358" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" transform="translate(-9.596 -17.172)"><path id="rect5362" fill="#594d44" stroke-width=".987" d="M96.689 153.431h150.56v86.485H96.689z"/><path id="rect5366" fill="#eeee0a" stroke-width=".982" d="M89.871 146.36h150.56v85.741H89.871z"/></g></g></g></g></g><use xlink:href="#use4061" id="use4081" width="744.094" height="1052.362" x="0" y="0"/><g id="use4083" transform="translate(-51.476 -43.937)"><g id="g4087" transform="translate(13.636 -25.758)"><g id="g4089"><g id="g4091"><g id="g4093" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" transform="translate(-9.596 -17.172)"><path id="rect4097" fill="#594d44" stroke-width=".987" d="M96.689 153.431h150.56v86.485H96.689z"/><path id="rect4101" fill="#eeee0a" stroke-width=".982" d="M89.871 146.36h150.56v85.741H89.871z"/></g></g></g></g></g><path id="rect4117" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M49.254 66.565h150.56v86.485H49.254z"/><path id="rect4121" fill="#eeee0a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M42.436 59.494h150.56v85.741H42.436z"/><path id="rect4117-9" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M242.436 66.193h150.56v86.485h-150.56z"/><path id="rect4117-6" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M430.82 66.193h150.56v86.485H430.82z"/><path id="rect4117-7" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M431.325 206.597h150.56v86.485h-150.56z"/><path id="rect4117-2" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M239.911 206.092h150.56v86.485h-150.56z"/><path id="rect4117-0" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".987" d="M50.517 205.082h150.56v86.485H50.517z"/><path id="rect4121-9" fill="#eeee0a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M235.365 58.989h150.56v85.741h-150.56z"/><path id="rect4121-91" fill="#eeee0a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M422.739 59.494h150.56v85.741h-150.56z"/><path id="rect4121-2" fill="#ee610a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M42.436 199.393h150.56v85.741H42.436z"/><path id="rect4121-2-6" fill="#ee610a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M235.87 197.878h150.56v85.741H235.87z"/><path id="rect4121-2-5" fill="#ee610a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".982" d="M423.244 199.393h150.56v85.741h-150.56z"/><path id="rect4117-0-7" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".868" d="M247.111 331.585h338.545v29.761H247.111z"/><path id="rect4117-0-7-3" fill="#ee610a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".868" d="M238.723 324.562h338.545v29.761H238.723z"/><path id="rect4117-7-4" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="1.342" d="M45.644 407.28h539.094v44.715H45.644z"/><path id="rect4117-7-4-0" fill="#594d44" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="1.342" d="M46.149 524.957h539.094v44.715H46.149z"/><path id="rect4117-7-4-3" fill="#eeee0a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="1.342" d="M39.079 400.714h539.094v44.715H39.079z"/><path id="rect4117-7-4-0-6" fill="#a00" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="1.342" d="M40.089 518.896h539.094v44.715H40.089z"/><path id="rect4121-4" fill="#eeee0a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".381" d="M46.715 633.397h43.31v44.916h-43.31z"/><path id="rect4121-4-3" fill="#ee610a" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".381" d="M257.776 633.397h43.31v44.916h-43.31z"/><path id="rect4121-4-8" fill="#a00" fill-opacity="1" fill-rule="evenodd" stroke="#000" stroke-dasharray="none" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".381" d="M458.48 633.397h43.31v44.916h-43.31z"/><text xml:space="preserve" id="text4802" x="49.529" y="120.622" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804" x="49.529" y="120.622">application</tspan></text><text xml:space="preserve" id="text4820" x="282.1" y="218.601" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822" x="282.1" y="218.601">OpenGL ES</tspan></text><text xml:space="preserve" id="text4802-3" x="250.488" y="122.305" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804-8" x="250.488" y="122.305">application</tspan></text><text xml:space="preserve" id="text4802-1" x="445.004" y="122.305" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804-5" x="445.004" y="122.305">application</tspan></text><text xml:space="preserve" id="text4802-35" x="87.699" y="94.133" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804-4" x="87.699" y="94.133">Media</tspan></text><text xml:space="preserve" id="text4820-3" x="77.945" y="219.197" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-6" x="77.945" y="219.197">
63OpenMax</tspan></text><text xml:space="preserve" id="text4820-9" x="522.483" y="217.328" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5" x="522.483" y="217.328">OpenVG</tspan></text><text xml:space="preserve" id="text4820-9-9" x="440.118" y="305.798" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1" x="440.118" y="305.798">EGL</tspan></text><text xml:space="preserve" id="text4820-9-9-5" x="262.241" y="378.196" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1-5" x="262.241" y="378.196">Kernel driver</tspan></text><text xml:space="preserve" id="text4820-9-9-1" x="223.756" y="480.995" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1-8" x="223.756" y="480.995">Videocore IV GPU</tspan></text><text xml:space="preserve" id="text4820-9-9-3" x="115.834" y="564.355" fill="#000" fill-opacity="1" stroke="none" class="themed" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:20px;line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1-52" x="115.834" y="568.355">Open</tspan><tspan id="tspan5043" x="115.834" y="590.134">source</tspan></text><text xml:space="preserve" id="text4820-9-9-3-6" x="356.071" y="568.412" fill="#000" fill-opacity="1" stroke="none" class="themed" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:20px;line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1-52-6" x="356.071" y="568.412">Closed</tspan><tspan id="tspan5043-7" x="356.071" y="590.191">source</tspan></text><text xml:space="preserve" id="text4820-9-9-3-4" x="591.731" y="568.658" fill="#000" fill-opacity="1" stroke="none" class="themed" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:20px;line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-1-52-1" x="591.731" y="568.658">Binary</tspan><tspan id="tspan5043-71" x="591.731" y="590.437">blob</tspan></text><path id="path5104" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m115.868 153.023.714 45.712" class="themed"/><path id="path5106" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M310.144 153.023v43.57" class="themed"/><path id="path5108" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M116.582 292.302v107.137" class="themed"/><path id="path5112" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M499.42 153.737v44.998" class="themed"/><path id="path5114" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m309.43 293.73.714 12.142" class="themed"/><path id="path5116" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m499.42 306.587-.714-12.857" class="themed"/><path id="path5118" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m407.996 305.872.714 17.857" class="themed"/><path id="path5120" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m310.144 305.872 189.276.715" class="themed"/><path id="path5122" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m407.282 362.298 1.428 37.141" class="themed"/><path id="path5154-7-4" fill="#070000" fill-opacity="1" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M401.176 383.962h13.889l-6.44 16.856" class="themed"/><path id="path5154-7-4-9" fill="#070000" fill-opacity="1" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M108.878 382.573h13.889l-6.44 16.856" class="themed"/><path id="path5154-7-4-1" fill="#070000" fill-opacity="1" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="M300.525 501.413h13.888l-6.439 16.856" class="themed"/><path id="path5154-7-4-5" fill="#070000" fill-opacity="1" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m315.222 469.284-13.89.015 7.137-16.863" class="themed"/><text xml:space="preserve" id="text4820-9-5" x="762.717" y="233.517" fill="#000" fill-opacity="1" stroke="none" class="themed" font-style="normal" font-weight="400" letter-spacing="0" style="line-height:125%" transform="scale(.87228 1.14642)" word-spacing="0"><tspan id="tspan4822-5-5" x="762.717" y="233.517">ARM</tspan></text><path id="path5317" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m613.676 61.455 21.212 16.162 1.01 160.606 18.182 18.182-18.182 18.182v152.525l-19.192 21.212" class="themed"/><path id="path3142" fill="none" stroke="#000" stroke-linecap="butt" stroke-linejoin="miter" stroke-opacity="1" stroke-width="1" d="m308.358 452.83-.714 65.353" class="themed"/><text xml:space="preserve" id="text4802-3-0" x="302.543" y="94.233" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804-8-2" x="302.543" y="94.233">3D</tspan></text><text xml:space="preserve" id="text4802-3-4" x="500.92" y="96.02" fill="#000" fill-opacity="1" stroke="none" font-style="normal" font-weight="400" letter-spacing="0" style="font-size:22px;line-height:125%" transform="scale(.96204 1.03945)" word-spacing="0"><tspan id="tspan4804-8-8" x="500.92" y="96.02">2D</tspan></text></g><!----></svg><!----> <figcaption>The VideoCore IV GPU driver stack<br/><small>(CC BY-SA 3.0)</small></figcaption></figure> <p><span class="note sidenote"><span class="sidenote-number">5</span>These header files and libraries can be found at <a href="https://github.com/raspberrypi/firmware" rel="nofollow">https://github.com/raspberrypi/firmware</a>.</span>The C header files and libraries for these Broadcom specific implementations are located in the <code>/opt/vc/include</code> and <code>/opt/vc/lib</code>
63 directories<span class="sidenote-number">5</span>.</p> <p><span class="note sidenote"><span class="sidenote-number">6</span>The Architecture Reference Guide for the Broadcom VideoCore IV GPU is available at <a href="https://docs.broadcom.com/docs/12358545" rel="nofollow">https://docs.broadcom.com/docs/12358545</a>.</span><span class="note sidenote"><span class="sidenote-number">7</span>The source code for the userland libraries can be found at <a href="https://github.com/raspberrypi/userland" rel="nofollow">https://github.com/raspberrypi/userland</a>.</span><span class="note sidenote"><span class="sidenote-number">8</span>The source code for the VC4 driver can be found in the <code>src/gallium/drivers/vc4</code> directory of the <a href="https://gitlab.freedesktop.org/mesa/mesa" rel="nofollow">Mesa repository</a>.</span>In 2014, Broadcom and the Raspberry Pi Foundation announced the documentation release for the VideoCore IV 3D graphics processor<span class="sidenote-number">6</span>, as well as the source release of the graphics stack under a BSD license<span class="sidenote-number">7</span>. 64Few months after the announcement, the source code of a Gallium-based Mesa OpenGL driver for the Broadcom SoC GPU, written from scratch by <em>Eric Anholt</em>, was committed to the Mesa project<span class="sidenote-number">8</span>. <strong>This paved the way towards open-source drivers for the Raspberry Pi GPUs</strong>.</p> <p><span class="note sidenote"><span class="sidenote-number">9</span>The source code for the V3D driver can be found in the <code>src/gallium/drivers/v3d</code> directory of the <a href="https://gitlab.freedesktop.org/mesa/mesa" rel="nofollow">Mesa repository</a>.</span>The Raspberry Pi 4 Broadcom BCM2711 SoC (formerly BCM2838) now includes the VideoCore VI GPU, thatâs only supported by a Mesa driver<span class="sidenote-number">9</span>. 65The original Broadcom proprietary driver, specifically designed for the BCM2837 SoC GPU, does not work on the Raspberry Pi 4. 66This Mesa V3D (VideoCore VI) driver <a href="https://www.khronos.org/conformance/adopters/conformant-products/opengles#submission_882" rel="nofollow">conforms to OpenGL ES 3.1</a> (as of March 2021), while the VideoCore VI GPU is capable of OpenGL ES 3.2.</p> <p>After this research phase, and its few historical findings, Iâm convinced the way forward to succeed in my mission, is to rely on these open-source drivers â¦</p> <h2 id="the-programming"><a class="anchor" aria-hidden="true" tabindex="-1" href="#the-programming">
66<script context="module"> 67 export const metadata = {"title":"Running OpenGL Shaders on the Raspberry Pi","date":"2021-03-08T00:00:00.000Z","published":true,"image":"./torus.jpg","slug":"glsl-raspberry-pi","tags":["OpenGL","Raspberry Pi"]}; 68 const { title, date, published, image, slug, tags } = metadata; 69</script>
69 <svg viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a>The Programming</h2> <p><span class="note sidenote"><span class="sidenote-number">10</span>The <a href="https://www.kernel.org/doc/html/v5.10/gpu/introduction.html" rel="nofollow">Linux GPU Driver Developerâs Guide</a> provides an extensive documentation of the DRM/KMS sub-system.</span>With these drivers, running OpenGL or OpenGL ES, without X11, is possible using the <a href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager" rel="nofollow">DRM</a>/<a href="https://en.wikipedia.org/wiki/Direct_Rendering_Manager#Kernel_Mode_Setting" rel="nofollow">KMS</a> Linux kernel sub-system<span class="sidenote-number">10</span>, in combination with the Mesa Generic Buffer Management (GBM) library.</p> <p>Luckily, I stumbled upon <a href="https://gitlab.freedesktop.org/mesa/kmscube/" rel="nofollow">kmscube</a>, which is an example application, written in C, that demonstrates how to use the KMS/GBM/EGL APIs to drive bare metal graphics, and provides an implementation of the <a href="https://en.wikipedia.org/wiki/Mode-setting" rel="nofollow">mode-setting</a> and <a href="https://en.wikipedia.org/wiki/Multiple_buffering#Page_flipping" rel="nofollow">page-flipping</a> operations.</p> <p>The basic idea is to use two triangles, covering the entire screen, that are rasterized by sampling the shader for every pixel. 70So that left me with:</p> <p>1) Loading a copy of the Shadertoy shader from the file system:</p> <!----><pre class="shiki One Dark Pro language-c" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// The template used to input uniforms that are automatically added by Shadertoy,</span></span> 71<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// and to call the Shadertoy shader main method entrypoint.</span></span> 72<span class="line"><span style="color:var(--shiki-token-keyword)">static</span><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">shadertoy_fs_tmpl </span><span style="color:var(--shiki-token-operator)">=</span></span> 73<span class="line"><span style="color:var(--shiki-token-string)"> "precision mediump float; </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 74<span class="line"><span style="color:var(--shiki-token-string)"> "uniform vec3 iResolution; // viewport resolution (in pixels) </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 75<span class="line"><span style="color:var(--shiki-token-string)"> "uniform float iTime; // shader playback time (in seconds) </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 76<span class="line"><span style="color:var(--shiki-token-string)"> "uniform int iFrame; // current frame number </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 77<span class="line"><span style="color:var(--shiki-token-string)"> " </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 78<span class="line"><span style="color:var(--shiki-token-string)"> "</span><span style="color:var(--shiki-token-constant)">%s</span><span style="color:var(--shiki-token-symbol)"> \n</span><span style="color:var(--shiki-token-string)">"</span></span> 79<span class="line"><span style="color:var(--shiki-token-string)"> " </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 80<span class="line"><span style="color:var(--shiki-token-string)"> "void main() </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 81<span class="line"><span style="color:var(--shiki-token-string)"> "{ </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 82<span class="line"><span style="color:var(--shiki-token-string)"> " mainImage(gl_FragColor, gl_FragCoord.xy); </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 83<span class="line"><span style="color:var(--shiki-token-string)"> "} </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 84<span class="line"></span> 85<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// Creates the fragment shader from a local copy of the Shadertoy shader</span></span> 86<span class="line"><span style="color:var(--shiki-token-keyword)">static</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-token-function)">load_shader</span><span style="color:var(--shiki-token-punctuation)">(</span><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">file</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 87<span class="line"><span style="color:var(--shiki-token-keyword)"> struct</span><span style="color:var(--shiki-color-text)">
87 stat statbuf</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 88<span class="line"><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">frag</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 89<span class="line"><span style="color:var(--shiki-token-keyword)"> int</span><span style="color:var(--shiki-color-text)"> fd</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> ret</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 90<span class="line"></span> 91<span class="line"><span style="color:var(--shiki-color-text)"> fd </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> open</span><span style="color:var(--shiki-color-text)">(file</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 92<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-color-text)">fd </span><span style="color:var(--shiki-token-operator)"><</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 93<span class="line"><span style="color:var(--shiki-token-function)"> err</span><span style="color:var(--shiki-color-text)">(fd</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string)"> "could not open '</span><span style="color:var(--shiki-token-constant)">%s</span><span style="color:var(--shiki-token-string)">'"</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> file)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 94<span class="line"><span style="color:var(--shiki-token-punctuation)"> }</span></span> 95<span class="line"></span> 96<span class="line"><span style="color:var(--shiki-color-text)"> ret </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> fstat</span><span style="color:var(--shiki-color-text)">(fd</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-operator)"> &</span><span style="color:var(--shiki-color-text)">statbuf)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 97<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-color-text)">ret </span><span style="color:var(--shiki-token-operator)"><</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 98<span class="line"><span style="color:var(--shiki-token-function)"> err</span><span style="color:var(--shiki-color-text)">(ret</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string)"> "could not stat '</span><span style="color:var(--shiki-token-constant)">%s</span><span style="color:var(--shiki-token-string)">'"</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> file)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 99<span class="line"><span style="color:var(--shiki-token-punctuation)"> }</span></span> 100<span class="line"></span> 101<span class="line"><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">text </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> mmap</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-constant)">NULL</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-variable)">
101 statbuf</span><span style="color:var(--shiki-color-text)">.</span><span style="color:var(--shiki-token-member)">st_size</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> PROT_READ</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> MAP_PRIVATE</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> fd</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 102<span class="line"><span style="color:var(--shiki-token-function)"> asprintf</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-operator)">&</span><span style="color:var(--shiki-color-text)">frag</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> shadertoy_fs_tmpl</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> text)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 103<span class="line"></span> 104<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-color-text)"> frag</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 105<span class="line"><span style="color:var(--shiki-token-punctuation)">}</span></span></code></pre><!----> <p>2) Compiling the shaders on the GPU, creating the OpenGL program, linking it, and initializing uniform variables and buffers:</p> <!----><pre class="shiki One Dark Pro language-c" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// Holds the playback time and frame number uniform locations</span></span> 106<span class="line"><span style="color:var(--shiki-color-text)">GLint iTime</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> iFrame</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 107<span class="line"></span> 108<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// The triangles, to be rasterized by sampling the shader for every pixel of the screen.</span></span> 109<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// Quads are not supported by OpenGL ES, so we have to use two triangles.</span></span> 110<span class="line"><span style="color:var(--shiki-token-keyword)">static</span><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-color-text)"> GLfloat vertices</span><span style="color:var(--shiki-token-keyword)">[]</span><span style="color:var(--shiki-token-operator)"> =</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 111<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // First triangle:</span></span> 112<span class="line"><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 113<span class="line"><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 114<span class="line"><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 115<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Second triangle:</span></span> 116<span class="line"><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 117<span class="line"><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 118<span class="line"><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 1.0</span><span style="color:var(--shiki-token-parameter)">f</span><span style="color:var(--shiki-token-punctuation)">,</span></span> 119<span class="line"><span style="color:var(--shiki-token-punctuation)">};</span></span> 120<span class="line"></span> 121<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// The vertex shader, responsible to position the geometry.</span></span> 122<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// We simply need the identity in our case.</span></span> 123<span class="line"><span style="color:var(--shiki-token-keyword)">static</span><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">
123shadertoy_vs </span><span style="color:var(--shiki-token-operator)">=</span></span> 124<span class="line"><span style="color:var(--shiki-token-string)"> "attribute vec3 position; </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 125<span class="line"><span style="color:var(--shiki-token-string)"> "void main() </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 126<span class="line"><span style="color:var(--shiki-token-string)"> "{ </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 127<span class="line"><span style="color:var(--shiki-token-string)"> " gl_Position = vec4(position, 1.0); </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span></span> 128<span class="line"><span style="color:var(--shiki-token-string)"> "} </span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 129<span class="line"></span> 130<span class="line"><span style="color:var(--shiki-token-keyword)">int</span><span style="color:var(--shiki-token-function)"> init_shadertoy</span><span style="color:var(--shiki-token-punctuation)">(</span><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-token-keyword)"> struct</span><span style="color:var(--shiki-token-parameter)"> gbm </span><span style="color:var(--shiki-token-operator)">*</span><span style="color:var(--shiki-color-text)">gbm</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> struct</span><span style="color:var(--shiki-token-parameter)"> egl </span><span style="color:var(--shiki-token-operator)">*</span><span style="color:var(--shiki-color-text)">egl</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> const</span><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">file</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 131<span class="line"><span style="color:var(--shiki-token-keyword)"> int</span><span style="color:var(--shiki-color-text)"> ret</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 132<span class="line"><span style="color:var(--shiki-token-keyword)"> char</span><span style="color:var(--shiki-token-operator)"> *</span><span style="color:var(--shiki-color-text)">shadertoy_fs</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 133<span class="line"><span style="color:var(--shiki-color-text)"> GLuint program</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> vbo</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 134<span class="line"><span style="color:var(--shiki-color-text)"> GLint iResolution</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 135<span class="line"></span> 136<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Loads the Shadertoy shader from the file system, and creates the fragment shader</span></span> 137<span class="line"><span style="color:var(--shiki-color-text)"> shadertoy_fs </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> load_shader</span><span style="color:var(--shiki-color-text)">(file)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 138<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Compiles the fragment and vertex shaders, and attaches them the returned program</span></span> 139<span class="line"><span style="color:var(--shiki-color-text)"> ret </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> create_program</span><span style="color:var(--shiki-color-text)">(shadertoy_vs</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)">
139 shadertoy_fs)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 140<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-color-text)">ret</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 141<span class="line"><span style="color:var(--shiki-token-function)"> printf</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-string)">"failed to create program</span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 142<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 143<span class="line"><span style="color:var(--shiki-token-punctuation)"> }</span></span> 144<span class="line"><span style="color:var(--shiki-color-text)"> program </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-color-text)"> ret</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 145<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Links the program</span></span> 146<span class="line"><span style="color:var(--shiki-color-text)"> ret </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> link_program</span><span style="color:var(--shiki-color-text)">(program)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 147<span class="line"><span style="color:var(--shiki-token-keyword)"> if</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-color-text)">ret</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 148<span class="line"><span style="color:var(--shiki-token-function)"> printf</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-string)">"failed to link program</span><span style="color:var(--shiki-token-symbol)">\n</span><span style="color:var(--shiki-token-string)">"</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 149<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-token-operator)"> -</span><span style="color:var(--shiki-token-numeric)">1</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 150<span class="line"><span style="color:var(--shiki-token-punctuation)"> }</span></span> 151<span class="line"></span> 152<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Matches the viewport width and height to the screen resolution</span></span> 153<span class="line"><span style="color:var(--shiki-token-function)"> glViewport</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-numeric)">0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-variable)"> gbm</span><span style="color:var(--shiki-color-text)">-></span><span style="color:var(--shiki-token-member)">width</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-variable)"> gbm</span><span style="color:var(--shiki-color-text)">-></span><span style="color:var(--shiki-token-member)">height</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 154<span class="line"><span style="color:var(--shiki-token-function)"> glUseProgram</span><span style="color:var(--shiki-color-text)">(program)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 155<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Initializes the uniform variables</span></span> 156<span class="line"><span style="color:var(--shiki-color-text)"> iTime </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> glGetUniformLocation</span><span style="color:var(--shiki-color-text)">(program</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string)"> "iTime"</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 157<span class="line"><span style="color:var(--shiki-color-text)"> iFrame </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> glGetUniformLocation</span><span style="color:var(--shiki-color-text)">(program</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string)">
157 "iFrame"</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 158<span class="line"><span style="color:var(--shiki-color-text)"> iResolution </span><span style="color:var(--shiki-token-operator)">=</span><span style="color:var(--shiki-token-function)"> glGetUniformLocation</span><span style="color:var(--shiki-color-text)">(program</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-string)"> "iResolution"</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 159<span class="line"><span style="color:var(--shiki-token-function)"> glUniform3f</span><span style="color:var(--shiki-color-text)">(iResolution</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-variable)"> gbm</span><span style="color:var(--shiki-color-text)">-></span><span style="color:var(--shiki-token-member)">width</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-variable)"> gbm</span><span style="color:var(--shiki-color-text)">-></span><span style="color:var(--shiki-token-member)">height</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 160<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Initializes the vertices buffer that holds the triangles data</span></span> 161<span class="line"><span style="color:var(--shiki-token-function)"> glGenBuffers</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-numeric)">1</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-operator)"> &</span><span style="color:var(--shiki-color-text)">vbo)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 162<span class="line"><span style="color:var(--shiki-token-function)"> glBindBuffer</span><span style="color:var(--shiki-color-text)">(GL_ARRAY_BUFFER</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> vbo)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 163<span class="line"><span style="color:var(--shiki-token-function)"> glBufferData</span><span style="color:var(--shiki-color-text)">(GL_ARRAY_BUFFER</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> sizeof</span><span style="color:var(--shiki-token-punctuation)">(</span><span style="color:var(--shiki-color-text)">vertices</span><span style="color:var(--shiki-token-punctuation)">),</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> GL_STATIC_DRAW)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 164<span class="line"><span style="color:var(--shiki-token-function)"> glBufferSubData</span><span style="color:var(--shiki-color-text)">(GL_ARRAY_BUFFER</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> sizeof</span><span style="color:var(--shiki-token-punctuation)">(</span><span style="color:var(--shiki-color-text)">vertices</span><span style="color:var(--shiki-token-punctuation)">),</span><span style="color:var(--shiki-token-operator)"> &</span><span style="color:var(--shiki-token-variable)">vertices</span><span style="color:var(--shiki-color-text)">[</span><span style="color:var(--shiki-token-numeric)">0</span><span style="color:var(--shiki-color-text)">])</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 165<span class="line"><span style="color:var(--shiki-token-function)"> glVertexAttribPointer</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-numeric)">0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 2</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> GL_FLOAT</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> GL_FALSE</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-token-keyword)">const</span><span style="color:var(--shiki-color-text)"> GLvoid </span><span style="color:var(--shiki-token-operator)">*</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-token-keyword)">intptr_t</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 166<span class="line"><span style="color:var(--shiki-token-function)"> glEnableVertexAttribArray</span><span style="color:var(--shiki-color-text)">(</span><span style="color:var(--shiki-token-numeric)">0</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 167<span class="line"></span> 168<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Provides the rendering method to be called for each frame</span></span> 169<span class="line"><span style="color:var(--shiki-token-variable)"> egl</span><span style="color:var(--shiki-color-text)">-></span><span style="color:var(--shiki-token-member)">draw</span><span style="color:var(--shiki-token-operator)"> =</span><span style="color:var(--shiki-color-text)"> draw_shadertoy</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 170<span class="line"></span> 171<span class="line"><span style="color:var(--shiki-token-keyword)"> return</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 172<span class="line"><span style="color:var(--shiki-token-punctuation)">}</span></span></code></pre><!----> <p>3) Finally, rasterizing the triangles, so that every pixel from the screen gets sampled from the fragment shader:</p> <!----><pre class="shiki One Dark Pro language-c" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span style="color:var(--shiki-token-comment);font-style:italic">// This is called to render every frame</span></span> 173<span class="line"><span style="color:var(--shiki-token-keyword)">static</span><span style="color:var(--shiki-token-keyword)"> void</span><span style="color:var(--shiki-token-function)"> draw_shadertoy</span><span style="color:var(--shiki-token-punctuation)">(</span><span style="color:var(--shiki-token-keyword)">
173uint64_t</span><span style="color:var(--shiki-color-text)"> start_time</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-keyword)"> unsigned</span><span style="color:var(--shiki-color-text)"> frame</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-punctuation)"> {</span></span> 174<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Sets the playback time uniform in seconds</span></span> 175<span class="line"><span style="color:var(--shiki-token-function)"> glUniform1f</span><span style="color:var(--shiki-color-text)">(iTime</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-token-function)">get_time_ns</span><span style="color:var(--shiki-color-text)">() </span><span style="color:var(--shiki-token-operator)">-</span><span style="color:var(--shiki-color-text)"> start_time</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-token-operator)"> /</span><span style="color:var(--shiki-token-punctuation)"> (</span><span style="color:var(--shiki-token-keyword)">double</span><span style="color:var(--shiki-token-punctuation)">)</span><span style="color:var(--shiki-color-text)"> NSEC_PER_SEC)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 176<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Sets the current frame number uniform</span></span> 177<span class="line"><span style="color:var(--shiki-token-function)"> glUniform1ui</span><span style="color:var(--shiki-color-text)">(iFrame</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-color-text)"> frame)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 178<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"> // Renders the triangles</span></span> 179<span class="line"><span style="color:var(--shiki-token-function)"> glDrawArrays</span><span style="color:var(--shiki-color-text)">(GL_TRIANGLES</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 0</span><span style="color:var(--shiki-token-punctuation)">,</span><span style="color:var(--shiki-token-numeric)"> 6</span><span style="color:var(--shiki-color-text)">)</span><span style="color:var(--shiki-token-punctuation)">;</span></span> 180<span class="line"><span style="color:var(--shiki-token-punctuation)">}</span></span></code></pre><!----> <p>The complete source code is available at <a href="https://github.com/astefanutti/shaderbang" rel="nofollow">Shaderbang</a>.</p> <h2 id="the-fun"><a class="anchor" aria-hidden="true" tabindex="-1" href="#the-fun">
180<script context="module"> 181 export const metadata = {"title":"Running OpenGL Shaders on the Raspberry Pi","date":"2021-03-08T00:00:00.000Z","published":true,"image":"./torus.jpg","slug":"glsl-raspberry-pi","tags":["OpenGL","Raspberry Pi"]}; 182 const { title, date, published, image, slug, tags } = metadata; 183</script>
183 <svg viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a>The Fun</h2> <figure><picture><!--[--><source srcset="/_app/immutable/assets/examples.CEsiFC5E.avif 600w, /_app/immutable/assets/examples.CkHOozpO.avif 1000w, /_app/immutable/assets/examples.BgZ4ibn2.avif 1400w" type="image/avif" sizes="100vw"/><source srcset="/_app/immutable/assets/examples.CAzUs3Fd.webp 600w, /_app/immutable/assets/examples.Bwzji2e7.webp 1000w, /_app/immutable/assets/examples.Bwh2iAT4.webp 1400w" type="image/webp" sizes="100vw"/><source srcset="/_app/immutable/assets/examples.D0HYVzUz.png 600w, /_app/immutable/assets/examples.CocPoZxi.png 1000w, /_app/immutable/assets/examples.B8dbPLqZ.png 1400w" type="image/png" sizes="100vw"/><!--]--> <img src="/_app/immutable/assets/examples.B8dbPLqZ.png" width="1400" height="783" alt="Examples" loading="lazy" class="svelte-3ned59"/></picture><!----> <figcaption>A selection of shaders from Shadertoy, that run successfully on the Rapsberry Pi.<br/> You can find copies of these in the <code>examples</code> directory of the <a href="https://github.com/astefanutti/shaderbang">project repository</a>.</figcaption></figure> <p>Iâve successfully run shaders on the RPi 3B+ and RPi 4, with Raspberry Pi OS Lite 2020-12-02, Linux kernel 5.4.79.</p> <p>You can run the following instructions to build the CLI binary:</p> <!----><pre class="shiki One Dark Pro language-shell" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> apt</span><span style="color:var(--shiki-token-string)"> update</span></span> 184<span class="line shell-output"><span style="color:var(--shiki-token-comment);font-style:italic"># Install the build tools</span></span> 185<span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> apt</span><span style="color:var(--shiki-token-string)"> install</span><span style="color:var(--shiki-token-string)"> gcc</span><span style="color:var(--shiki-token-string)"> make</span></span> 186<span class="line shell-output"><span style="color:var(--shiki-token-comment);font-style:italic"># Install the required DRM, GBM, EGL and OpenGL ES API headers</span></span> 187<span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> apt</span><span style="color:var(--shiki-token-string)"> install</span><span style="color:var(--shiki-token-string)"> libdrm-dev</span><span style="color:var(--shiki-token-string)"> libgbm-dev</span><span style="color:var(--shiki-token-string)"> libegl-dev</span><span style="color:var(--shiki-token-string)"> libgles2-mesa-dev</span></span> 188<span class="line shell-output"><span style="color:var(--shiki-token-comment);font-style:italic"># Clone the repository</span></span> 189<span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">git</span><span style="color:var(--shiki-token-string)"> clone</span><span style="color:var(--shiki-token-string)"> https://github.com/astefanutti/shaderbang.git</span><span style="color:var(--shiki-color-text)"> && </span><span style="color:var(--shiki-token-symbol)">cd</span><span style="color:var(--shiki-token-string)"> shaderbang</span></span> 190<span class="line shell-output"><span style="color:var(--shiki-token-comment);font-style:italic"># Build the glsl CLI binary</span></span> 191<span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">make</span></span></code></pre><!----> <p>The VC4/V3D driver kernel module must be activated. 192Assuming youâve installed <a href="https://www.raspberrypi.org/software/operating-systems" rel="nofollow">Raspberry Pi OS</a>, this can be achieved by running the following commands:</p> <p>1) Edit the <code>/boot/config.txt</code> <a href="https://www.raspberrypi.org/documentation/configuration/config-txt/" rel="nofollow">file</a>, e.g.:</p> <!----><pre class="shiki One Dark Pro language-shell wrap" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> vi</span><span style="color:var(--shiki-token-string)"> /<wbr>boot/<wbr>config<wbr>.txt</span></span></code></pre><!----> <p>2) Set the following properties:</p> <!----><pre class="shiki One Dark Pro language-ini" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"># Required: Enable the firmware/fake DRM/KMS VC4/V3D driver</span></span> 193<span class="line"><span style="color:var(--shiki-token-keyword)">dtoverlay</span><span style="color:var(--shiki-color-text)">=</span><span style="color:var(--shiki-token-string)">vc4-fkms-v3d</span></span> 194<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"># Optional: Increase the memory reserved for the GPU</span></span> 195<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"># 16MB disables certain GPU features</span></span> 196<span class="line"><span style="color:var(--shiki-token-keyword)">gpu_mem</span><span style="color:var(--shiki-color-text)">=</span><span style="color:var(--shiki-token-string)">64</span></span> 197<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"># Optional: Avoid GPU down-clocking below 500 MHz that slows FPS down</span></span> 198<span class="line"><span style="color:var(--shiki-token-comment);font-style:italic"># Should be set to 250 on the RPi 3</span></span> 199<span class="line"><span style="color:var(--shiki-token-keyword)">v3d_freq_min</span><span style="color:var(--shiki-color-text)">=</span><span style="color:var(--shiki-token-string)">500</span></span></code></pre><!----> <p>3) Reboot your Raspberry Pi, so that the changes are taken into account, e.g.:</p> <!----><pre class="shiki One Dark Pro language-shell wrap" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> reboot</span></span></code></pre><!----> <p>You can then run shaders from the <code>examples</code> directory, e.g.:</p> <!----><pre class="shiki One Dark Pro language-shell" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">./glsl</span><span style="color:var(--shiki-token-string)"> examples/stripey_torus_interior.glsl</span></span> 200<span class="line"></span> 201<span class="line shell-output"><span style="color:var(--shiki-token-function)">OpenGL</span><span style="color:var(--shiki-token-string)"> ES</span><span style="color:var(--shiki-token-string)"> 2.x</span><span style="color:var(--shiki-token-string)"> information:</span></span> 202<span class="line shell-output"><span style="color:var(--shiki-token-function)"> version:</span><span style="color:var(--shiki-token-string)"> "OpenGL ES 3.1 Mesa 19.3.2"</span></span> 203<span class="line shell-output"><span style="color:var(--shiki-token-function)"> shading</span><span style="color:var(--shiki-token-string)"> language</span><span style="color:var(--shiki-token-string)"> version:</span><span style="color:var(--shiki-token-string)"> "OpenGL ES GLSL ES 3.10"</span></span> 204<span class="line shell-output"><span style="color:var(--shiki-token-function)"> vendor:</span><span style="color:var(--shiki-token-string)"> "Broadcom"</span></span> 205<span class="line shell-output"><span style="color:var(--shiki-token-function)"> renderer:</span><span style="color:var(--shiki-token-string)"> "V3D 4.2"</span></span></code></pre><!----> <p>And check that <code>renderer: "V3D 4.2"</code> is present in the console output, to confirm itâs setup correctly.</p> <p>Soon after I started testing, I realized the framerate was fluctuating, and the V3D GPU frequency was dropping well below 500 MHz. 206This can be observed by running the following command from a separate terminal:</p> <!----><pre class="shiki One Dark Pro language-shell wrap" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">watch</span><span style="color:var(--shiki-token-constant)"> -n</span><span style="color:var(--shiki-token-numeric)"> 1</span><span style="color:var(--shiki-token-string)"> vcgencmd</span><span style="color:var(--shiki-token-string)"> measure<wbr>_clock</span><span style="color:var(--shiki-token-string)"> v3d</span></span></code></pre><!----> <p><span class="note sidenote"><span class="sidenote-number">11</span>This is not optimal, as it increases power consumption, while the GPU is idle.</span>This issue has been reported in <a href="https://github.com/raspberrypi/linux/issues/3935" rel="nofollow">raspberrypi/linux#3935</a>. 207It seems the default <em>governor</em> scales the GPU frequency down, despite instructions being scheduled into the GPU workload queue. 208A solution to prevent GPU frequency down-scaling, is to set the minimum frequency, by adding <code>v3d_freq_min=500</code> to the <code>/boot/config.txt</code> file<span class="sidenote-number">11</span>.</p> <p>This can also be used to <a href="https://www.raspberrypi.org/documentation/configuration/config-txt/overclocking.md" rel="nofollow">overclock</a> the GPU. 209Iâve successfully tested overclocking the V3D GPU to 600 MHz, which results in a noticeable FPS improvement.</p> <h2 id="the-future"><a class="anchor" aria-hidden="true" tabindex="-1" href="#the-future">
209<script context="module"> 210 export const metadata = {"title":"Running OpenGL Shaders on the Raspberry Pi","date":"2021-03-08T00:00:00.000Z","published":true,"image":"./torus.jpg","slug":"glsl-raspberry-pi","tags":["OpenGL","Raspberry Pi"]}; 211 const { title, date, published, image, slug, tags } = metadata; 212</script>
212 <svg viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a>The Future</h2> <p>The <code>vc4-fkms-v3d</code> driver is known as the <em>fake/firmware</em> DRM/KMS driver, where the kernel driver still delegates the interactions with the display controller to the firmware. 213A newer <code>vc4-kms-v3d</code> driver, known as the <em>full</em> DRM/KMS driver, is now available, where the kernel drives the display controller directly.</p> <p>I gave it a try, after an upgrade to the latest kernel version available (as of March 2021):</p> <!----><pre class="shiki One Dark Pro language-shell wrap" style="background-color:var(--shiki-color-background);color:var(--shiki-color-text)" tabindex="0"><code tabindex="0"><span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">sudo</span><span style="color:var(--shiki-token-string)"> apt</span><span style="color:var(--shiki-token-string)"> full-upgrade</span></span> 214<span class="line"><span class="shell-prompt">$ </span><span style="color:var(--shiki-token-string)">uname</span><span style="color:var(--shiki-token-constant)"> -a</span></span> 215<span class="line shell-output"><span style="color:var(--shiki-token-function)">Linux</span><span style="color:var(--shiki-token-string)"> master</span><span style="color:var(--shiki-token-string)"> 5<wbr>.10<wbr>.17-v7l+</span><span style="color:var(--shiki-token-comment);font-style:italic"> #1403 SMP Mon Feb 22 11:33:35 GMT 2021 armv7l GNU/<wbr>Linux</span></span></code></pre><!----> <p>Unfortunately, I faced the issue reported in <a href="https://github.com/raspberrypi/linux/issues/4020" rel="nofollow">raspberrypi/linux#4020</a>. 216I plan to try it again, once itâs fixed. 217It seems <a href="https://www.raspberrypi.org/forums/viewtopic.php?t=293877#p1775592" rel="nofollow">it may be possible</a> to use it in combination with the touchscreen driver for the DSI display. 218So it could possibly enable <strong>interactivity</strong>, by feeding the mouse uniform, with touchscreen events from <a href="http://www.tslib.org" rel="nofollow">tslib</a>.</p> <p>There are also few things that, I think, would be logical additions:</p> <ul><li>Forward keyboard events to the input keyboard texture</li> <li>Feed audio / video inputs to microphone / camera textures</li> <li>Package Shadertoy default media files</li> <li>Load arbitrary input texture files</li> <li>â¦</li></ul> <p>What started as a toy project, to end year 2020 light-heartedly, turned out to be a small, yet very rewarding, journey into the world of open-source GPU programming. 219I think I can safely say it: mission accomplished!</p> <p>Iâd be happy to hear your feedback at <a href="https://github.com/astefanutti/shaderbang" rel="nofollow">Shaderbang</a>!</p><!--]--><!----></article><!----><!--]--><!----> <footer><p>Copyright © <a href="https://github.com/astefanutti">Antonin Stefanutti</a>, 2026</p></footer><!--]--><!--]--> <!--[-1--><!--]--><!--]--> 220 221
221<script> 222 { 223 __sveltekit_1hofghi = { 224 base: new URL(".", location).pathname.slice(0, -1) 225 }; 226 227 const element = document.currentScript.parentElement; 228 229 Promise.all([ 230 import("./_app/immutable/entry/start.CE_5GFeA.js"), 231 import("./_app/immutable/entry/app.BlQISDEY.js") 232 ]).then(([kit, app]) => { 233 kit.start(app, element, { 234 node_ids: [0, 3], 235 data: [null,null], 236 form: null, 237 error: null 238 }); 239 }); 240 } 241 </script>
241 242 </div> 243</body> 244 245</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.