mirror of
https://github.com/sotrh/learn-wgpu.git
synced 2024-11-16 06:12:55 +00:00
322 lines
96 KiB
HTML
322 lines
96 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en-US">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>The Surface | Learn Wgpu</title>
|
|
<meta name="generator" content="VuePress 1.9.9">
|
|
|
|
<meta name="description" content="">
|
|
|
|
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.0ab5638a.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.ff6fcecb.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.c00ab437.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/25.8723ba2a.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/21.4345fd66.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/23.18ddfc34.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.64885ea0.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.074823aa.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.8fb96127.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.9d0bf8a1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.01f9c5ca.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.027df4f5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.20efa08a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.49636032.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.f70eb73f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.0cdcc9a7.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.1fd466cc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.7085bcef.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.d0524281.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.4986fdcb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.e983ad80.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.20094dae.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.9e436899.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.9968bcc5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.6a61b13c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.c917f8a0.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.1a378fbc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/33.0dc057ef.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.4300f76e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.7c61df69.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.21b41042.js"><link rel="prefetch" href="/learn-wgpu/assets/js/37.6fd34bf3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/38.7ff8a392.js"><link rel="prefetch" href="/learn-wgpu/assets/js/39.6091f394.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.889a3487.js"><link rel="prefetch" href="/learn-wgpu/assets/js/40.35785000.js"><link rel="prefetch" href="/learn-wgpu/assets/js/41.e5da7d6d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.4ea262a9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.1f8656df.js"><link rel="prefetch" href="/learn-wgpu/assets/js/44.4c30e130.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.e0a66d0e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.e7bb83ef.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.5b29d039.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.ef851145.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.ebac4d1f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.680f030b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.620d995c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.7d4d8360.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.7ed96fbe.js">
|
|
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.0ab5638a.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 open"><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/" aria-current="page" class="active sidebar-link">The Surface</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#first-some-housekeeping-state" class="sidebar-link">First, some housekeeping: State</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#state-new" class="sidebar-link">State::new()</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#resize" class="sidebar-link">resize()</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#input" class="sidebar-link">input()</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#update" class="sidebar-link">update()</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#render" class="sidebar-link">render()</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#wait-what-s-going-on-with-renderpassdescriptor" class="sidebar-link">Wait, what's going on with RenderPassDescriptor?</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#validation-errors" class="sidebar-link">Validation Errors?</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial2-surface/#challenge" class="sidebar-link">Challenge</a></li></ul></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></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></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="the-surface"><a href="#the-surface" class="header-anchor">#</a> The Surface</h1> <h2 id="first-some-housekeeping-state"><a href="#first-some-housekeeping-state" class="header-anchor">#</a> First, some housekeeping: State</h2> <p>For convenience, we're going to pack all the fields into a struct and create some methods for it.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// lib.rs</span>
|
|
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>window<span class="token punctuation">::</span></span><span class="token class-name">Window</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token keyword">struct</span> <span class="token type-definition class-name">State</span> <span class="token punctuation">{</span>
|
|
surface<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Surface</span><span class="token punctuation">,</span>
|
|
device<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Device</span><span class="token punctuation">,</span>
|
|
queue<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Queue</span><span class="token punctuation">,</span>
|
|
config<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceConfiguration</span><span class="token punctuation">,</span>
|
|
size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator"><</span><span class="token keyword">u32</span><span class="token operator">></span><span class="token punctuation">,</span>
|
|
window<span class="token punctuation">:</span> <span class="token class-name">Window</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">impl</span> <span class="token class-name">State</span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// Creating some of the wgpu types requires async code</span>
|
|
<span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
|
|
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">window</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token operator">&</span><span class="token class-name">Window</span> <span class="token punctuation">{</span>
|
|
<span class="token operator">&</span><span class="token keyword">self</span><span class="token punctuation">.</span>window
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> new_size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator"><</span><span class="token keyword">u32</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">input</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> event<span class="token punctuation">:</span> <span class="token operator">&</span><span class="token class-name">WindowEvent</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">bool</span> <span class="token punctuation">{</span>
|
|
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">render</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token class-name">Result</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceError</span><span class="token operator">></span> <span class="token punctuation">{</span>
|
|
<span class="token macro property">todo!</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="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> <h2 id="state-new"><a href="#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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">State</span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// ...</span>
|
|
<span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">let</span> size <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">inner_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token comment">// The instance is a handle to our GPU</span>
|
|
<span class="token comment">// Backends::all => Vulkan + Metal + DX12 + Browser WebGPU</span>
|
|
<span class="token keyword">let</span> instance <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Instance</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">InstanceDescriptor</span> <span class="token punctuation">{</span>
|
|
backends<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Backends</span><span class="token punctuation">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
dx12_shader_compiler<span class="token punctuation">:</span> <span class="token class-name">Default</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token comment">// # Safety</span>
|
|
<span class="token comment">//</span>
|
|
<span class="token comment">// The surface needs to live as long as the window that created it.</span>
|
|
<span class="token comment">// State owns the window so this should be safe.</span>
|
|
<span class="token keyword">let</span> surface <span class="token operator">=</span> <span class="token keyword">unsafe</span> <span class="token punctuation">{</span> instance<span class="token punctuation">.</span><span class="token function">create_surface</span><span class="token punctuation">(</span><span class="token operator">&</span>window<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token keyword">let</span> adapter <span class="token operator">=</span> instance<span class="token punctuation">.</span><span class="token function">request_adapter</span><span class="token punctuation">(</span>
|
|
<span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RequestAdapterOptions</span> <span class="token punctuation">{</span>
|
|
power_preference<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">PowerPreference</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
compatible_surface<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token operator">&</span>surface<span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
force_fallback_adapter<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><h3 id="instance-and-adapter"><a href="#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>. <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> <div class="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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> adapter <span class="token operator">=</span> instance
|
|
<span class="token punctuation">.</span><span class="token function">enumerate_adapters</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Backends</span><span class="token punctuation">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>adapter<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// Check if this adapter supports our surface</span>
|
|
adapter<span class="token punctuation">.</span><span class="token function">is_surface_supported</span><span class="token punctuation">(</span><span class="token operator">&</span>surface<span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
</code></pre></div><p>One thing to note is that <code>enumerate_adapters</code> isn't available on WASM, so you have to use <code>request_adapter</code>.</p> <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, <a href="https://docs.rs/wgpu/latest/wgpu/struct.Adapter.html" target="_blank" rel="noopener noreferrer">check out the docs<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> <h3 id="the-surface-2"><a href="#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 <a href="https://crates.io/crates/raw-window-handle" target="_blank" rel="noopener noreferrer">raw-window-handle<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>'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> <h3 id="device-and-queue"><a href="#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> <div class="language-rust extra-class"><pre class="language-rust"><code> <span class="token keyword">let</span> <span class="token punctuation">(</span>device<span class="token punctuation">,</span> queue<span class="token punctuation">)</span> <span class="token operator">=</span> adapter<span class="token punctuation">.</span><span class="token function">request_device</span><span class="token punctuation">(</span>
|
|
<span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">DeviceDescriptor</span> <span class="token punctuation">{</span>
|
|
features<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Features</span><span class="token punctuation">::</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token comment">// WebGL doesn't support all of wgpu's features, so if</span>
|
|
<span class="token comment">// we're building for the web we'll have to disable some.</span>
|
|
limits<span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token macro property">cfg!</span><span class="token punctuation">(</span>target_arch <span class="token operator">=</span> <span class="token string">"wasm32"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Limits</span><span class="token punctuation">::</span><span class="token function">downlevel_webgl2_defaults</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Limits</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
label<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
<span class="token class-name">None</span><span class="token punctuation">,</span> <span class="token comment">// Trace path</span>
|
|
<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="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> <div class="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 <a href="https://docs.rs/wgpu/latest/wgpu/struct.Features.html" target="_blank" rel="noopener noreferrer">here<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> <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 <a href="https://docs.rs/wgpu/latest/wgpu/struct.Limits.html" target="_blank" rel="noopener noreferrer">here<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-rust extra-class"><pre class="language-rust"><code> <span class="token keyword">let</span> surface_caps <span class="token operator">=</span> surface<span class="token punctuation">.</span><span class="token function">get_capabilities</span><span class="token punctuation">(</span><span class="token operator">&</span>adapter<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token comment">// Shader code in this tutorial assumes an sRGB surface texture. Using a different</span>
|
|
<span class="token comment">// one will result all the colors coming out darker. If you want to support non</span>
|
|
<span class="token comment">// sRGB surfaces, you'll need to account for that when drawing to the frame.</span>
|
|
<span class="token keyword">let</span> surface_format <span class="token operator">=</span> surface_caps<span class="token punctuation">.</span>formats<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">copied</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>f<span class="token closure-punctuation punctuation">|</span></span> f<span class="token punctuation">.</span><span class="token function">describe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>srgb<span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
<span class="token punctuation">.</span><span class="token function">unwrap_or</span><span class="token punctuation">(</span>surface_caps<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceConfiguration</span> <span class="token punctuation">{</span>
|
|
usage<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureUsages</span><span class="token punctuation">::</span><span class="token constant">RENDER_ATTACHMENT</span><span class="token punctuation">,</span>
|
|
format<span class="token punctuation">:</span> surface_format<span class="token punctuation">,</span>
|
|
width<span class="token punctuation">:</span> size<span class="token punctuation">.</span>width<span class="token punctuation">,</span>
|
|
height<span class="token punctuation">:</span> size<span class="token punctuation">.</span>height<span class="token punctuation">,</span>
|
|
present_mode<span class="token punctuation">:</span> surface_caps<span class="token punctuation">.</span>present_modes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
|
|
alpha_mode<span class="token punctuation">:</span> surface_caps<span class="token punctuation">.</span>alpha_modes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
|
|
view_formats<span class="token punctuation">:</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">;</span>
|
|
surface<span class="token punctuation">.</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token operator">&</span>device<span class="token punctuation">,</span> <span class="token operator">&</span>config<span class="token punctuation">)</span><span class="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, 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. We can get a supported format from the <code>SurfaceCapabilities</code>.</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> <div class="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>PresentMode::Fifo</code>, will cap the display rate at the display's framerate. This is essentially VSync. This mode is guaranteed to be supported on all platforms. There are other options and you can see all of them <a href="https://docs.rs/wgpu/latest/wgpu/enum.PresentMode.html" target="_blank" rel="noopener noreferrer">in the docs<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="note"><p>If you want to let your users pick what <code>PresentMode</code> they use, you can use <a href="https://docs.rs/wgpu/latest/wgpu/struct.SurfaceCapabilities.html#structfield.present_modes" target="_blank" rel="noopener noreferrer">SurfaceCapabilities::present_modes<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> to get a list of all the <code>PresentMode</code>s the surface supports:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> modes <span class="token operator">=</span> <span class="token operator">&</span>surface_caps<span class="token punctuation">.</span>present_modes<span class="token punctuation">;</span>
|
|
</code></pre></div><p>Regardless, <code>PresentMode::Fifo</code> will always be supported, and <code>PresentMode::AutoVsync</code> and <code>PresentMode::AutoNoVsync</code> have fallback support and therefore will work on all platforms.</p></div> <p><code>alpha_mode</code> is honestly not something I'm familiar with. I believe it has something to do with transparent windows, but feel free to open a pull request. For now we'll just use the first <code>AlphaMode</code> in the list given by <code>surface_caps</code>.</p> <p><code>view_formats</code> is a list of <code>TextureFormat</code>s that you can use when creating <code>TextureView</code>s (we'll cover those briefly later in the this tutorial as well as more in depth <a href="../tutorial5-textures">in the texture tutorial</a>). As of writing this means that if your surface is srgb color space, you can create a texture view that uses a linear color space.</p> <p>Now that we've configured our surface properly we can add these new fields at the end of the method.</p> <div class="language-rust extra-class"><pre class="language-rust"><code> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">:</span> <span class="token operator">&</span><span class="token class-name">Window</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// ...</span>
|
|
|
|
<span class="token keyword">Self</span> <span class="token punctuation">{</span>
|
|
window<span class="token punctuation">,</span>
|
|
surface<span class="token punctuation">,</span>
|
|
device<span class="token punctuation">,</span>
|
|
queue<span class="token punctuation">,</span>
|
|
config<span class="token punctuation">,</span>
|
|
size<span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">pub</span> <span class="token keyword">async</span> <span class="token keyword">fn</span> <span class="token function-definition function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// Window setup...</span>
|
|
|
|
<span class="token keyword">let</span> <span class="token keyword">mut</span> state <span class="token operator">=</span> <span class="token class-name">State</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>window<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token comment">// Event loop...</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><p>Now that <code>run()</code> is async, <code>main()</code> will need some way to await the future. We could use a crate like <a href="https://docs.rs/tokio" target="_blank" rel="noopener noreferrer">tokio<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>, or <a href="https://docs.rs/async-std" target="_blank" rel="noopener noreferrer">async-std<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>, but I'm going to go with the much more lightweight <a href="https://docs.rs/pollster" target="_blank" rel="noopener noreferrer">pollster<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>. Add the following to your <code>Cargo.toml</code>:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
|
|
<span class="token comment"># other deps...</span>
|
|
<span class="token key property">pollster</span> <span class="token punctuation">=</span> <span class="token string">"0.2"</span>
|
|
</code></pre></div><p>We then use the <code>block_on</code> function provided by pollster to await our future:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token namespace">pollster<span class="token punctuation">::</span></span><span class="token function">block_on</span><span class="token punctuation">(</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><div class="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 <a href="https://docs.rs/wasm-bindgen-futures" target="_blank" rel="noopener noreferrer">wasm-bindgen-futures<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> crate to our WASM dependencies as that doesn't require us to change any code. Your dependencies should look something like this:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
|
|
<span class="token key property">cfg-if</span> <span class="token punctuation">=</span> <span class="token string">"1"</span>
|
|
<span class="token key property">winit</span> <span class="token punctuation">=</span> <span class="token string">"0.27"</span>
|
|
<span class="token key property">env_logger</span> <span class="token punctuation">=</span> <span class="token string">"0.10"</span>
|
|
<span class="token key property">log</span> <span class="token punctuation">=</span> <span class="token string">"0.4"</span>
|
|
<span class="token key property">wgpu</span> <span class="token punctuation">=</span> <span class="token string">"0.15"</span>
|
|
<span class="token key property">pollster</span> <span class="token punctuation">=</span> <span class="token string">"0.2"</span>
|
|
|
|
<span class="token punctuation">[</span><span class="token table class-name">target.'cfg(target_arch = "wasm32")'.dependencies</span><span class="token punctuation">]</span>
|
|
<span class="token key property">console_error_panic_hook</span> <span class="token punctuation">=</span> <span class="token string">"0.1.6"</span>
|
|
<span class="token key property">console_log</span> <span class="token punctuation">=</span> <span class="token string">"0.2.0"</span>
|
|
<span class="token key property">wgpu</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">"0.15"</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"webgl"</span><span class="token punctuation">]</span><span class="token punctuation">}</span>
|
|
<span class="token key property">wasm-bindgen</span> <span class="token punctuation">=</span> <span class="token string">"0.2"</span>
|
|
<span class="token key property">wasm-bindgen-futures</span> <span class="token punctuation">=</span> <span class="token string">"0.4"</span>
|
|
<span class="token key property">web-sys</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">"0.3"</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span>
|
|
<span class="token string">"Document"</span><span class="token punctuation">,</span>
|
|
<span class="token string">"Window"</span><span class="token punctuation">,</span>
|
|
<span class="token string">"Element"</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">]</span><span class="token punctuation">}</span>
|
|
</code></pre></div><h2 id="resize"><a href="#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> every time 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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// impl State</span>
|
|
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">resize</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> new_size<span class="token punctuation">:</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token operator"><</span><span class="token keyword">u32</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">if</span> new_size<span class="token punctuation">.</span>width <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&&</span> new_size<span class="token punctuation">.</span>height <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">self</span><span class="token punctuation">.</span>size <span class="token operator">=</span> new_size<span class="token punctuation">;</span>
|
|
<span class="token keyword">self</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>width <span class="token operator">=</span> new_size<span class="token punctuation">.</span>width<span class="token punctuation">;</span>
|
|
<span class="token keyword">self</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span>height <span class="token operator">=</span> new_size<span class="token punctuation">.</span>height<span class="token punctuation">;</span>
|
|
<span class="token keyword">self</span><span class="token punctuation">.</span>surface<span class="token punctuation">.</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">self</span><span class="token punctuation">.</span>device<span class="token punctuation">,</span> <span class="token operator">&</span><span class="token keyword">self</span><span class="token punctuation">.</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">match</span> event <span class="token punctuation">{</span>
|
|
<span class="token comment">// ...</span>
|
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">if</span> <span class="token operator">!</span>state<span class="token punctuation">.</span><span class="token function">input</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
|
|
<span class="token comment">// ...</span>
|
|
|
|
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">Resized</span><span class="token punctuation">(</span>physical_size<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span>physical_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">ScaleFactorChanged</span> <span class="token punctuation">{</span> new_inner_size<span class="token punctuation">,</span> <span class="token punctuation">..</span> <span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// new_inner_size is &&mut so we have to dereference it twice</span>
|
|
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token operator">*</span>new_inner_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token comment">// ...</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><h2 id="input"><a href="#input" class="header-anchor">#</a> input()</h2> <p><code>input()</code> returns a <code>bool</code> to indicate whether an event has been fully processed. If the method returns <code>true</code>, the main loop won't process the event any further.</p> <p>We're just going to return false for now because we don't have any events we want to capture.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// impl State</span>
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">input</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> event<span class="token punctuation">:</span> <span class="token operator">&</span><span class="token class-name">WindowEvent</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">bool</span> <span class="token punctuation">{</span>
|
|
<span class="token boolean">false</span>
|
|
<span class="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>run()</code>. Doing that (and previous changes) should have your loop looking like this.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// run()</span>
|
|
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
|
|
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">WindowEvent</span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">ref</span> event<span class="token punctuation">,</span>
|
|
window_id<span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">if</span> <span class="token operator">!</span>state<span class="token punctuation">.</span><span class="token function">input</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// UPDATED!</span>
|
|
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
|
|
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">CloseRequested</span>
|
|
<span class="token operator">|</span> <span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
|
|
input<span class="token punctuation">:</span>
|
|
<span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
|
|
state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">,</span>
|
|
virtual_keycode<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Escape</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">..</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">..</span>
|
|
<span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Exit</span><span class="token punctuation">,</span>
|
|
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">Resized</span><span class="token punctuation">(</span>physical_size<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span>physical_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">ScaleFactorChanged</span> <span class="token punctuation">{</span> new_inner_size<span class="token punctuation">,</span> <span class="token punctuation">..</span> <span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token operator">*</span>new_inner_size<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
_ <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
_ <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
</code></pre></div><h2 id="update"><a href="#update" class="header-anchor">#</a> update()</h2> <p>We don't have anything to update yet, so leave the method empty.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// remove `todo!()`</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><p>We'll add some code here later on to move around objects.</p> <h2 id="render"><a href="#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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// impl State</span>
|
|
|
|
<span class="token keyword">fn</span> <span class="token function-definition function">render</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token class-name">Result</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceError</span><span class="token operator">></span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span>surface<span class="token punctuation">.</span><span class="token function">get_current_texture</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
|
|
</code></pre></div><p>The <code>get_current_texture</code> function will wait for the <code>surface</code> to provide a new <code>SurfaceTexture</code> that we will render to. We'll store this in <code>output</code> for later.</p> <div class="language-rust extra-class"><pre class="language-rust"><code> <span class="token keyword">let</span> view <span class="token operator">=</span> output<span class="token punctuation">.</span>texture<span class="token punctuation">.</span><span class="token function">create_view</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureViewDescriptor</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</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> <div class="language-rust extra-class"><pre class="language-rust"><code> <span class="token keyword">let</span> <span class="token keyword">mut</span> encoder <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span>device<span class="token punctuation">.</span><span class="token function">create_command_encoder</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">CommandEncoderDescriptor</span> <span class="token punctuation">{</span>
|
|
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">"Render Encoder"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="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> <div class="language-rust extra-class"><pre class="language-rust"><code> <span class="token punctuation">{</span>
|
|
<span class="token keyword">let</span> _render_pass <span class="token operator">=</span> encoder<span class="token punctuation">.</span><span class="token function">begin_render_pass</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPassDescriptor</span> <span class="token punctuation">{</span>
|
|
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">"Render Pass"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
color_attachments<span class="token punctuation">:</span> <span class="token operator">&</span><span class="token punctuation">[</span><span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPassColorAttachment</span> <span class="token punctuation">{</span>
|
|
view<span class="token punctuation">:</span> <span class="token operator">&</span>view<span class="token punctuation">,</span>
|
|
resolve_target<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
|
|
ops<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Operations</span> <span class="token punctuation">{</span>
|
|
load<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">LoadOp</span><span class="token punctuation">::</span><span class="token class-name">Clear</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Color</span> <span class="token punctuation">{</span>
|
|
r<span class="token punctuation">:</span> <span class="token number">0.1</span><span class="token punctuation">,</span>
|
|
g<span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span>
|
|
b<span class="token punctuation">:</span> <span class="token number">0.3</span><span class="token punctuation">,</span>
|
|
a<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
store<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
|
|
depth_stencil_attachment<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
|
|
<span class="token comment">// submit will accept anything that implements IntoIter</span>
|
|
<span class="token keyword">self</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token namespace">std<span class="token punctuation">::</span>iter<span class="token punctuation">::</span></span><span class="token function">once</span><span class="token punctuation">(</span>encoder<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
output<span class="token punctuation">.</span><span class="token function">present</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
<span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
|
<span class="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>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> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// run()</span>
|
|
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
|
|
<span class="token keyword">match</span> event <span class="token punctuation">{</span>
|
|
<span class="token comment">// ...</span>
|
|
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">RedrawRequested</span><span class="token punctuation">(</span>window_id<span class="token punctuation">)</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
state<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token keyword">match</span> state<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
<span class="token class-name">Ok</span><span class="token punctuation">(</span>_<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
|
|
<span class="token comment">// Reconfigure the surface if lost</span>
|
|
<span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceError</span><span class="token punctuation">::</span><span class="token class-name">Lost</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span><span class="token function">resize</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>size<span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token comment">// The system is out of memory, we should probably quit</span>
|
|
<span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">SurfaceError</span><span class="token punctuation">::</span><span class="token class-name">OutOfMemory</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Exit</span><span class="token punctuation">,</span>
|
|
<span class="token comment">// All other errors (Outdated, Timeout) should be resolved by the next frame</span>
|
|
<span class="token class-name">Err</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token macro property">eprintln!</span><span class="token punctuation">(</span><span class="token string">"{:?}"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">MainEventsCleared</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
|
|
<span class="token comment">// RedrawRequested will only trigger once, unless we manually</span>
|
|
<span class="token comment">// request it.</span>
|
|
state<span class="token punctuation">.</span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">request_redraw</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token comment">// ...</span>
|
|
<span class="token punctuation">}</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
</code></pre></div><p>With all that, you should be getting something that looks like this.</p> <p><img src="data:image/png;base64,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IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAOiECAADUCREAAKBOiAAAAHVCBAAAqBMiAABAnRABAADqhAgAAFAnRAAAgDohAgAA1AkRAACgTogAAAB1QgQAAKgTIgAAQJ0QAQAA6oQIAABQJ0QAAIA6IQIAANQJEQAAoE6IAAAAdUIEAACoEyIAAECdEAEAAOqECAAAUCdEAACAuqkk2b5udKHnAAAAfob8P4Fe1tYvSjndAAAAAElFTkSuQmCC" alt="Window with a blue background"></p> <h2 id="wait-what-s-going-on-with-renderpassdescriptor"><a href="#wait-what-s-going-on-with-renderpassdescriptor" class="header-anchor">#</a> Wait, what's going on with RenderPassDescriptor?</h2> <p>Some of you may be able to tell what's going on just by looking at it, but I'd be remiss if I didn't go over it. Let's take a look at the code again.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token operator">&</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPassDescriptor</span> <span class="token punctuation">{</span>
|
|
label<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">"Render Pass"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
color_attachments<span class="token punctuation">:</span> <span class="token operator">&</span><span class="token punctuation">[</span>
|
|
<span class="token comment">// ...</span>
|
|
<span class="token punctuation">]</span><span class="token punctuation">,</span>
|
|
depth_stencil_attachment<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span>
|
|
</code></pre></div><p>A <code>RenderPassDescriptor</code> only has three fields: <code>label</code>, <code>color_attachments</code> and <code>depth_stencil_attachment</code>. The <code>color_attachments</code> describe where we are going to draw our color to. We use the <code>TextureView</code> we created earlier to make sure that we render to the screen.</p> <div class="note"><p>The <code>color_attachments</code> field is a "sparse" array. This allows you to use a pipeline that expects multiple render targets and only supply the ones you care about.</p></div> <p>We'll use <code>depth_stencil_attachment</code> later, but we'll set it to <code>None</code> for now.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">RenderPassColorAttachment</span> <span class="token punctuation">{</span>
|
|
view<span class="token punctuation">:</span> <span class="token operator">&</span>view<span class="token punctuation">,</span>
|
|
resolve_target<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
|
|
ops<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Operations</span> <span class="token punctuation">{</span>
|
|
load<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">LoadOp</span><span class="token punctuation">::</span><span class="token class-name">Clear</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Color</span> <span class="token punctuation">{</span>
|
|
r<span class="token punctuation">:</span> <span class="token number">0.1</span><span class="token punctuation">,</span>
|
|
g<span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span>
|
|
b<span class="token punctuation">:</span> <span class="token number">0.3</span><span class="token punctuation">,</span>
|
|
a<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
store<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">,</span>
|
|
<span class="token punctuation">}</span><span class="token punctuation">)</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 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> <div class="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><img src="/learn-wgpu/assets/img/no-clear.753f913f.png" alt="./no-clear.png"></p></div> <h2 id="validation-errors"><a href="#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 <a href="https://github.com/gfx-rs/wgpu" target="_blank" rel="noopener noreferrer">https://github.com/gfx-rs/wgpu<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> <h2 id="challenge"><a href="#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> <div id="wasm-example"><!----> <button>Try Tutorial2_surface!</button></div> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial2-surface/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">5/26/2023, 10:34:53 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
|
|
←
|
|
<a href="/learn-wgpu/beginner/tutorial1-window/" class="prev">
|
|
Dependencies and the window
|
|
</a></span> <span class="next"><a href="/learn-wgpu/beginner/tutorial3-pipeline/">
|
|
The Pipeline
|
|
</a>
|
|
→
|
|
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
|
|
<script src="/learn-wgpu/assets/js/app.ff6fcecb.js" defer></script><script src="/learn-wgpu/assets/js/2.c00ab437.js" defer></script><script src="/learn-wgpu/assets/js/25.8723ba2a.js" defer></script><script src="/learn-wgpu/assets/js/21.4345fd66.js" defer></script><script src="/learn-wgpu/assets/js/23.18ddfc34.js" defer></script>
|
|
</body>
|
|
</html>
|