learn-wgpu/showcase/gifs/index.html

155 lines
40 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Creating gifs | Learn Wgpu</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.4.0">
<meta property="article:modified_time" content="2021-11-24T22:56:00.000Z"><meta property="og:site_name" content="Learn Wgpu"><meta property="og:title" content="Creating gifs"><meta property="og:type" content="website"><meta property="og:url" content="/showcase/gifs/"><meta name="twitter:title" content="Creating gifs"><meta name="twitter:url" content="/showcase/gifs/"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:label1" content="Written by"><meta name="twitter:data2" content="Benjamin Hansen"><meta name="twitter:creator" content="https://twitter.com/sotrh760">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.e2608c6d.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.e7d9d08e.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.2694e6b4.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/18.4b7a320e.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/22.2132e362.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.634b5397.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.031b1ca8.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.d174877d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.ec63c87c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.1c03a39b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.a0495455.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.ee1d4bd4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.115758a0.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.1f0de2c3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.1cd966d6.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.745e0d31.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.1a88f225.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.5e2c93e5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.87991ea0.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.8eefda0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.d7f5cf22.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.476932c1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.adc9c96e.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.4869a8a3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.35a5043b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.ba2bca1b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.2afe8d9a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.022e952a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/6.bc35a8a9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/7.2856f422.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.dd2d2989.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.ecb6e79c.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.e2608c6d.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/" 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-threading/" class="sidebar-link">Multi-threading with Wgpu and Rayon</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/" class="sidebar-link">Foreward</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="active sidebar-link">Creating gifs</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/gifs/#how-are-we-making-the-gif" class="sidebar-link">How are we making the GIF?</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/showcase/gifs/#how-do-we-make-the-frames" class="sidebar-link">How do we make the frames?</a></li></ul></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/" class="sidebar-link">Memory Layout in GLSL</a></li><li><a href="/learn-wgpu/showcase/imgui-demo/" class="sidebar-link">Basic Imgui Demo</a></li></ul></section></li><li><a href="/learn-wgpu/news/" class="sidebar-link">News</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="creating-gifs"><a href="#creating-gifs" class="header-anchor">#</a> Creating gifs</h1> <p>Sometimes you've created a nice simulation/animation, and you want to show it off. While you can record a video, that might be a bit overkill to break out your video recording if you just want something to post on twitter. That's where what <a href="https://en.wikipedia.org/wiki/GIF" target="_blank" rel="noopener noreferrer">GIF<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a>s are for.</p> <p>Also, GIF is pronounced GHIF, not JIF as JIF is not only <a href="https://en.wikipedia.org/wiki/Jif_%28peanut_butter%29" target="_blank" rel="noopener noreferrer">peanut butter<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a>, it is also a <a href="https://filext.com/file-extension/JIF" target="_blank" rel="noopener noreferrer">different image format<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a>.</p> <h2 id="how-are-we-making-the-gif"><a href="#how-are-we-making-the-gif" class="header-anchor">#</a> How are we making the GIF?</h2> <p>We're going to create a function using the <a href="https://docs.rs/gif/" target="_blank" rel="noopener noreferrer">gif crate<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></a> to encode the actual image.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">save_gif</span><span class="token punctuation">(</span>path<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> frames<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">u8</span><span class="token operator">&gt;&gt;</span><span class="token punctuation">,</span> speed<span class="token punctuation">:</span> <span class="token keyword">i32</span><span class="token punctuation">,</span> size<span class="token punctuation">:</span> <span class="token keyword">u16</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">failure<span class="token punctuation">::</span></span><span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">use</span> <span class="token namespace">gif<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Frame</span><span class="token punctuation">,</span> <span class="token class-name">Encoder</span><span class="token punctuation">,</span> <span class="token class-name">Repeat</span><span class="token punctuation">,</span> <span class="token class-name">SetParameter</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> image <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token class-name">File</span><span class="token punctuation">::</span><span class="token function">create</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> encoder <span class="token operator">=</span> <span class="token class-name">Encoder</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> image<span class="token punctuation">,</span> size<span class="token punctuation">,</span> size<span class="token punctuation">,</span> <span class="token operator">&amp;</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>
encoder<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">Repeat</span><span class="token punctuation">::</span><span class="token class-name">Infinite</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token keyword">mut</span> frame <span class="token keyword">in</span> frames <span class="token punctuation">{</span>
encoder<span class="token punctuation">.</span><span class="token function">write_frame</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token class-name">Frame</span><span class="token punctuation">::</span><span class="token function">from_rgba_speed</span><span class="token punctuation">(</span>size<span class="token punctuation">,</span> size<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> frame<span class="token punctuation">,</span> speed<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 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>All we need to use this code is the frames of the GIF, how fast it should run, and the size of the GIF (you could use width and height seperately, but I didn't).</p> <h2 id="how-do-we-make-the-frames"><a href="#how-do-we-make-the-frames" class="header-anchor">#</a> How do we make the frames?</h2> <p>If you checked out the <a href="/learn-wgpu/showcase/windowless/#a-triangle-without-a-window">windowless showcase</a>, you'll know that we render directly to a <code>wgpu::Texture</code>. We'll create a texture to render to and a buffer the copy the output to.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token comment">// create a texture to render to</span>
<span class="token keyword">let</span> texture_size <span class="token operator">=</span> <span class="token number">256u32</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> rt_desc <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureDescriptor</span> <span class="token punctuation">{</span>
size<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Extent3d</span> <span class="token punctuation">{</span>
width<span class="token punctuation">:</span> texture_size<span class="token punctuation">,</span>
height<span class="token punctuation">:</span> texture_size<span class="token punctuation">,</span>
depth_or_array_layers<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
mip_level_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
sample_count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
dimension<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureDimension</span><span class="token punctuation">::</span><span class="token constant">D2</span><span class="token punctuation">,</span>
format<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">TextureFormat</span><span class="token punctuation">::</span><span class="token class-name">Rgba8UnormSrgb</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">COPY_SRC</span>
<span class="token operator">|</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>
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 keyword">let</span> render_target <span class="token operator">=</span> <span class="token namespace">framework<span class="token punctuation">::</span></span><span class="token class-name">Texture</span><span class="token punctuation">::</span><span class="token function">from_descriptor</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>device<span class="token punctuation">,</span> rt_desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// wgpu requires texture -&gt; buffer copies to be aligned using</span>
<span class="token comment">// wgpu::COPY_BYTES_PER_ROW_ALIGNMENT. Because of this we'll</span>
<span class="token comment">// need to save both the padded_bytes_per_row as well as the</span>
<span class="token comment">// unpadded_bytes_per_row</span>
<span class="token keyword">let</span> pixel_size <span class="token operator">=</span> <span class="token namespace">mem<span class="token punctuation">::</span></span><span class="token function">size_of</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token punctuation">[</span><span class="token keyword">u8</span><span class="token punctuation">;</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">u32</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> align <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token constant">COPY_BYTES_PER_ROW_ALIGNMENT</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> unpadded_bytes_per_row <span class="token operator">=</span> pixel_size <span class="token operator">*</span> texture_size<span class="token punctuation">;</span>
<span class="token keyword">let</span> padding <span class="token operator">=</span> <span class="token punctuation">(</span>align <span class="token operator">-</span> unpadded_bytes_per_row <span class="token operator">%</span> align<span class="token punctuation">)</span> <span class="token operator">%</span> align<span class="token punctuation">;</span>
<span class="token keyword">let</span> padded_bytes_per_row <span class="token operator">=</span> unpadded_bytes_per_row <span class="token operator">+</span> padding<span class="token punctuation">;</span>
<span class="token comment">// create a buffer to copy the texture to so we can get the data</span>
<span class="token keyword">let</span> buffer_size <span class="token operator">=</span> <span class="token punctuation">(</span>padded_bytes_per_row <span class="token operator">*</span> texture_size<span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferAddress</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> buffer_desc <span class="token operator">=</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferDescriptor</span> <span class="token punctuation">{</span>
size<span class="token punctuation">:</span> buffer_size<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">BufferUsages</span><span class="token punctuation">::</span><span class="token constant">COPY_DST</span> <span class="token operator">|</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">BufferUsages</span><span class="token punctuation">::</span><span class="token constant">MAP_READ</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">&quot;Output Buffer&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
mapped_at_creation<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 keyword">let</span> output_buffer <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_buffer</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>buffer_desc<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>With that we can render a frame, and then copy that frame to a <code>Vec&lt;u8&gt;</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> <span class="token keyword">mut</span> frames <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> c <span class="token keyword">in</span> <span class="token operator">&amp;</span>colors <span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> encoder <span class="token operator">=</span> device<span class="token punctuation">.</span><span class="token function">create_command_encoder</span><span class="token punctuation">(</span><span class="token operator">&amp;</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">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 keyword">let</span> <span class="token keyword">mut</span> rpass <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">&amp;</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">&quot;GIF Pass&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
color_attachments<span class="token punctuation">:</span> <span class="token operator">&amp;</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">&amp;</span>render_target<span class="token punctuation">.</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> c<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
g<span class="token punctuation">:</span> c<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
b<span class="token punctuation">:</span> c<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</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>
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>
rpass<span class="token punctuation">.</span><span class="token function">set_pipeline</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>render_pipeline<span class="token punctuation">)</span><span class="token punctuation">;</span>
rpass<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drop</span><span class="token punctuation">(</span>rpass<span class="token punctuation">)</span><span class="token punctuation">;</span>
encoder<span class="token punctuation">.</span><span class="token function">copy_texture_to_buffer</span><span class="token punctuation">(</span>
<span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageCopyTexture</span> <span class="token punctuation">{</span>
texture<span class="token punctuation">:</span> <span class="token operator">&amp;</span>render_target<span class="token punctuation">.</span>texture<span class="token punctuation">,</span>
mip_level<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
origin<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Origin3d</span><span class="token punctuation">::</span><span class="token constant">ZERO</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">ImageCopyBuffer</span> <span class="token punctuation">{</span>
buffer<span class="token punctuation">:</span> <span class="token operator">&amp;</span>output_buffer<span class="token punctuation">,</span>
layout<span class="token punctuation">:</span> <span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">ImageDataLayout</span> <span class="token punctuation">{</span>
offset<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
bytes_per_row<span class="token punctuation">:</span> padded_bytes_per_row<span class="token punctuation">,</span>
rows_per_image<span class="token punctuation">:</span> texture_size<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
render_target<span class="token punctuation">.</span>desc<span class="token punctuation">.</span>size
<span class="token punctuation">)</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>
<span class="token comment">// Create the map request</span>
<span class="token keyword">let</span> buffer_slice <span class="token operator">=</span> output_buffer<span class="token punctuation">.</span><span class="token function">slice</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">let</span> request <span class="token operator">=</span> buffer_slice<span class="token punctuation">.</span><span class="token function">map_async</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">MapMode</span><span class="token punctuation">::</span><span class="token class-name">Read</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// wait for the GPU to finish</span>
device<span class="token punctuation">.</span><span class="token function">poll</span><span class="token punctuation">(</span><span class="token namespace">wgpu<span class="token punctuation">::</span></span><span class="token class-name">Maintain</span><span class="token punctuation">::</span><span class="token class-name">Wait</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> result <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token keyword">await</span><span class="token punctuation">;</span>
<span class="token keyword">match</span> result <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 operator">=&gt;</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> padded_data <span class="token operator">=</span> buffer_slice<span class="token punctuation">.</span><span class="token function">get_mapped_range</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> data <span class="token operator">=</span> padded_data
<span class="token punctuation">.</span><span class="token function">chunks</span><span class="token punctuation">(</span>padded_bytes_per_row <span class="token keyword">as</span> _<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>chunk<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span> <span class="token operator">&amp;</span>chunk<span class="token punctuation">[</span><span class="token punctuation">..</span>unpadded_bytes_per_row <span class="token keyword">as</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">flatten</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span> <span class="token operator">*</span>x <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drop</span><span class="token punctuation">(</span>padded_data<span class="token punctuation">)</span><span class="token punctuation">;</span>
output_buffer<span class="token punctuation">.</span><span class="token function">unmap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
frames<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> <span class="token macro property">eprintln!</span><span class="token punctuation">(</span><span class="token string">&quot;Something went wrong&quot;</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>Once that's done we can pass our frames into <code>save_gif()</code>.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token function">save_gif</span><span class="token punctuation">(</span><span class="token string">&quot;output.gif&quot;</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> frames<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> texture_size <span class="token keyword">as</span> <span class="token keyword">u16</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>
</code></pre></div><p>That's the gist of it. We can improve things using a texture array, and sending the draw commands all at once, but this gets the idea across. With the shader I wrote we get the following GIF.</p> <p><img src="/learn-wgpu/assets/img/output.5ed23d6e.gif" alt="./output.gif"></p> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/showcase/gifs/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" 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></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/24/2021, 10:56:00 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/showcase/windowless/" class="prev">
Wgpu without a window
</a></span> <span class="next"><a href="/learn-wgpu/showcase/pong/">
Pong
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.e7d9d08e.js" defer></script><script src="/learn-wgpu/assets/js/2.2694e6b4.js" defer></script><script src="/learn-wgpu/assets/js/18.4b7a320e.js" defer></script><script src="/learn-wgpu/assets/js/22.2132e362.js" defer></script>
</body>
</html>