<divid="app"data-server-rendered="true"><divclass="theme-container"><divclass="theme-default-content"><h1>404</h1><blockquote>How did we get here?</blockquote><ahref="/learn-wgpu/"class="router-link-active">Take me home.</a></div></div><divclass="global-ui"><!----></div></div>
<divid="app"data-server-rendered="true"><divclass="theme-container"><divclass="theme-default-content"><h1>404</h1><blockquote>That's a Four-Oh-Four.</blockquote><ahref="/learn-wgpu/"class="router-link-active">Take me home.</a></div></div><divclass="global-ui"><!----></div></div>
(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{593:function(e,t,o){"use strict";o.r(t);vars=o(23),r=Object(s.a)({},(function(){vare=this,t=e.$createElement,o=e._self._c||t;returno("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("h1",{attrs:{id:"foreword"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#foreword"}},[e._v("#")]),e._v(" Foreword")]),e._v(" "),o("p",[e._v("The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with "),o("code",[e._v("wgpu")]),e._v(". I won't go over specifics of creating "),o("code",[e._v("wgpu")]),e._v(" resources, as those will be covered elsewhere. The code for these examples is still available however, and will be accessible on Github.")])])}),[],!1,null,null,null);t.default=r.exports}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{593:function(e,t,o){"use strict";o.r(t);vars=o(23),r=Object(s.a)({},(function(){vare=this,t=e.$createElement,o=e._self._c||t;returno("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[o("h1",{attrs:{id:"foreword"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#foreword"}},[e._v("#")]),e._v(" Foreword")]),e._v(" "),o("p",[e._v("The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with "),o("code",[e._v("wgpu")]),e._v(". I won't go over the specifics of creating "),o("code",[e._v("wgpu")]),e._v(" resources, as those will be covered elsewhere. The code for these examples is still available however and will be accessible on Github.")])])}),[],!1,null,null,null);t.default=r.exports}}]);
</code></pre></div><h2id="using-rust-s-new-resolver"><ahref="#using-rust-s-new-resolver"class="header-anchor">#</a> Using Rust's new resolver</h2><p>As of version 0.10, wgpu require's cargo's <ahref="https://doc.rust-lang.org/cargo/reference/resolver.html#feature-resolver-version-2"target="_blank"rel="noopener noreferrer">newest feature resolver<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>, which is the default in the 2021 edition (any new project started with Rust version 1.56.0 or newer). However, if you are still using the 2018 edition, you must include <code>resolver = "2"</code> in either the <code>[package]</code> section of <code>Cargo.toml</code> if you are working on a single crate, or the <code>[workspace]</code> section of the root <code>Cargo.toml</code> in a workspace.</p><h2id="env-logger"><ahref="#env-logger"class="header-anchor">#</a> env_logger</h2><p>It is very important to enable logging via <code>env_logger::init();</code>.
</code></pre></div><h2id="using-rust-s-new-resolver"><ahref="#using-rust-s-new-resolver"class="header-anchor">#</a> Using Rust's new resolver</h2><p>As of version 0.10, wgpu requires cargo's <ahref="https://doc.rust-lang.org/cargo/reference/resolver.html#feature-resolver-version-2"target="_blank"rel="noopener noreferrer">newest feature resolver<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>, which is the default in the 2021 edition (any new project started with Rust version 1.56.0 or newer). However, if you are still using the 2018 edition, you must include <code>resolver = "2"</code> in either the <code>[package]</code> section of <code>Cargo.toml</code> if you are working on a single crate, or the <code>[workspace]</code> section of the root <code>Cargo.toml</code> in a workspace.</p><h2id="env-logger"><ahref="#env-logger"class="header-anchor">#</a> env_logger</h2><p>It is very important to enable logging via <code>env_logger::init();</code>.
When wgpu hits any error it panics with a generic message, while logging the real error via the log crate.
This means if you don't include <code>env_logger::init()</code> wgpu will fail silently, leaving you very confused!</p><h2id="the-code"><ahref="#the-code"class="header-anchor">#</a> The code</h2><p>There's not much going on here yet, so I'm just going to post the code in full. Just paste this into your <code>lib.rs</code> or equivalent.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">winit<spanclass="token punctuation">::</span></span><spanclass="token punctuation">{</span>
This means if you don't include <code>env_logger::init()</code>, wgpu will fail silently, leaving you very confused!</p><h2id="the-code"><ahref="#the-code"class="header-anchor">#</a> The code</h2><p>There's not much going on here yet, so I'm just going to post the code in full. Just paste this into your <code>lib.rs</code> or equivalent.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">winit<spanclass="token punctuation">::</span></span><spanclass="token punctuation">{</span>
</code></pre></div><p>All this does is create a window, and keep it open until the user closes it, or presses escape. Next we'll need a <code>main.rs</code> to actually run the code. It's quite simple it just imports <code>run()</code> and, well runs it!</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">tutorial1_window<spanclass="token punctuation">::</span></span>run<spanclass="token punctuation">;</span>
</code></pre></div><p>All this does is create a window, and keep it open until the user closes it, or presses escape. Next, we'll need a <code>main.rs</code> to run the code. It's quite simple, it just imports <code>run()</code> and, well, runs it!</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">tutorial1_window<spanclass="token punctuation">::</span></span>run<spanclass="token punctuation">;</span>
</code></pre></div><p>If you only want to support desktop, that's all you have to do! In the next tutorial we'll actually start using wgpu!</p><h2id="added-support-for-the-web"><ahref="#added-support-for-the-web"class="header-anchor">#</a> Added support for the web</h2><p>If I go through this tutorial about WebGPU and never talk about using it on the web, then I'd hardly call this tutorial complete. Fortunately getting a wgpu application running in a browser is not too difficult once you get things set up.</p><p>Lets start with the changes we need to make to are <code>Cargo.toml</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">lib</span><spanclass="token punctuation">]</span>
</code></pre></div><p>If you only want to support desktops, that's all you have to do! In the next tutorial, we'll start using wgpu!</p><h2id="added-support-for-the-web"><ahref="#added-support-for-the-web"class="header-anchor">#</a> Added support for the web</h2><p>If I go through this tutorial about WebGPU and never talk about using it on the web, then I'd hardly call this tutorial complete. Fortunately getting a wgpu application running in a browser is not too difficult once you get things set up.</p><p>Let's start with the changes we need to make to are <code>Cargo.toml</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">lib</span><spanclass="token punctuation">]</span>
</code></pre></div><p>These lines tell cargo that we want to allow our crate to build a native Rust static library (rlib) and a C/C++ compatible library (cdylib). We need the rlib if we want to run wgpu in a desktop environment. We need the cdylib to create the Web Assembly that browser will actually run.</p><divclass="note"><h2id="web-assembly"><ahref="#web-assembly"class="header-anchor">#</a> Web Assembly</h2><p>Web Assembly ie WASM, is a binary format supported by most modern browsers that allows lowerlevel languages such as Rust to run on a web page. This allows us to right the bulk of our application in Rust and use a few lines of Javascript to get it running in a web browser.</p></div><p>Now all we need are some more dependencies that are specific to running in WASM:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><p>These lines tell cargo that we want to allow our crate to build a native Rust static library (rlib) and a C/C++ compatible library (cdylib). We need rlib if we want to run wgpu in a desktop environment. We need cdylib to create the Web Assembly that the browser will run.</p><divclass="note"><h2id="web-assembly"><ahref="#web-assembly"class="header-anchor">#</a> Web Assembly</h2><p>Web Assembly i.e. WASM, is a binary format supported by most modern browsers that allows lower-level languages such as Rust to run on a web page. This allows us to write the bulk of our application in Rust and use a few lines of Javascript to get it running in a web browser.</p></div><p>Now, all we need are some more dependencies that are specific to running in WASM:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><p>The <ahref="https://docs.rs/cfg-if"target="_blank"rel="noopener noreferrer">cfg-if<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> crate adds a macro that makes using platformspecific code more manageable.</p><p>The <code>[target.'cfg(target_arch = "wasm32")'.dependencies]</code> line tells cargo to only include these dependencies if we are targeting the <code>wasm32</code> architecture. The next few dependencies are just make interfacing with javascript a lot easier.</p><ul><li><ahref="https://docs.rs/console_error_panic_hook"target="_blank"rel="noopener noreferrer">console_error_panic_hook<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> configures the <code>panic!</code> macro to send errors to the javascript console. Without this when you encounter panics, you'll be left in the dark for what caused them.</li><li><ahref="https://docs.rs/console_log"target="_blank"rel="noopener noreferrer">console_log<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> implements the <ahref="https://docs.rs/log"target="_blank"rel="noopener noreferrer">log<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> API. It sends all logs to the javascript console. It can be configured to only send logs of a particular log level. This is also great for debugging.</li><li>We need to enable WebGL feature on wgpu if we want to run on most current browsers. Support is in the works for using the WebGPU api directly, but that is only possible on experimental versions of browsers such as Firefox Nightly and Chrome Canary.<br>
You're welcome to test this code on these browsers (and the wgpu devs would appreciate it as well), but for sake of simplicity I'm going to stick to using the WebGL feature until the WebGPU api gets to a more stable state.<br>
If you want more details check out the guide for compiling for the web on <ahref="https://github.com/gfx-rs/wgpu/wiki/Running-on-the-Web-with-WebGPU-and-WebGL"target="_blank"rel="noopener noreferrer">wgpu's repo<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></li><li><ahref="https://docs.rs/wasm-bindgen"target="_blank"rel="noopener noreferrer">wasm-bindgen<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> is the most important dependency in this list. It's responsible for generating the boilerplate code that will tell the browser how to use our crate. It also allows us to expose methods in Rust that will can be used in Javascript, and vice-versa.<br>
I won't get into the specifics of wasm-bindgen, so if you need a primer (or just a refresher) check out <ahref="https://rustwasm.github.io/wasm-bindgen/"target="_blank"rel="noopener noreferrer">this<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></li><li><ahref="https://docs.rs/web-sys"target="_blank"rel="noopener noreferrer">web-sys<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> is a crate that includes many methods and structures that are available in a normal javascript application: <code>get_element_by_id</code>, <code>append_child</code>. The features listed are only the bare minimum of what we need currently.</li></ul><h2id="more-code"><ahref="#more-code"class="header-anchor">#</a> More code</h2><p>First we need to import <code>wasm-bindgen</code> in <code>lib.rs</code>:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg(target_arch=<spanclass="token string">"wasm32"</span>)]</span>
</code></pre></div><p>The <ahref="https://docs.rs/cfg-if"target="_blank"rel="noopener noreferrer">cfg-if<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> crate adds a macro that makes using platform-specific code more manageable.</p><p>The <code>[target.'cfg(target_arch = "wasm32")'.dependencies]</code> line tells cargo to only include these dependencies if we are targeting the <code>wasm32</code> architecture. The next few dependencies just make interfacing with javascript a lot easier.</p><ul><li><ahref="https://docs.rs/console_error_panic_hook"target="_blank"rel="noopener noreferrer">console_error_panic_hook<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> configures the <code>panic!</code> macro to send errors to the javascript console. Without this when you encounter panics, you'll be left in the dark about what caused them.</li><li><ahref="https://docs.rs/console_log"target="_blank"rel="noopener noreferrer">console_log<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> implements the <ahref="https://docs.rs/log"target="_blank"rel="noopener noreferrer">log<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> API. It sends all logs to the javascript console. It can be configured to only send logs of a particular log level. This is also great for debugging.</li><li>We need to enable WebGL feature on wgpu if we want to run on most current browsers. Support is in the works for using the WebGPU api directly, but that is only possible on experimental versions of browsers such as Firefox Nightly and Chrome Canary.<br>
You're welcome to test this code on these browsers (and the wgpu devs would appreciate it as well), but for sake of simplicity, I'm going to stick to using the WebGL feature until the WebGPU api gets to a more stable state.<br>
If you want more details check out the guide for compiling for the web on <ahref="https://github.com/gfx-rs/wgpu/wiki/Running-on-the-Web-with-WebGPU-and-WebGL"target="_blank"rel="noopener noreferrer">wgpu's repo<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></li><li><ahref="https://docs.rs/wasm-bindgen"target="_blank"rel="noopener noreferrer">wasm-bindgen<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> is the most important dependency in this list. It's responsible for generating the boilerplate code that will tell the browser how to use our crate. It also allows us to expose methods in Rust that can be used in Javascript, and vice-versa.<br>
I won't get into the specifics of wasm-bindgen, so if you need a primer (or just a refresher) check out <ahref="https://rustwasm.github.io/wasm-bindgen/"target="_blank"rel="noopener noreferrer">this<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></li><li><ahref="https://docs.rs/web-sys"target="_blank"rel="noopener noreferrer">web-sys<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> is a crate that includes many methods and structures that are available in a normal javascript application: <code>get_element_by_id</code>, <code>append_child</code>. The features listed are only the bare minimum of what we need currently.</li></ul><h2id="more-code"><ahref="#more-code"class="header-anchor">#</a> More code</h2><p>First, we need to import <code>wasm-bindgen</code> in <code>lib.rs</code>:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg(target_arch=<spanclass="token string">"wasm32"</span>)]</span>
</code></pre></div><p>Next we need to tell wasm-bindgen to run our <code>run()</code> function when the WASM is loaded:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg_attr(target_arch=<spanclass="token string">"wasm32"</span>, wasm_bindgen(start))]</span>
</code></pre></div><p>Next, we need to tell wasm-bindgen to run our <code>run()</code> function when the WASM is loaded:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg_attr(target_arch=<spanclass="token string">"wasm32"</span>, wasm_bindgen(start))]</span>
</code></pre></div><p>Then we need to toggle what logger we are using based on if we are in WASM land or not. Add the following to the top of the run function replacing the <code>env_logger::init()</code> line:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token namespace">cfg_if<spanclass="token punctuation">::</span></span><spanclass="token macro property">cfg_if!</span><spanclass="token punctuation">{</span>
</code></pre></div><p>This will setup <code>console_log</code> and <code>console_error_panic_hook</code> in a web build, and will initialize <code>env_logger</code> in a normal build. This is important as <code>env_logger</code> doesn't support Web Assembly at the moment.</p><p>Next, after we create our event loop and window, we need to add an canvas to the html document that we will host our application:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg(target_arch = <spanclass="token string">"wasm32"</span>)]</span>
</code></pre></div><p>This will setup <code>console_log</code> and <code>console_error_panic_hook</code> in a web build, and will initialize <code>env_logger</code> in a normal build. This is important as <code>env_logger</code> doesn't support Web Assembly at the moment.</p><p>Next, after we create our event loop and window, we need to add a canvas to the HTML document that we will host our application:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[cfg(target_arch = <spanclass="token string">"wasm32"</span>)]</span>
<spanclass="token punctuation">{</span>
<spanclass="token comment">// Winit prevents sizing with CSS, so we have to set</span>
<spanclass="token comment">// the size manually when on web.</span>
@ -118,11 +118,11 @@ I won't get into the specifics of wasm-bindgen, so if you need a primer (or just
</code></pre></div><divclass="note"><p>The <code>"wasm-example"</code> id is specific to my project (aka. this tutorial). You can substitute this for what ever id your using in your html. Alternatively you could add the canvas directly to the <code><body></code> as they do in the wgpu repo. This part is ultimately up to you.</p></div><p>That's all the web specific code we need for now. Next thing we need to do is build the Web Assembly itself.</p><h2id="wasm-pack"><ahref="#wasm-pack"class="header-anchor">#</a> Wasm Pack</h2><p>Now you can build a wgpu application with just wasm-bindgen, but I ran into some issues doing that. For one, you need to install wasm-bindgen on your computer as well as include it as a dependency. They version you install as a dependency <strong>needs</strong> to exactly match the version you installed, otherwise your build will fail.</p><p>In order to get around this shortcoming, and to make the lives of everyone reading this easier, I opted to add <ahref="https://rustwasm.github.io/docs/wasm-pack/"target="_blank"rel="noopener noreferrer">wasm-pack<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> to the mix. Wasm-pack handles installing the correct version of wasm-bindgen for you, and it supports building for different types of web targets as well: browser, NodeJS, and bundlers such as webpack.</p><p>In order to use wasm-pack, first you need to <ahref="https://rustwasm.github.io/wasm-pack/installer/"target="_blank"rel="noopener noreferrer">install it<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p><p>Once you've done that, we can use it to build our crate. If you only have one crate in your project, you can just use <code>wasm-pack build</code>. If your using a workspace, you'll have to specify what crate you want to build. Imagine your crate is a directory called <code>game</code>, you would use:</p><divclass="language-bash extra-class"><preclass="language-bash"><code>wasm-pack build game
</code></pre></div><divclass="note"><p>The <code>"wasm-example"</code> id is specific to my project (aka. this tutorial). You can substitute this for whatever id you're using in your HTML. Alternatively, you could add the canvas directly to the <code><body></code> as they do in the wgpu repo. This part is ultimately up to you.</p></div><p>That's all the web-specific code we need for now. The next thing we need to do is build the Web Assembly itself.</p><h2id="wasm-pack"><ahref="#wasm-pack"class="header-anchor">#</a> Wasm Pack</h2><p>Now you can build a wgpu application with just wasm-bindgen, but I ran into some issues doing that. For one, you need to install wasm-bindgen on your computer as well as include it as a dependency. The version you install as a dependency <strong>needs</strong> to exactly match the version you installed, otherwise, your build will fail.</p><p>To get around this shortcoming, and to make the lives of everyone reading this easier, I opted to add <ahref="https://rustwasm.github.io/docs/wasm-pack/"target="_blank"rel="noopener noreferrer">wasm-pack<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> to the mix. Wasm-pack handles installing the correct version of wasm-bindgen for you, and it supports building for different types of web targets as well: browser, NodeJS, and bundlers such as webpack.</p><p>To use wasm-pack, first, you need to <ahref="https://rustwasm.github.io/wasm-pack/installer/"target="_blank"rel="noopener noreferrer">install it<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p><p>Once you've done that, we can use it to build our crate. If you only have one crate in your project, you can just use <code>wasm-pack build</code>. If you're using a workspace, you'll have to specify what crate you want to build. Imagine your crate is a directory called <code>game</code>, you would use:</p><divclass="language-bash extra-class"><preclass="language-bash"><code>wasm-pack build game
</code></pre></div><p>Once wasm-pack is done building you'll have a <code>pkg</code> directory in the same directory as your crate. This has all the javascript code needed to run the WASM code. You'd then import the WASM module in javascript:</p><divclass="language-js extra-class"><preclass="language-js"><code><spanclass="token keyword">const</span> init <spanclass="token operator">=</span><spanclass="token keyword">await</span><spanclass="token keyword">import</span><spanclass="token punctuation">(</span><spanclass="token string">'./pkg/game.js'</span><spanclass="token punctuation">)</span><spanclass="token punctuation">;</span>
</code></pre></div><p>This site uses <ahref="https://vuepress.vuejs.org/"target="_blank"rel="noopener noreferrer">Vuepress<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>, so I load the WASM in a Vue component. How you handle your WASM will depend on what you want to do. If you want to check out how I'm doing things take a look at <ahref="https://github.com/sotrh/learn-wgpu/blob/master/docs/.vuepress/components/WasmExample.vue"target="_blank"rel="noopener noreferrer">this<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p><divclass="note"><p>If you intend to use your WASM module in a plain HTML website, you'll need to tell wasm-pack to target the web:</p><divclass="language-bash extra-class"><preclass="language-bash"><code>wasm-pack build --target web
</code></pre></div><p>You'll then need run the WASM code in an ES6 Module:</p><divclass="language-html extra-class"><preclass="language-html"><code><spanclass="token doctype"><spanclass="token punctuation"><!</span><spanclass="token doctype-tag">DOCTYPE</span><spanclass="token name">html</span><spanclass="token punctuation">></span></span>
</code></pre></div><p>You'll then need to run the WASM code in an ES6 Module:</p><divclass="language-html extra-class"><preclass="language-html"><code><spanclass="token doctype"><spanclass="token punctuation"><!</span><spanclass="token doctype-tag">DOCTYPE</span><spanclass="token name">html</span><spanclass="token punctuation">></span></span>
</code></pre></div></div><p>Press the button below and you will see the code running!</p><divid="wasm-example"><!----><button>Try Tutorial1_window!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial1-window/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div></div><p>Press the button below and you will see the code running!</p><divid="wasm-example"><!----><button>Try Tutorial1_window!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial1-window/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>I'm glossing over <code>State</code>s fields, but they'll make more sense as I explain the code behind the methods.</p><h2id="state-new"><ahref="#state-new"class="header-anchor">#</a> State::new()</h2><p>The code for this is pretty straight forward, but let's break this down a bit.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">State</span><spanclass="token punctuation">{</span>
</code></pre></div><p>I'm glossing over <code>State</code>s fields, but they'll make more sense as I explain the code behind these methods.</p><h2id="state-new"><ahref="#state-new"class="header-anchor">#</a> State::new()</h2><p>The code for this is pretty straightforward, but let's break it down a bit.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">State</span><spanclass="token punctuation">{</span>
</code></pre></div><h3id="instance-and-adapter"><ahref="#instance-and-adapter"class="header-anchor">#</a> Instance and Adapter</h3><p>The <code>instance</code> is the first thing you create when using wgpu. Its main purpose
is to create <code>Adapter</code>s and <code>Surface</code>s.</p><p>The <code>adapter</code> is a handle to our actual graphics card. You can use this to get information about the graphics card such as its name and what backend the adapter uses. We use this to create our <code>Device</code> and <code>Queue</code> later. Let's discuss the fields of <code>RequestAdapterOptions</code>.</p><ul><li><code>power_preference</code> has two variants: <code>LowPower</code>, and <code>HighPerformance</code>. This means will pick an adapter that favors battery life such as a integrated GPU when using <code>LowPower</code>. <code>HighPerformance</code>as will pick an adapter for more power hungry yet more performant GPU's such as your dedicated graphics card. WGPU will favor <code>LowPower</code> if there is no adapter for the <code>HighPerformance</code> option.</li><li>The <code>compatible_surface</code> field tells wgpu to find an adapter that can present to the supplied surface.</li><li>The <code>force_fallback_adapter</code> forces wgpu to pick an adapter that will work on all hardware. This usually means that the rendering backend will use a "software" system, instead of hardware such as a GPU.</li></ul><divclass="note"><p>The options I've passed to <code>request_adapter</code> aren't guaranteed to work for all devices, but will work for most of them. If wgpu can't find an adapter with the required permissions, <code>request_adapter</code> will return <code>None</code>. If you want to get all adapters for a particular backend you can use <code>enumerate_adapters</code>. This will give you an iterator that you can loop over to check if one of the adapters works for your needs.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> adapter <spanclass="token operator">=</span> instance
is to create <code>Adapter</code>s and <code>Surface</code>s.</p><p>The <code>adapter</code> is a handle to our actual graphics card. You can use this to get information about the graphics card such as its name and what backend the adapter uses. We use this to create our <code>Device</code> and <code>Queue</code> later. Let's discuss the fields of <code>RequestAdapterOptions</code>.</p><ul><li><code>power_preference</code> has two variants: <code>LowPower</code>, and <code>HighPerformance</code>. <code>LowPower</code> will pick an adapter that favors battery life, such as an integrated GPU. <code>HighPerformance</code>will pick an adapter for more power-hungry yet more performant GPU's such as a dedicated graphics card. WGPU will favor <code>LowPower</code> if there is no adapter for the <code>HighPerformance</code> option.</li><li>The <code>compatible_surface</code> field tells wgpu to find an adapter that can present to the supplied surface.</li><li>The <code>force_fallback_adapter</code> forces wgpu to pick an adapter that will work on all hardware. This usually means that the rendering backend will use a "software" system, instead of hardware such as a GPU.</li></ul><divclass="note"><p>The options I've passed to <code>request_adapter</code> aren't guaranteed to work for all devices, but will work for most of them. If wgpu can't find an adapter with the required permissions, <code>request_adapter</code> will return <code>None</code>. If you want to get all adapters for a particular backend you can use <code>enumerate_adapters</code>. This will give you an iterator that you can loop over to check if one of the adapters works for your needs.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> adapter <spanclass="token operator">=</span> instance
</code></pre></div><p>Another thing to note is that <code>Adapter</code>s are locked to a specific backend. If you are on Windows and have 2 graphics cards you'll have at least 4 adapters available to use, 2 Vulkan and 2 DirectX.</p><p>For more fields you can use to refine your search <ahref="https://docs.rs/wgpu/latest/wgpu/struct.Adapter.html"target="_blank"rel="noopener noreferrer">check out the docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p></div><h3id="the-surface-2"><ahref="#the-surface-2"class="header-anchor">#</a> The Surface</h3><p>The <code>surface</code> is the part of the window that we draw to. We need it to draw directly to the screen. Our <code>window</code> needs to implement <ahref="https://crates.io/crates/raw-window-handle"target="_blank"rel="noopener noreferrer">raw-window-handle<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>'s <code>HasRawWindowHandle</code> trait to create a surface. Fortunately, winit's <code>Window</code> fits the bill. We also need it to request our <code>adapter</code>.</p><h3id="device-and-queue"><ahref="#device-and-queue"class="header-anchor">#</a> Device and Queue</h3><p>Let's use the <code>adapter</code> to create the device and queue.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span><spanclass="token punctuation">(</span>device<spanclass="token punctuation">,</span> queue<spanclass="token punctuation">)</span><spanclass="token operator">=</span> adapter<spanclass="token punctuation">.</span><spanclass="token function">request_device</span><spanclass="token punctuation">(</span>
</code></pre></div><p>Another thing to note is that <code>Adapter</code>s are locked to a specific backend. If you are on Windows and have 2 graphics cards you'll have at least 4 adapters available to use, 2 Vulkan and 2 DirectX.</p><p>For more fields you can use to refine your search,<ahref="https://docs.rs/wgpu/latest/wgpu/struct.Adapter.html"target="_blank"rel="noopener noreferrer">check out the docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p></div><h3id="the-surface-2"><ahref="#the-surface-2"class="header-anchor">#</a> The Surface</h3><p>The <code>surface</code> is the part of the window that we draw to. We need it to draw directly to the screen. Our <code>window</code> needs to implement <ahref="https://crates.io/crates/raw-window-handle"target="_blank"rel="noopener noreferrer">raw-window-handle<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>'s <code>HasRawWindowHandle</code> trait to create a surface. Fortunately, winit's <code>Window</code> fits the bill. We also need it to request our <code>adapter</code>.</p><h3id="device-and-queue"><ahref="#device-and-queue"class="header-anchor">#</a> Device and Queue</h3><p>Let's use the <code>adapter</code> to create the device and queue.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span><spanclass="token punctuation">(</span>device<spanclass="token punctuation">,</span> queue<spanclass="token punctuation">)</span><spanclass="token operator">=</span> adapter<spanclass="token punctuation">.</span><spanclass="token function">request_device</span><spanclass="token punctuation">(</span>
</code></pre></div><p>The <code>features</code> field on <code>DeviceDescriptor</code>, allows us to specify what extra features we want. For this simple example, I've decided not to use any extra features.</p><divclass="note"><p>The graphics card you have limits the features you can use. If you want to use certain features you may need to limit what devices you support, or provide workarounds.</p><p>You can get a list of features supported by your device using <code>adapter.features()</code>, or <code>device.features()</code>.</p><p>You can view a full list of features <ahref="https://docs.rs/wgpu/latest/wgpu/struct.Features.html"target="_blank"rel="noopener noreferrer">here<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p></div><p>The <code>limits</code> field describes the limit of certain types of resources that we can create. We'll use the defaults for this tutorial, so we can support most devices. You can view a list of limits <ahref="https://docs.rs/wgpu/latest/wgpu/struct.Limits.html"target="_blank"rel="noopener noreferrer">here<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> config <spanclass="token operator">=</span><spanclass="token namespace">wgpu<spanclass="token punctuation">::</span></span><spanclass="token class-name">SurfaceConfiguration</span><spanclass="token punctuation">{</span>
</code></pre></div><p>The <code>features</code> field on <code>DeviceDescriptor</code>, allows us to specify what extra features we want. For this simple example, I've decided not to use any extra features.</p><divclass="note"><p>The graphics card you have limits the features you can use. If you want to use certain features you may need to limit what devices you support or provide workarounds.</p><p>You can get a list of features supported by your device using <code>adapter.features()</code>, or <code>device.features()</code>.</p><p>You can view a full list of features <ahref="https://docs.rs/wgpu/latest/wgpu/struct.Features.html"target="_blank"rel="noopener noreferrer">here<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p></div><p>The <code>limits</code> field describes the limit of certain types of resources that we can create. We'll use the defaults for this tutorial, so we can support most devices. You can view a list of limits <ahref="https://docs.rs/wgpu/latest/wgpu/struct.Limits.html"target="_blank"rel="noopener noreferrer">here<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> config <spanclass="token operator">=</span><spanclass="token namespace">wgpu<spanclass="token punctuation">::</span></span><spanclass="token class-name">SurfaceConfiguration</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Here we are defining a config for our surface. This will define how the surface creates its underlying <code>SurfaceTexture</code>s. We will talk about <code>SurfaceTexture</code> when we get to the <code>render</code> function. For now lets talk about the config's fields.</p><p>The <code>usage</code> field describes how <code>SurfaceTexture</code>s will be used. <code>RENDER_ATTACHMENT</code> specifies that the textures will be used to write to the screen (we'll talk about more <code>TextureUsages</code>s later).</p><p>The <code>format</code> defines how <code>SurfaceTexture</code>s will be stored on the gpu. Different displays prefer different formats. We use <code>surface.get_preferred_format(&adapter)</code> to figure out the best format to use based on the display you're using.</p><p><code>width</code> and <code>height</code> are the width and the height in pixels of a <code>SurfaceTexture</code>. This should usually be the width and the height of the window.</p><divclass="warning">
</code></pre></div><p>Here we are defining a config for our surface. This will define how the surface creates its underlying <code>SurfaceTexture</code>s. We will talk about <code>SurfaceTexture</code> when we get to the <code>render</code> function. For now, let's talk about the config's fields.</p><p>The <code>usage</code> field describes how <code>SurfaceTexture</code>s will be used. <code>RENDER_ATTACHMENT</code> specifies that the textures will be used to write to the screen (we'll talk about more <code>TextureUsages</code>s later).</p><p>The <code>format</code> defines how <code>SurfaceTexture</code>s will be stored on the gpu. Different displays prefer different formats. We use <code>surface.get_preferred_format(&adapter)</code> to figure out the best format to use based on the display you're using.</p><p><code>width</code> and <code>height</code> are the width and the height in pixels of a <code>SurfaceTexture</code>. This should usually be the width and the height of the window.</p><divclass="warning">
Make sure that the width and height of the `SurfaceTexture` are not 0, as that can cause your app to crash.
</div><p><code>present_mode</code> uses <code>wgpu::PresentMode</code> enum which determines how to sync the surface with the display. The option we picked, <code>FIFO</code>, will cap the display rate at the displays framerate. This is essentially VSync. This is also the most optimal mode on mobile. There are other options and you can see all of them <ahref="https://docs.rs/wgpu/latest/wgpu/enum.PresentMode.html"target="_blank"rel="noopener noreferrer">in the docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></p><p>Now that we've configured our surface properly we can add these new fields at the end of the method.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">Self</span><spanclass="token punctuation">{</span>
</div><p><code>present_mode</code> uses <code>wgpu::PresentMode</code> enum which determines how to sync the surface with the display. The option we picked, <code>FIFO</code>, will cap the display rate at the display's framerate. This is essentially VSync. This is also the most optimal mode on mobile. There are other options and you can see all of them <ahref="https://docs.rs/wgpu/latest/wgpu/enum.PresentMode.html"target="_blank"rel="noopener noreferrer">in the docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></p><p>Now that we've configured our surface properly we can add these new fields at the end of the method.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">Self</span><spanclass="token punctuation">{</span>
surface<spanclass="token punctuation">,</span>
device<spanclass="token punctuation">,</span>
queue<spanclass="token punctuation">,</span>
@ -115,7 +115,7 @@ Make sure that the width and height of the `SurfaceTexture` are not 0, as that c
<spanclass="token punctuation">}</span>
<spanclass="token comment">// ...</span>
<spanclass="token punctuation">}</span>
</code></pre></div><p>Since our <code>State::new()</code> method is async we need to change run to be async as well so that we can await it.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">async</span><spanclass="token keyword">fn</span><spanclass="token function-definition function">run</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Since our <code>State::new()</code> method is async we need to change <code>run()</code> to be async as well so that we can await it.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">async</span><spanclass="token keyword">fn</span><spanclass="token function-definition function">run</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
@ -128,7 +128,7 @@ Make sure that the width and height of the `SurfaceTexture` are not 0, as that c
</code></pre></div><p>We then use the <code>block_on</code> function provided by pollster to await our future:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><divclass="warning"><p>Don't use <code>block_on</code> inside of an async function if you plan to support WASM. Futures have to be run using the browsers executor. If you try to bring your own you code will crash when you encounter a future that doesn't execute immediately.</p></div><p>If we try to build WASM now it will fail because <code>wasm-bindgen</code> doesn't support using async functions as <code>start</code> methods. You could switch to calling <code>run</code> manually in javascript, but for simplicity we'll add the <ahref="https://docs.rs/wasm-bindgen-futures"target="_blank"rel="noopener noreferrer">wasm-bindgen-futures<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> crate to our WASM dependencies as that doesn't require us to change any code. Your dependecies should look something like this:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><divclass="warning"><p>Don't use <code>block_on</code> inside of an async function if you plan to support WASM. Futures have to be run using the browser's executor. If you try to bring your own your code will crash when you encounter a future that doesn't execute immediately.</p></div><p>If we try to build WASM now it will fail because <code>wasm-bindgen</code> doesn't support using async functions as <code>start</code> methods. You could switch to calling <code>run</code> manually in javascript, but for simplicity, we'll add the <ahref="https://docs.rs/wasm-bindgen-futures"target="_blank"rel="noopener noreferrer">wasm-bindgen-futures<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> crate to our WASM dependencies as that doesn't require us to change any code. Your dependencies should look something like this:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><h2id="resize"><ahref="#resize"class="header-anchor">#</a> resize()</h2><p>If we want to support resizing in our application, we're going to need to reconfigure the <code>surface</code> everytime the window's size changes. That's the reason we stored the physical <code>size</code> and the <code>config</code> used to configure the <code>surface</code>. With all of these, the resize method is very simple.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// impl State</span>
</code></pre></div><h2id="resize"><ahref="#resize"class="header-anchor">#</a> resize()</h2><p>If we want to support resizing in our application, we're going to need to reconfigure the <code>surface</code> everytime the window's size changes. That's the reason we stored the physical <code>size</code> and the <code>config</code> used to configure the <code>surface</code>. With all of these, the resize method is very simple.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// impl State</span>
</code></pre></div><p>There's nothing really different here from the initial <code>surface</code> configuration, so I won't get into it.</p><p>We call this method in <code>main()</code> in the event loop for the following events.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">match</span> event <spanclass="token punctuation">{</span>
</code></pre></div><p>There's nothing different here from the initial <code>surface</code> configuration, so I won't get into it.</p><p>We call this method in <code>run()</code> in the event loop for the following events.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">match</span> event <spanclass="token punctuation">{</span>
</code></pre></div><p>We need to do a little more work in the event loop. We want <code>State</code> to have priority over <code>main()</code>. Doing that (and previous changes) should have your loop looking like this.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// main()</span>
</code></pre></div><p>We need to do a little more work in the event loop. We want <code>State</code> to have priority over <code>run()</code>. Doing that (and previous changes) should have your loop looking like this.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// run()</span>
</code></pre></div><p>We'll add some code here later on to move around objects.</p><h2id="render"><ahref="#render"class="header-anchor">#</a> render()</h2><p>Here's where the magic happens. First we need to get a frame to render to.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// impl State</span>
</code></pre></div><p>We'll add some code here later on to move around objects.</p><h2id="render"><ahref="#render"class="header-anchor">#</a> render()</h2><p>Here's where the magic happens. First, we need to get a frame to render to.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// impl State</span>
</code></pre></div><p>This line creates a <code>TextureView</code> with default settings. We need to do this because we want to control how the render code interacts with the texture.</p><p>We also need to create a <code>CommandEncoder</code> to create the actual commands to send to the gpu. Most modern graphics frameworks expect commands to be stored in a command buffer before being sent to the gpu. The <code>encoder</code> builds a command buffer that we can then send to the gpu.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span><spanclass="token keyword">mut</span> encoder <spanclass="token operator">=</span><spanclass="token keyword">self</span><spanclass="token punctuation">.</span>device<spanclass="token punctuation">.</span><spanclass="token function">create_command_encoder</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token namespace">wgpu<spanclass="token punctuation">::</span></span><spanclass="token class-name">CommandEncoderDescriptor</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Now we can actually get to clearing the screen (long time coming). We need to use the <code>encoder</code> to create a <code>RenderPass</code>. The <code>RenderPass</code> has all the methods for the actual drawing. The code for creating a <code>RenderPass</code> is a bit nested, so I'll copy it all here before talking about its pieces.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token punctuation">{</span>
</code></pre></div><p>Now we can get to clearing the screen (long time coming). We need to use the <code>encoder</code> to create a <code>RenderPass</code>. The <code>RenderPass</code> has all the methods for the actual drawing. The code for creating a <code>RenderPass</code> is a bit nested, so I'll copy it all here before talking about its pieces.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token punctuation">{</span>
</code></pre></div><p>First things first, let's talk about the extra block (<code>{}</code>) around <code>encoder.begin_render_pass(...)</code>. <code>begin_render_pass()</code> borrows <code>encoder</code> mutably (aka <code>&mut self</code>). We can't call <code>encoder.finish()</code> until we release that mutable borrow. The block tells rust to drop any variables within it when the code leaves that scope thus releasing the mutable borrow on <code>encoder</code> and allowing us to <code>finish()</code> it. If you don't like the <code>{}</code>, you can also use <code>drop(render_pass)</code> to achieve the same effect.</p><p>We can get the same results by removing the <code>{}</code>, and the <code>let _render_pass =</code> line, but we need access to the <code>_render_pass</code> in the next tutorial, so we'll leave it as is.</p><p>The last lines of the code tell <code>wgpu</code> to finish the command buffer, and to submit it to the gpu's render queue.</p><p>We need to update the event loop again to call this method. We'll also call update before it too.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// main()</span>
</code></pre></div><p>First things first, let's talk about the extra block (<code>{}</code>) around <code>encoder.begin_render_pass(...)</code>. <code>begin_render_pass()</code> borrows <code>encoder</code> mutably (aka <code>&mut self</code>). We can't call <code>encoder.finish()</code> until we release that mutable borrow. The block tells rust to drop any variables within it when the code leaves that scope thus releasing the mutable borrow on <code>encoder</code> and allowing us to <code>finish()</code> it. If you don't like the <code>{}</code>, you can also use <code>drop(render_pass)</code> to achieve the same effect.</p><p>We can get the same results by removing the <code>{}</code>, and the <code>let _render_pass =</code> line, but we need access to the <code>_render_pass</code> in the next tutorial, so we'll leave it as is.</p><p>The last lines of the code tell <code>wgpu</code> to finish the command buffer, and to submit it to the gpu's render queue.</p><p>We need to update the event loop again to call this method. We'll also call <code>update()</code> before it too.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// run()</span>
</code></pre></div><p>The <code>RenderPassColorAttachment</code> has the <code>view</code> field which informs <code>wgpu</code> what texture to save the colors to. In this case we specify <code>view</code> that we created using <code>surface.get_current_texture()</code>. This means that any colors we draw to this attachment will get drawn to the screen.</p><p>The <code>resolve_target</code> is the texture that will receive the resolved output. This will be the same as <code>view</code> unless multisampling is enabled. We don't need to specify this, so we leave it as <code>None</code>.</p><p>The <code>ops</code> field takes a <code>wpgu::Operations</code> object. This tells wgpu what to do with the colors on the screen (specified by <code>view</code>). The <code>load</code> field tells wgpu how to handle colors stored from the previous frame. Currently, we are clearing the screen with a bluish color. The <code>store</code> field tells wgpu whether we want to store the rendered results to the <code>Texture</code> behind our <code>TextureView</code> (in this case it's the <code>SurfaceTexture</code>). We use <code>true</code> as we do want to store our render results.</p><divclass="note"><p>It's not uncommon to not clear the screen if the screen is going to be completely covered up with objects. If your scene doesn't cover the entire screen however you can end up with something like this.</p><p><imgsrc="/learn-wgpu/assets/img/no-clear.753f913f.png"alt="./no-clear.png"></p></div><h2id="validation-errors"><ahref="#validation-errors"class="header-anchor">#</a> Validation Errors?</h2><p>If wgpu is using Vulkan on your machine, you may run into validation errors if you are running an older version of the Vulkan SDK. You should be using at least version <code>1.2.182</code> as older versions can give out some false positives. If errors persist, you may have encountered a bug in wgpu. You can post an issue at <ahref="https://github.com/gfx-rs/wgpu"target="_blank"rel="noopener noreferrer">https://github.com/gfx-rs/wgpu<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></p><h2id="challenge"><ahref="#challenge"class="header-anchor">#</a> Challenge</h2><p>Modify the <code>input()</code> method to capture mouse events, and update the clear color using that. <em>Hint: you'll probably need to use <code>WindowEvent::CursorMoved</code></em>.</p><divid="wasm-example"><!----><button>Try Tutorial2_surface!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial2-surface/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>The <code>RenderPassColorAttachment</code> has the <code>view</code> field which informs <code>wgpu</code> what texture to save the colors to. In this case we specify the <code>view</code> that we created using <code>surface.get_current_texture()</code>. This means that any colors we draw to this attachment will get drawn to the screen.</p><p>The <code>resolve_target</code> is the texture that will receive the resolved output. This will be the same as <code>view</code> unless multisampling is enabled. We don't need to specify this, so we leave it as <code>None</code>.</p><p>The <code>ops</code> field takes a <code>wpgu::Operations</code> object. This tells wgpu what to do with the colors on the screen (specified by <code>view</code>). The <code>load</code> field tells wgpu how to handle colors stored from the previous frame. Currently, we are clearing the screen with a bluish color. The <code>store</code> field tells wgpu whether we want to store the rendered results to the <code>Texture</code> behind our <code>TextureView</code> (in this case it's the <code>SurfaceTexture</code>). We use <code>true</code> as we do want to store our render results.</p><divclass="note"><p>It's not uncommon to not clear the screen if the screen is going to be completely covered up with objects. If your scene doesn't cover the entire screen however you can end up with something like this.</p><p><imgsrc="/learn-wgpu/assets/img/no-clear.753f913f.png"alt="./no-clear.png"></p></div><h2id="validation-errors"><ahref="#validation-errors"class="header-anchor">#</a> Validation Errors?</h2><p>If wgpu is using Vulkan on your machine, you may run into validation errors if you are running an older version of the Vulkan SDK. You should be using at least version <code>1.2.182</code> as older versions can give out some false positives. If errors persist, you may have encountered a bug in wgpu. You can post an issue at <ahref="https://github.com/gfx-rs/wgpu"target="_blank"rel="noopener noreferrer">https://github.com/gfx-rs/wgpu<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a></p><h2id="challenge"><ahref="#challenge"class="header-anchor">#</a> Challenge</h2><p>Modify the <code>input()</code> method to capture mouse events, and update the clear color using that. <em>Hint: you'll probably need to use <code>WindowEvent::CursorMoved</code></em>.</p><divid="wasm-example"><!----><button>Try Tutorial2_surface!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial2-surface/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"aria-current="page"class="active sidebar-link">Model Loading</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-in-the-res-folder"class="sidebar-link">Accessing files in the res folder</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-from-wasm"class="sidebar-link">Accessing files from WASM</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#loading-models-with-tobj"class="sidebar-link">Loading models with TOBJ</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-a-mesh"class="sidebar-link">Rendering a mesh</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#using-the-correct-textures"class="sidebar-link">Using the correct textures</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-the-entire-model"class="sidebar-link">Rendering the entire model</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="model-loading"><ahref="#model-loading"class="header-anchor">#</a> Model Loading</h1><p>Up to this point we've been creating our models manually. While this is an acceptable way to do this, but it's really slow if we want to include complex models with lots of polygons. Because of this, we're going modify our code to leverage the obj model format so that we can create a model in a software such as blender and display it in our code.</p><p>Our <code>main.rs</code> file is getting pretty cluttered, let's create a <code>model.rs</code> file that we can put our model loading code into.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading open"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"aria-current="page"class="active sidebar-link">Model Loading</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-in-the-res-folder"class="sidebar-link">Accessing files in the res folder</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#accessing-files-from-wasm"class="sidebar-link">Accessing files from WASM</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#loading-models-with-tobj"class="sidebar-link">Loading models with TOBJ</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-a-mesh"class="sidebar-link">Rendering a mesh</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#using-the-correct-textures"class="sidebar-link">Using the correct textures</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/beginner/tutorial9-models/#rendering-the-entire-model"class="sidebar-link">Rendering the entire model</a></li></ul></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="model-loading"><ahref="#model-loading"class="header-anchor">#</a> Model Loading</h1><p>Up to this point we've been creating our models manually. While this is an acceptable way to do this, it's really slow if we want to include complex models with lots of polygons. Because of this, we're going to modify our code to leverage the <code>.obj</code> model format so that we can create a model in software such as blender and display it in our code.</p><p>Our <code>lib.rs</code> file is getting pretty cluttered, let's create a <code>model.rs</code> file that we can put our model loading code into.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// model.rs</span>
</code></pre></div><p>You'll notice a couple of things here. In <code>main.rs</code> we had <code>Vertex</code> as a struct, here we're using a trait. We could have multiple vertex types (model, UI, instance data, etc.). Making <code>Vertex</code> a trait will allow us to abstract our the <code>VertexBufferLayout</code> creation code to make creating <code>RenderPipeline</code>s simpler.</p><p>Another thing to mention is the <code>normal</code> field in <code>ModelVertex</code>. We won't use this until we talk about lighting, but will add it to the struct for now.</p><p>Let's define our <code>VertexBufferLayout</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">Vertex</span><spanclass="token keyword">for</span><spanclass="token class-name">ModelVertex</span><spanclass="token punctuation">{</span>
</code></pre></div><p>You'll notice a couple of things here. In <code>lib.rs</code> we had <code>Vertex</code> as a struct, here we're using a trait. We could have multiple vertex types (model, UI, instance data, etc.). Making <code>Vertex</code> a trait will allow us to abstract out the <code>VertexBufferLayout</code> creation code to make creating <code>RenderPipeline</code>s simpler.</p><p>Another thing to mention is the <code>normal</code> field in <code>ModelVertex</code>. We won't use this until we talk about lighting, but will add it to the struct for now.</p><p>Let's define our <code>VertexBufferLayout</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">Vertex</span><spanclass="token keyword">for</span><spanclass="token class-name">ModelVertex</span><spanclass="token punctuation">{</span>
</code></pre></div><p>This is basically the same as the original <code>VertexBufferLayout</code>, but we added a <code>VertexAttribute</code> for the <code>normal</code>. Remove the <code>Vertex</code> struct in <code>main.rs</code> as we won't need it anymore, and use our new <code>Vertex</code> from model for the <code>RenderPipeline</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> render_pipeline <spanclass="token operator">=</span> device<spanclass="token punctuation">.</span><spanclass="token function">create_render_pipeline</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token namespace">wgpu<spanclass="token punctuation">::</span></span><spanclass="token class-name">RenderPipelineDescriptor</span><spanclass="token punctuation">{</span>
</code></pre></div><p>This is basically the same as the original <code>VertexBufferLayout</code>, but we added a <code>VertexAttribute</code> for the <code>normal</code>. Remove the <code>Vertex</code> struct in <code>lib.rs</code> as we won't need it anymore, and use our new <code>Vertex</code> from <code>model</code> for the <code>RenderPipeline</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">let</span> render_pipeline <spanclass="token operator">=</span> device<spanclass="token punctuation">.</span><spanclass="token function">create_render_pipeline</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token namespace">wgpu<spanclass="token punctuation">::</span></span><spanclass="token class-name">RenderPipelineDescriptor</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Since the <code>desc</code> method is implemented on the <code>Vertex</code> trait, the trait needs to be imported before the method will be accessible. Put the import towards the top of the file with the others.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">model<spanclass="token punctuation">::</span></span><spanclass="token class-name">Vertex</span><spanclass="token punctuation">;</span>
</code></pre></div><p>With all that in place we need a model to render. If you have one already that's great, but I've supplied a <ahref="https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/res/cube.zip"target="_blank"rel="noopener noreferrer">zip file<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> with the model and all of it's textures. We're going to put this model in a new <code>res</code> folder next to the existing <code>src</code> folder.</p><h2id="accessing-files-in-the-res-folder"><ahref="#accessing-files-in-the-res-folder"class="header-anchor">#</a> Accessing files in the res folder</h2><p>When cargo builds and runs our program it sets what's known as the current working directory. This directory is usually the folder containing your projects root <code>Cargo.toml</code>. The path to our res folder may differ depending on the structure of the project. In the <code>res</code> folder for the example code for this section tutorial is at <code>code/beginner/tutorial9-models/res/</code>. When loading our model we could use this path, and just append <code>cube.obj</code>. This is fine, but if we change our projects structure, our code will break.</p><p>We're going to fix that by modifying our build script to copy our <code>res</code> folder to where cargo creates our executable, and we'll reference it from there. Create a file called <code>build.rs</code> and add the following:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">anyhow<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><p>With all that in place, we need a model to render. If you have one already that's great, but I've supplied a <ahref="https://github.com/sotrh/learn-wgpu/blob/master/code/beginner/tutorial9-models/res/cube.zip"target="_blank"rel="noopener noreferrer">zip file<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> with the model and all of its textures. We're going to put this model in a new <code>res</code> folder next to the existing <code>src</code> folder.</p><h2id="accessing-files-in-the-res-folder"><ahref="#accessing-files-in-the-res-folder"class="header-anchor">#</a> Accessing files in the res folder</h2><p>When cargo builds and runs our program it sets what's known as the current working directory. This directory is usually the folder containing your project's root <code>Cargo.toml</code>. The path to our res folder may differ depending on the structure of the project. In the <code>res</code> folder for the example code for this section tutorial is at <code>code/beginner/tutorial9-models/res/</code>. When loading our model we could use this path, and just append <code>cube.obj</code>. This is fine, but if we change our project's structure, our code will break.</p><p>We're going to fix that by modifying our build script to copy our <code>res</code> folder to where cargo creates our executable, and we'll reference it from there. Create a file called <code>build.rs</code> and add the following:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">anyhow<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="accessing-files-from-wasm"><ahref="#accessing-files-from-wasm"class="header-anchor">#</a> Accessing files from WASM</h2><p>By design, you can't access files on a users filesystem in Web Assembly. Instead we'll serve those files up using a web serve, and then load those files into our code using an http request. In order to simplify this, let's create a file called <code>resources.rs</code> to handle this for us. We'll create two functions that will load text files and binary files respectively.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>io<spanclass="token punctuation">::</span></span><spanclass="token punctuation">{</span><spanclass="token class-name">BufReader</span><spanclass="token punctuation">,</span><spanclass="token class-name">Cursor</span><spanclass="token punctuation">}</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="accessing-files-from-wasm"><ahref="#accessing-files-from-wasm"class="header-anchor">#</a> Accessing files from WASM</h2><p>By design, you can't access files on a user's filesystem in Web Assembly. Instead, we'll serve those files up using a web serve, and then load those files into our code using an http request. In order to simplify this, let's create a file called <code>resources.rs</code> to handle this for us. We'll create two functions that will load text files and binary files respectively.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">std<spanclass="token punctuation">::</span>io<spanclass="token punctuation">::</span></span><spanclass="token punctuation">{</span><spanclass="token class-name">BufReader</span><spanclass="token punctuation">,</span><spanclass="token class-name">Cursor</span><spanclass="token punctuation">}</span><spanclass="token punctuation">;</span>
</code></pre></div><divclass="note"><p>We're using <code>OUT_DIR</code> on desktop to get at our <code>res</code> folder.</p></div><p>I'm using <ahref="https://docs.rs/reqwest"target="_blank"rel="noopener noreferrer">reqwest<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> to handle loading the requests when using WASM. Add the following to the Cargo.toml:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">target.'cfg(target_arch = "wasm32")'.dependencies</span><spanclass="token punctuation">]</span>
</code></pre></div><divclass="note"><p>We're using <code>OUT_DIR</code> on desktop to get to our <code>res</code> folder.</p></div><p>I'm using <ahref="https://docs.rs/reqwest"target="_blank"rel="noopener noreferrer">reqwest<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> to handle loading the requests when using WASM. Add the following to the Cargo.toml:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token punctuation">[</span><spanclass="token table class-name">target.'cfg(target_arch = "wasm32")'.dependencies</span><spanclass="token punctuation">]</span>
<spanclass="token comment"># Other dependencies</span>
</code></pre></div><p>We'll also need to add the <code>Location</code> feature to <code>web-sys</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token key property">web-sys</span><spanclass="token punctuation">=</span><spanclass="token punctuation">{</span><spanclass="token key property">version</span><spanclass="token punctuation">=</span><spanclass="token string">"0.3"</span><spanclass="token punctuation">,</span><spanclass="token key property">features</span><spanclass="token punctuation">=</span><spanclass="token punctuation">[</span>
</code></pre></div><p>We could have put this methods in an <code>impl Model</code>, but I felt it made more sense to have the <code>RenderPass</code> do all the rendering, as that's kind of it's job. This does mean we have to import <code>DrawModel</code> when we go to render though.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// lib.rs</span>
</code></pre></div><p>We could have put these methods in an <code>impl Model</code>, but I felt it made more sense to have the <code>RenderPass</code> do all the rendering, as that's kind of its job. This does mean we have to import <code>DrawModel</code> when we go to render though.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// lib.rs</span>
</code></pre></div><p>With all that in place we should get the following.</p><p><imgsrc="/learn-wgpu/assets/img/cubes-correct.2db711eb.png"alt="cubes-correct.png"></p><h2id="rendering-the-entire-model"><ahref="#rendering-the-entire-model"class="header-anchor">#</a> Rendering the entire model</h2><p>Right now we are specifying the mesh and the material directly. This is useful if we want to draw a mesh with a different material. We're also not rendering other parts of the model (if we had some). Let's create a method for <code>DrawModel</code> that will draw all the parts of the model with their respective materials.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token type-definition class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><p>With all that in place, we should get the following.</p><p><imgsrc="/learn-wgpu/assets/img/cubes-correct.2db711eb.png"alt="cubes-correct.png"></p><h2id="rendering-the-entire-model"><ahref="#rendering-the-entire-model"class="header-anchor">#</a> Rendering the entire model</h2><p>Right now we are specifying the mesh and the material directly. This is useful if we want to draw a mesh with a different material. We're also not rendering other parts of the model (if we had some). Let's create a method for <code>DrawModel</code> that will draw all the parts of the model with their respective materials.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">pub</span><spanclass="token keyword">trait</span><spanclass="token type-definition class-name">DrawModel</span><spanclass="token operator"><</span><spanclass="token lifetime-annotation symbol">'a</span><spanclass="token operator">></span><spanclass="token punctuation">{</span>
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><p>I've been putting this off for a while. Implementing a camera isn't specifically related to using WGPU properly, but it's been bugging me so let's do it.</p><p><code>main.rs</code> is getting a little crowded, so let's create a <code>camera.rs</code> file to put our camera code. The first thing we're going to put in it in is some imports and our <code>OPENGL_TO_WGPU_MATRIX</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">cgmath<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><p>I've been putting this off for a while. Implementing a camera isn't specifically related to using WGPU properly, but it's been bugging me so let's do it.</p><p><code>main.rs</code> is getting a little crowded, so let's create a <code>camera.rs</code> file to put our camera code. The first things we're going to put in it are some imports and our <code>OPENGL_TO_WGPU_MATRIX</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">use</span><spanclass="token namespace">cgmath<spanclass="token punctuation">::</span></span><spanclass="token operator">*</span><spanclass="token punctuation">;</span>
</code></pre></div><divclass="note"><p><code>std::time::Instant</code> panics on WASM, so we'll use the <ahref="https://docs.rs/instant"target="_blank"rel="noopener noreferrer">instant crate<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a>. You'll want to include it in your <code>Cargo.toml</code>:</p><divclass="language-toml extra-class"><preclass="language-toml"><code><spanclass="token key property">instant</span><spanclass="token punctuation">=</span><spanclass="token string">"0.1"</span>
</code></pre></div></div><h2id="the-camera"><ahref="#the-camera"class="header-anchor">#</a> The Camera</h2><p>Next we need create a new <code>Camera</code> struct. We're going to be using a FPS style camera, so we'll store the position and the yaw (horizontal rotation), and pitch (vertical rotation). We'll have a <code>calc_matrix</code> method to create our view matrix.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div></div><h2id="the-camera"><ahref="#the-camera"class="header-anchor">#</a> The Camera</h2><p>Next, we need to create a new <code>Camera</code> struct. We're going to be using an FPS-style camera, so we'll store the position and the yaw (horizontal rotation), and pitch (vertical rotation). We'll have a <code>calc_matrix</code> method to create our view matrix.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div><p>On thing to note: <code>cgmath</code> currently returns a right-handed projection matrix from the <code>perspective</code> function. This means that the z-axis points out of the screen. If you want the z-axis to be <em>into</em> the screen (aka. a left-handed projection matrix), you'll have to code your own.</p><p>You can tell the difference between a right-handed coordinate system and a left-handed one by using your hands. Point your thumb to the right. This is the x-axis. Point your pointer finger up. This is the y-axis. Extend your middle finger. This is the z-axis. On your right hand your middle finger should be pointing towards you. On your left hand it should be pointing away.</p><p><imgsrc="/learn-wgpu/assets/img/left_right_hand.ccabf5d0.gif"alt="./left_right_hand.gif"></p><h1id="the-camera-controller"><ahref="#the-camera-controller"class="header-anchor">#</a> The Camera Controller</h1><p>Our camera is different, so we'll need a new camera controller. Add the following to <code>camera.rs</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div><p>One thing to note: <code>cgmath</code> currently returns a right-handed projection matrix from the <code>perspective</code> function. This means that the z-axis points out of the screen. If you want the z-axis to be <em>into</em> the screen (aka. a left-handed projection matrix), you'll have to code your own.</p><p>You can tell the difference between a right-handed coordinate system and a left-handed one by using your hands. Point your thumb to the right. This is the x-axis. Point your pointer finger up. This is the y-axis. Extend your middle finger. This is the z-axis. On your right hand, your middle finger should be pointing towards you. On your left hand, it should be pointing away.</p><p><imgsrc="/learn-wgpu/assets/img/left_right_hand.ccabf5d0.gif"alt="./left_right_hand.gif"></p><h1id="the-camera-controller"><ahref="#the-camera-controller"class="header-anchor">#</a> The Camera Controller</h1><p>Our camera is different, so we'll need a new camera controller. Add the following to <code>camera.rs</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[derive(Debug)]</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. Up to this point we have been using <code>WindowEvent</code>s for our camera controls. While this works, it's not the best solution. The <ahref="https://docs.rs/winit/0.24.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved"target="_blank"rel="noopener noreferrer">winit docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration.</p><p>Now to fix this we could change the <code>input()</code> function to process <code>DeviceEvent</code> instead of <code>WindowEvent</code>, but keyboard and button presses don't get emitted as <code>DeviceEvent</code>s on MacOS and WASM. Instead, we'll just remove the <code>CursorMoved</code> check in <code>input()</code>, and a manual call to <code>camera_controller.process_mouse()</code> in the <code>run()</code> function.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// UPDATED!</span>
</code></pre></div><p><code>input()</code> will need to be updated as well. Up to this point, we have been using <code>WindowEvent</code>s for our camera controls. While this works, it's not the best solution. The <ahref="https://docs.rs/winit/0.24.0/winit/event/enum.WindowEvent.html?search=#variant.CursorMoved"target="_blank"rel="noopener noreferrer">winit docs<span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></a> inform us that OS will often transform the data for the <code>CursorMoved</code> event to allow effects such as cursor acceleration.</p><p>Now to fix this we could change the <code>input()</code> function to process <code>DeviceEvent</code> instead of <code>WindowEvent</code>, but keyboard and button presses don't get emitted as <code>DeviceEvent</code>s on MacOS and WASM. Instead, we'll just remove the <code>CursorMoved</code> check in <code>input()</code>, and a manual call to <code>camera_controller.process_mouse()</code> in the <code>run()</code> function.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// UPDATED!</span>
</code></pre></div><p>The <code>update</code> function requires a bit more explanation. The <code>update_camera</code> function on the <code>CameraController</code> has a parameter <code>dt: Duration</code> which is the delta time or time between frames. This is to help smooth out the camera movement so that it's not locked be the framerate. Currently we aren't calculating <code>dt</code>, so I decided to pass it into <code>update</code> as a parameter.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">update</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token keyword">mut</span><spanclass="token keyword">self</span><spanclass="token punctuation">,</span> dt<spanclass="token punctuation">:</span><spanclass="token namespace">instant<spanclass="token punctuation">::</span></span><spanclass="token class-name">Duration</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>The <code>update</code> function requires a bit more explanation. The <code>update_camera</code> function on the <code>CameraController</code> has a parameter <code>dt: Duration</code> which is the delta time or time between frames. This is to help smooth out the camera movement so that it's not locked by the framerate. Currently, we aren't calculating <code>dt</code>, so I decided to pass it into <code>update</code> as a parameter.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">fn</span><spanclass="token function-definition function">update</span><spanclass="token punctuation">(</span><spanclass="token operator">&</span><spanclass="token keyword">mut</span><spanclass="token keyword">self</span><spanclass="token punctuation">,</span> dt<spanclass="token punctuation">:</span><spanclass="token namespace">instant<spanclass="token punctuation">::</span></span><spanclass="token class-name">Duration</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>With that we should be able to move our camera wherever we want.</p><p><imgsrc="/learn-wgpu/assets/img/screenshot.4f5740bc.png"alt="./screenshot.png"></p><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>With that, we should be able to move our camera wherever we want.</p><p><imgsrc="/learn-wgpu/assets/img/screenshot.4f5740bc.png"alt="./screenshot.png"></p><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial12-camera/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><p>The main selling point of Vulkan, DirectX 12, Metal, and by extension Wgpu is that these APIs is that they designed from the ground up to be thread safe. Up to this point we have been doing everything on a single thread. That's about to change.</p><divclass="note"><p>I won't go into what threads are in this tutorial. That is a course in and of itself. All we'll be covering is using threading to make loading resources faster.</p><p>We won't go over multithreading rendering as we don't have enough different types of objects to justify that yet. This will change in a coming tutorial</p></div><h2id="parallelizing-loading-models-and-textures"><ahref="#parallelizing-loading-models-and-textures"class="header-anchor">#</a> Parallelizing loading models and textures</h2><p>Currently we load the materials and meshes of our model one at a time. This is a perfect opportunity for multithreading! All our changes will be in <code>model.rs</code>. Let's first start with the materials. We'll convert the regular for loop into a <code>par_iter().map()</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// resources.rs</span>
</code></pre></div><p>Once 0.13 comes out I'll revert to using the version published on crates.io.</p></div><p>The main selling point of Vulkan, DirectX 12, Metal, and by extension Wgpu is that these APIs is that they designed from the ground up to be thread safe. Up to this point, we have been doing everything on a single thread. That's about to change.</p><divclass="note"><p>I won't go into what threads are in this tutorial. That is a course in and of itself. All we'll be covering is using threading to make loading resources faster.</p><p>We won't go over multithreading rendering as we don't have enough different types of objects to justify that yet. This will change in a coming tutorial</p></div><h2id="parallelizing-loading-models-and-textures"><ahref="#parallelizing-loading-models-and-textures"class="header-anchor">#</a> Parallelizing loading models and textures</h2><p>Currently, we load the materials and meshes of our model one at a time. This is a perfect opportunity for multithreading! All our changes will be in <code>model.rs</code>. Let's first start with the materials. We'll convert the regular for loop into a <code>par_iter().map()</code>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token comment">// resources.rs</span>
</code></pre></div><p>Next we can update the meshes to be loaded in parallel.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">Model</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Next, we can update the meshes to be loaded in parallel.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">impl</span><spanclass="token class-name">Model</span><spanclass="token punctuation">{</span>
</code></pre></div><p>We've parallelized loading the meshes, and making the vertex array for them. Probably a bit overkill, but <code>rayon</code> should prevent us from using too many threads.</p><divclass="note"><p>You'll notice that we didn't use <code>rayon</code> for calculating the tangent, and bitangent. I tried to get it to work, but I was having trouble finding a way to do it without multiple mutable references to <code>vertices</code>. I don't feel like introducing a <code>std::sync::Mutex</code>, so I'll leave it for now.</p><p>This is honestly a better job for a compute shader, as the model data is going to get loaded into a buffer anyway.</p></div><h2id="it-s-that-easy"><ahref="#it-s-that-easy"class="header-anchor">#</a> It's that easy!</h2><p>Most of the <code>wgpu</code> types are <code>Send + Sync</code>, so we can use them in threads without much trouble. It was so easy, that I feel like this tutorial is too short! I'll just leave off with a speed comparison between the previous model loading code and the current code.</p><divclass="language- extra-class"><preclass="language-text"><code>Elapsed (Original): 309.596382ms
Elapsed (Threaded): 199.645027ms
</code></pre></div><p>We're not loading that many resources, so the speedup is minimal. We'll be doing more stuff with threading, but this is a good introduction.</p><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial13-threading/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><!----></main></div></div><divclass="global-ui"><!----></div></div>
</code></pre></div><p>We're not loading that many resources, so the speedup is minimal. We'll be doing more stuff with threading, but this is a good introduction.</p><divid="wasm-example"><!----><button>Try Tutorial12_camera!</button></div><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/intermediate/tutorial13-threading/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><!----></main></div></div><divclass="global-ui"><!----></div></div>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>News</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/news/0.12/"aria-current="page"class="active sidebar-link">Update to 0.12!</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#multi-view-added"class="sidebar-link">Multi view added</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#no-more-block-attribute"class="sidebar-link">No more block attribute</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#more-validation"class="sidebar-link">More validation</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#misc"class="sidebar-link">Misc</a></li></ul></li><li><ahref="/learn-wgpu/news/pre-0.12/"class="sidebar-link">News (Pre 0.12)</a></li></ul></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="update-to-0-12"><ahref="#update-to-0-12"class="header-anchor">#</a> Update to 0.12!</h1><p>There's not a ton of changes in this release, so the migration
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>Showcase</span><spanclass="arrow right"></span></p><!----></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>News</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/news/0.12/"aria-current="page"class="active sidebar-link">Update to 0.12!</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#multi-view-added"class="sidebar-link">Multi view added</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#no-more-block-attribute"class="sidebar-link">No more block attribute</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#more-validation"class="sidebar-link">More validation</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/news/0.12/#misc"class="sidebar-link">Misc</a></li></ul></li><li><ahref="/learn-wgpu/news/pre-0.12/"class="sidebar-link">News (Pre 0.12)</a></li></ul></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="update-to-0-12"><ahref="#update-to-0-12"class="header-anchor">#</a> Update to 0.12!</h1><p>There are not a ton of changes in this release, so the migration
wasn't too painful.</p><h2id="multi-view-added"><ahref="#multi-view-added"class="header-anchor">#</a> Multi view added</h2><p>The <code>RenderPipelineDescriptor</code> now includes a <code>multiview</code> field that
indicates the number of array textures if array textures are used
as render attachments.</p><h2id="no-more-block-attribute"><ahref="#no-more-block-attribute"class="header-anchor">#</a> No more block attribute</h2><p>The WGSL spec has changed and the <code>block</code> attribute is no longer a thing.
This means that structs in WGSL no longer need to be anotated to be used
This means that structs in WGSL no longer need to be annotated to be used
as uniform input. For example:</p><divclass="language-wgsl extra-class"><preclass="language-text"><code>[[block]]
struct Camera {
view_pos: vec4<f32>;
@ -61,7 +61,7 @@ I needed to do was add a padding field:</p> <div class="language-rust extra-clas
breaks glob imports (aka. <code>use anyhow::*</code>), I had to switch qualified
imports and uses (ie. <code>anyhow::Result</code>). This was mostly an issue on my
build scripts for some of the showcase examples.</p><p>The main tutorial examples weren't affected, and the changes are minor, so
if your curious feel free to look at the repo.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
if you're curious feel free to look at the repo.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"aria-current="page"class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"aria-current="page"class="active sidebar-link">Compute Example: Tangents and Bitangents</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#possible-improvements"class="sidebar-link">Possible Improvements</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#results"class="sidebar-link">Results</a></li></ul></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="compute-example-tangents-and-bitangents"><ahref="#compute-example-tangents-and-bitangents"class="header-anchor">#</a> Compute Example: Tangents and Bitangents</h1><p>This proved more difficult than I anticipated. The first problem I encountered was some vertex data corruption due to the shader reading my vertex data incorrectly. I was using my<code>ModelVertex</code> struct I used in the <ahref="/learn-wgpu/intermediate/tutorial11-normals/">normal mapping tutorial</a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[repr(C)]</span>
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"aria-current="page"class="sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"aria-current="page"class="active sidebar-link">Compute Example: Tangents and Bitangents</a><ulclass="sidebar-sub-headers"><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#possible-improvements"class="sidebar-link">Possible Improvements</a></li><liclass="sidebar-sub-header"><ahref="/learn-wgpu/showcase/compute/#results"class="sidebar-link">Results</a></li></ul></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="compute-example-tangents-and-bitangents"><ahref="#compute-example-tangents-and-bitangents"class="header-anchor">#</a> Compute Example: Tangents and Bitangents</h1><p>This proved more difficult than I anticipated. The first problem I encountered was some vertex data corruption due to the shader reading my vertex data incorrectly. I was using the<code>ModelVertex</code> struct I used in the <ahref="/learn-wgpu/intermediate/tutorial11-normals/">normal mapping tutorial</a>.</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token attribute attr-name">#[repr(C)]</span>
</code></pre></div><p>At first glance, this seems just fine, but OpenGL experts would likely see a problem with the structure. Our fields aren't aligned properly to support the <code>std430</code> alignment that storage buffers require.. I won't get into detail but you can check out the <ahref="../alignment">alignment showcase</a> if you want to know more. To summarize, the <code>vec2</code> for the <code>tex_coords</code> was messing up the byte alignment, corrupting the vertex data resulting in the following:</p><p><imgsrc="/learn-wgpu/assets/img/corruption.675b1eca.png"alt="./corruption.png"></p><p>I could have fixed this by adding a padding field after <code>tex_coords</code> on the Rust side, but that would require modifying the <code>VertexBufferLayout</code>. I ended up solving this problem by using the components of the vectors directly and resulted with a struct like this:</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code><spanclass="token keyword">struct</span><spanclass="token class-name">ModelVertex</span><spanclass="token punctuation">{</span>
</code></pre></div><p>At first glance, this seems just fine, but OpenGL experts would likely see a problem with the structure. Our fields aren't aligned properly to support the <code>std430</code> alignment that storage buffers require. I won't get into detail but you can check out the <ahref="../alignment">alignment showcase</a> if you want to know more. To summarize, the <code>vec2</code> for the <code>tex_coords</code> was messing up the byte alignment, corrupting the vertex data resulting in the following:</p><p><imgsrc="/learn-wgpu/assets/img/corruption.675b1eca.png"alt="./corruption.png"></p><p>I could have fixed this by adding a padding field after <code>tex_coords</code> on the Rust side, but that would require modifying the <code>VertexBufferLayout</code>. I ended up solving this problem by using the components of the vectors directly which resulted in a struct like this:</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code><spanclass="token keyword">struct</span><spanclass="token class-name">ModelVertex</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Since <code>std430</code> will use the alignment of the largest element of the struct, using all floats means the struct will be aligned to 4 bytes. This is alignment matches what <code>ModelVertex</code> uses in Rust. This was kind of a pain to work with, but it fixed the corruption issue.</p><p>The second problem required me to rethink how I was computing the tangent and bitangent. The previous algorithm I was using only computed the tangent and bitangent for each triangle and set all the vertices in that triangle to use the same tangent and bitangent. While this is fine in a singlethreaded context, the code breaks down when trying to compute the triangles in parallel. The reason is that multiple triangles can share the same vertices. This means that when we go to save the resulting tangents, we inevitably end up trying to write to the same vertex from multiple different threads which is a big no no. You can see the issue with this method below:</p><p><imgsrc="/learn-wgpu/assets/img/black_triangles.df338b97.png"alt="./black_triangles.png"></p><p>Those black triangles were the result of multiple GPU threads trying to modify the same vertices. Looking at the data in Render Doc I could see that the tangents and bitangents were garbage numbers such as <code>NaN</code>.</p><p><imgsrc="/learn-wgpu/assets/img/render_doc_output.e0c8b298.png"alt="./render_doc_output.png"></p><p>While on the CPU we could introduce a synchronization primitive such as a <code>Mutex</code> to fix this issue, AFAIK there isn't really such a thing on the GPU. Instead I decided to swap my code to work with each vertex individually. There are some hurdles with that, but those will be easier to explain in code. Let's start with the <code>main</code> function.</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code><spanclass="token keyword">void</span><spanclass="token function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>Since <code>std430</code> will use the alignment of the largest element of the struct, using all floats means the struct will be aligned to 4 bytes. This is alignment matches what <code>ModelVertex</code> uses in Rust. This was kind of a pain to work with, but it fixed the corruption issue.</p><p>The second problem required me to rethink how I was computing the tangent and bitangent. The previous algorithm I was using only computed the tangent and bitangent for each triangle and set all the vertices in that triangle to use the same tangent and bitangent. While this is fine in a single-threaded context, the code breaks down when trying to compute the triangles in parallel. The reason is that multiple triangles can share the same vertices. This means that when we go to save the resulting tangents, we inevitably end up trying to write to the same vertex from multiple different threads which is a big no no. You can see the issue with this method below:</p><p><imgsrc="/learn-wgpu/assets/img/black_triangles.df338b97.png"alt="./black_triangles.png"></p><p>Those black triangles were the result of multiple GPU threads trying to modify the same vertices. Looking at the data in Render Doc I could see that the tangents and bitangents were garbage numbers such as <code>NaN</code>.</p><p><imgsrc="/learn-wgpu/assets/img/render_doc_output.e0c8b298.png"alt="./render_doc_output.png"></p><p>While on the CPU we could introduce a synchronization primitive such as a <code>Mutex</code> to fix this issue, AFAIK there isn't really such a thing on the GPU. Instead, I decided to swap my code to work with each vertex individually. There are some hurdles with that, but those will be easier to explain in code. Let's start with the <code>main</code> function.</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code><spanclass="token keyword">void</span><spanclass="token function">main</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>We use the <code>gl_GlobalInvocationID.x</code> to get the index of the vertex we want to compute the tangents for. I opted to put the actual calculation into it's own method. Let's take a look at that.</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code>ModelVertex <spanclass="token function">calcTangentBitangent</span><spanclass="token punctuation">(</span><spanclass="token keyword">uint</span> vertexIndex<spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
</code></pre></div><p>We use the <code>gl_GlobalInvocationID.x</code> to get the index of the vertex we want to compute the tangents for. I opted to put the actual calculation into its own method. Let's take a look at that.</p><divclass="language-glsl extra-class"><preclass="language-glsl"><code>ModelVertex <spanclass="token function">calcTangentBitangent</span><spanclass="token punctuation">(</span><spanclass="token keyword">uint</span> vertexIndex<spanclass="token punctuation">)</span><spanclass="token punctuation">{</span>
ModelVertex v <spanclass="token operator">=</span> srcVertices<spanclass="token punctuation">[</span>vertexIndex<spanclass="token punctuation">]</span><spanclass="token punctuation">;</span>
</code></pre></div><h2id="possible-improvements"><ahref="#possible-improvements"class="header-anchor">#</a> Possible Improvements</h2><p>Looping over every triangle for every vertex is likely raising some red flags for some of you. In a singlethreaded context, this algorithm would end up being O(N*M). As we are utilizing the high number of threads available to our GPU, this is less of an issue, but it still means our GPU is burning more cycles than it needs to.</p><p>One way I came up with to possibly improve performance is to store the index of each triangle in a hash map like structure with the vertex index as keys. Here's some pseudo code:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">for</span> t <spanclass="token keyword">in</span><spanclass="token number">0</span><spanclass="token punctuation">..</span>indices<spanclass="token punctuation">.</span><spanclass="token function">len</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token operator">/</span><spanclass="token number">3</span><spanclass="token punctuation">{</span>
</code></pre></div><h2id="possible-improvements"><ahref="#possible-improvements"class="header-anchor">#</a> Possible Improvements</h2><p>Looping over every triangle for every vertex is likely raising some red flags for some of you. In a single-threaded context, this algorithm would end up being O(N*M). As we are utilizing the high number of threads available to our GPU, this is less of an issue, but it still means our GPU is burning more cycles than it needs to.</p><p>One way I came up with to possibly improve performance is to store the index of each triangle in a hash map like structure with the vertex index as keys. Here's some pseudo code:</p><divclass="language-rust extra-class"><preclass="language-rust"><code><spanclass="token keyword">for</span> t <spanclass="token keyword">in</span><spanclass="token number">0</span><spanclass="token punctuation">..</span>indices<spanclass="token punctuation">.</span><spanclass="token function">len</span><spanclass="token punctuation">(</span><spanclass="token punctuation">)</span><spanclass="token operator">/</span><spanclass="token number">3</span><spanclass="token punctuation">{</span>
</code></pre></div><p>I ultimately decided against this method as it was more complicated, and I haven't had time to benchmark it to see if it's faster that the simple method.</p><h2id="results"><ahref="#results"class="header-anchor">#</a> Results</h2><p>The tangents and bitangents are now getting calculated correctly and on the GPU!</p><p><imgsrc="/learn-wgpu/assets/img/results.7918efc1.png"alt="./results.png"></p><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/showcase/compute/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
</code></pre></div><p>I ultimately decided against this method as it was more complicated, and I haven't had time to benchmark it to see if it's faster than the simple method.</p><h2id="results"><ahref="#results"class="header-anchor">#</a> Results</h2><p>The tangents and bitangents are now getting calculated correctly and on the GPU!</p><p><imgsrc="/learn-wgpu/assets/img/results.7918efc1.png"alt="./results.png"></p><divclass="auto-github-link"><ahref="https://github.com/sotrh/learn-wgpu/tree/master/code/showcase/compute/"target="_blank"rel="noopener noreferrer">Check out the code!</a><span><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"focusable="false"x="0px"y="0px"viewBox="0 0 100 100"width="15"height="15"class="icon outbound"><pathfill="currentColor"d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygonfill="currentColor"points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><spanclass="sr-only">(opens new window)</span></span></div></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"aria-current="page"class="active sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="foreword"><ahref="#foreword"class="header-anchor">#</a> Foreword</h1><p>The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with <code>wgpu</code>. I won't go over specifics of creating <code>wgpu</code> resources, as those will be covered elsewhere. The code for these examples is still available however, and will be accessible on Github.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:41:58 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">
<divid="app"data-server-rendered="true"><divclass="theme-container"><headerclass="navbar"><divclass="inner"><divclass="sidebar-button"><svgxmlns="http://www.w3.org/2000/svg"aria-hidden="true"role="img"viewBox="0 0 448 512"class="icon"><pathfill="currentColor"d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><ahref="/learn-wgpu/"class="home-link router-link-active"><!----><spanclass="site-name">Learn Wgpu</span></a><divclass="links"><!----><divclass="search-box"><inputaria-label="Search"autocomplete="off"spellcheck="false"value=""><!----></div></div></div></header><divclass="sidebar-mask"></div><divclass="docs-layout"><asideclass="sidebar"><!----><ulclass="sidebar-links"><li><ahref="/learn-wgpu/"aria-current="page"class="sidebar-link">Introduction</a></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Beginner</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/beginner/tutorial1-window/"class="sidebar-link">Dependencies and the window</a></li><li><ahref="/learn-wgpu/beginner/tutorial2-surface/"class="sidebar-link">The Surface</a></li><li><ahref="/learn-wgpu/beginner/tutorial3-pipeline/"class="sidebar-link">The Pipeline</a></li><li><ahref="/learn-wgpu/beginner/tutorial4-buffer/"class="sidebar-link">Buffers and Indices</a></li><li><ahref="/learn-wgpu/beginner/tutorial5-textures/"class="sidebar-link">Textures and bind groups</a></li><li><ahref="/learn-wgpu/beginner/tutorial6-uniforms/"class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><ahref="/learn-wgpu/beginner/tutorial7-instancing/"class="sidebar-link">Instancing</a></li><li><ahref="/learn-wgpu/beginner/tutorial8-depth/"class="sidebar-link">The Depth Buffer</a></li><li><ahref="/learn-wgpu/beginner/tutorial9-models/"class="sidebar-link">Model Loading</a></li></ul></section></li><li><sectionclass="sidebar-group depth-0"><pclass="sidebar-heading"><span>Intermediate</span><!----></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/intermediate/tutorial10-lighting/"class="sidebar-link">Working with Lights</a></li><li><ahref="/learn-wgpu/intermediate/tutorial11-normals/"class="sidebar-link">Normal Mapping</a></li><li><ahref="/learn-wgpu/intermediate/tutorial12-camera/"class="sidebar-link">A Better Camera</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading open"><span>Showcase</span><spanclass="arrow down"></span></p><ulclass="sidebar-links sidebar-group-items"><li><ahref="/learn-wgpu/showcase/"aria-current="page"class="active sidebar-link">Foreword</a></li><li><ahref="/learn-wgpu/showcase/windowless/"class="sidebar-link">Wgpu without a window</a></li><li><ahref="/learn-wgpu/showcase/gifs/"class="sidebar-link">Creating gifs</a></li><li><ahref="/learn-wgpu/showcase/pong/"class="sidebar-link">Pong</a></li><li><ahref="/learn-wgpu/showcase/compute/"class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><ahref="/learn-wgpu/showcase/alignment/"class="sidebar-link">Memory Layout in WGSL</a></li></ul></section></li><li><sectionclass="sidebar-group collapsable depth-0"><pclass="sidebar-heading"><span>News</span><spanclass="arrow right"></span></p><!----></section></li></ul></aside><mainclass="page"><divclass="theme-default-content content__default"><h1id="foreword"><ahref="#foreword"class="header-anchor">#</a> Foreword</h1><p>The articles in this section are not meant to be tutorials. They are showcases of the various things you can do with <code>wgpu</code>. I won't go over the specifics of creating <code>wgpu</code> resources, as those will be covered elsewhere. The code for these examples is still available however and will be accessible on Github.</p></div><footerclass="page-edit"><!----><divclass="last-updated"><spanclass="prefix">Last Updated: </span><spanclass="time">5/14/2022, 6:44:34 PM</span></div></footer><divclass="page-nav"><pclass="inner"><spanclass="prev">