You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
learn-wgpu/showcase/alignment/index.html

52 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Memory Layout in WGSL | Learn Wgpu</title>
<meta name="generator" content="VuePress 1.9.10">
<meta name="description" content="">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.81cb5453.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.a49faced.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.2ef7287a.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/1.eaeeb819.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/65.362df98e.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.baf5d1fe.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.b8633c49.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.0b8835f1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.af1bbe85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.626c7cb3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.5a8ea302.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.f4e8226b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.dd15c417.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.4eb59bb5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.48960e96.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.a01dc53f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.5e81f33c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.caf73498.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.a01d50ae.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.9ed2104b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.1676676b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.fd4eb8d5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.914a9a40.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.77f7d987.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.ea2d6bbf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.80d94795.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.c58683af.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.74bc1dea.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.e6627282.js"><link rel="prefetch" href="/learn-wgpu/assets/js/33.945dce62.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.0fe8e5e4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.7c607f94.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.e6a8b391.js"><link rel="prefetch" href="/learn-wgpu/assets/js/37.5ecf7ce2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/38.b0253733.js"><link rel="prefetch" href="/learn-wgpu/assets/js/39.73123b03.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.ff267fdb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/40.30864a0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/41.47515217.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.4caac867.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.ac6fc643.js"><link rel="prefetch" href="/learn-wgpu/assets/js/44.27513d85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.2ea5b108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.e591bcb9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.3a7bf317.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.0a15e622.js"><link rel="prefetch" href="/learn-wgpu/assets/js/49.ad5a99aa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.250d79d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/50.05fd19ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/51.820d6108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/52.48268452.js"><link rel="prefetch" href="/learn-wgpu/assets/js/53.8c976652.js"><link rel="prefetch" href="/learn-wgpu/assets/js/54.daee63ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/55.3799ddaa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/56.a43d5d8e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/57.9cdfcb79.js"><link rel="prefetch" href="/learn-wgpu/assets/js/58.35b75a7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/59.5dd82339.js"><link rel="prefetch" href="/learn-wgpu/assets/js/60.1ced8124.js"><link rel="prefetch" href="/learn-wgpu/assets/js/61.f10516d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/62.24bfa87e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/63.90f94cac.js"><link rel="prefetch" href="/learn-wgpu/assets/js/64.b9a310af.js"><link rel="prefetch" href="/learn-wgpu/assets/js/66.ef1e3716.js"><link rel="prefetch" href="/learn-wgpu/assets/js/67.ab338058.js"><link rel="prefetch" href="/learn-wgpu/assets/js/68.d785413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.2c0d831a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.985bc61a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/vendors~docsearch.efa6f8ef.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.81cb5453.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="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> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" aria-current="page" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" class="sidebar-link">Dependencies and the window</a></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="sidebar-link">A Better Camera</a></li><li><a href="/learn-wgpu/intermediate/tutorial13-hdr/" class="sidebar-link">High Dynamic Range Rendering</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>Showcase</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/showcase/" aria-current="page" class="sidebar-link">Foreword</a></li><li><a href="/learn-wgpu/showcase/windowless/" class="sidebar-link">Wgpu without a window</a></li><li><a href="/learn-wgpu/showcase/gifs/" class="sidebar-link">Creating gifs</a></li><li><a href="/learn-wgpu/showcase/pong/" class="sidebar-link">Pong</a></li><li><a href="/learn-wgpu/showcase/compute/" class="sidebar-link">Compute Example: Tangents and Bitangents</a></li><li><a href="/learn-wgpu/showcase/alignment/" aria-current="page" class="active sidebar-link">Memory Layout in WGSL</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/alignment/#alignment-of-vertex-and-index-buffers" class="sidebar-link">Alignment of vertex and index buffers</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/alignment/#alignment-of-uniform-and-storage-buffers" class="sidebar-link">Alignment of Uniform and Storage buffers</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/alignment/#how-to-deal-with-alignment-issues" class="sidebar-link">How to deal with alignment issues</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/alignment/#additional-resources" class="sidebar-link">Additional resources</a></li></ul></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>News</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="memory-layout-in-wgsl"><a href="#memory-layout-in-wgsl" class="header-anchor">#</a> Memory Layout in WGSL</h1> <div class="warn"><p>This page is currently being reworked. I want to understand the topics a bit better, but as 0.12 is out I want to release what I have for now.</p></div> <h2 id="alignment-of-vertex-and-index-buffers"><a href="#alignment-of-vertex-and-index-buffers" class="header-anchor">#</a> Alignment of vertex and index buffers</h2> <p>Vertex buffers require defining a <code>VertexBufferLayout</code>, so the memory alignment is whatever you tell WebGPU it should be. This can be really convenient for keeping down memory usage on the GPU.</p> <p>The Index Buffer uses the alignment of whatever primitive type you specify via the <code>IndexFormat</code> you pass into <code>RenderEncoder::set_index_buffer()</code>.</p> <h2 id="alignment-of-uniform-and-storage-buffers"><a href="#alignment-of-uniform-and-storage-buffers" class="header-anchor">#</a> Alignment of Uniform and Storage buffers</h2> <p>GPUs are designed to process thousands of pixels in parallel. In order to achieve this, some sacrifices had to be made. Graphics hardware likes to have all the bytes you intend on processing aligned by powers of 2. The exact specifics of why this is are beyond my level of knowledge, but it's important to know so that you can troubleshoot why your shaders aren't working.</p> <p>Let's take a look at the following table:</p> <hr> <table><thead><tr><th>Type</th> <th>Alignment in Bytes</th> <th>Size in Bytes</th></tr></thead> <tbody><tr><td>scalar (i32, u32, f32)</td> <td>4</td> <td>4</td></tr> <tr><td>vec2&lt;T&gt;</td> <td>8</td> <td>8</td></tr> <tr><td>vec3&lt;T&gt;</td> <td><strong>16</strong></td> <td>12</td></tr> <tr><td>vec4&lt;T&gt;</td> <td>16</td> <td>16</td></tr></tbody></table> <p>You can see for <code>vec3</code> the alignment is the next power of 2 from the size, 16. This can catch beginners (and even veterans) off guard as it's not the most intuitive. This becomes especially important when we start laying out structs. Take the light struct from the <a href="/learn-wgpu/intermediate/tutorial10-lighting/#seeing-the-light">lighting tutorial</a>:</p> <p>You can see the full table of the alignments in section <a href="https://www.w3.org/TR/WGSL/#alignment-and-size" target="_blank" rel="noopener noreferrer">4.3.7.1 of the WGSL spec<span><svg xmlns="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"><path fill="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> <polygon fill="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> <span class="sr-only">(opens new window)</span></span></a></p> <div class="language-wgsl extra-class"><pre class="language-wgsl"><code><span class="token keyword">struct</span> <span class="token class-name">Light</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> <span class="token builtin">vec3</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
color<span class="token punctuation">:</span> <span class="token builtin">vec3</span><span class="token punctuation">&lt;</span><span class="token builtin">f32</span><span class="token punctuation">&gt;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>So what's the alignment of this struct? Your first guess would be that it's the sum of the alignments of the individual fields. That might make sense if we were in Rust-land, but in shader-land, it's a little more involved. The alignment for a given struct is given by the following equation:</p> <div class="language- extra-class"><pre class="language-text"><code>// S is the struct in question
// M is a member of the struct
AlignOf(S) = max(AlignOfMember(S, M1), ... , AlignOfMember(S, Mn))
</code></pre></div><p>Basically, the alignment of the struct is the maximum of the alignments of the members of the struct. This means that:</p> <div class="language- extra-class"><pre class="language-text"><code>AlignOf(Light)
= max(AlignOfMember(Light, position), AlignOfMember(Light, color))
= max(16, 16)
= 16
</code></pre></div><p>This is why the <code>LightUniform</code> has those padding fields. WGPU won't accept it if the data is not aligned correctly.</p> <h2 id="how-to-deal-with-alignment-issues"><a href="#how-to-deal-with-alignment-issues" class="header-anchor">#</a> How to deal with alignment issues</h2> <p>In general, 16 is the max alignment you'll see. In that case, you might think that we should be able to do something like the following:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[repr(C, align(16))]</span>
<span class="token attribute attr-name">#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]</span>
<span class="token keyword">struct</span> <span class="token type-definition class-name">LightUniform</span> <span class="token punctuation">{</span>
position<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
color<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token keyword">f32</span><span class="token punctuation">;</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><p>But this won't compile. The <a href="https://docs.rs/bytemuck/" target="_blank" rel="noopener noreferrer">bytemuck crate<span><svg xmlns="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"><path fill="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> <polygon fill="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> <span class="sr-only">(opens new window)</span></span></a> doesn't work with structs with implicit padding bytes. Rust can't guarantee that the memory between the fields has been initialized properly. This gave me an error when I tried it:</p> <div class="language- extra-class"><pre class="language-text"><code>error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--&gt; code/intermediate/tutorial10-lighting/src/main.rs:246:8
|
246 | struct LightUniform {
| ^^^^^^^^^^^^
|
= note: source type: `LightUniform` (256 bits)
= note: target type: `_::{closure#0}::TypeWithoutPadding` (192 bits)
</code></pre></div><h2 id="additional-resources"><a href="#additional-resources" class="header-anchor">#</a> Additional resources</h2> <p>If you're looking for more information check out the <a href="https://gist.github.com/teoxoy/936891c16c2a3d1c3c5e7204ac6cd76c" target="_blank" rel="noopener noreferrer">write-up<span><svg xmlns="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"><path fill="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> <polygon fill="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> <span class="sr-only">(opens new window)</span></span></a> by @teoxoy.</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/28/2023, 12:41:28 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/showcase/compute/" class="prev">
Compute Example: Tangents and Bitangents
</a></span> <span class="next"><a href="/learn-wgpu/news/0.18%20and%20hdr/">
Update to 0.18 and HDR tutorial
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.a49faced.js" defer></script><script src="/learn-wgpu/assets/js/2.2ef7287a.js" defer></script><script src="/learn-wgpu/assets/js/1.eaeeb819.js" defer></script><script src="/learn-wgpu/assets/js/65.362df98e.js" defer></script>
</body>
</html>