<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Half-Life on Ivan Molodetskikh’s Webpage</title>
    <link>https://bxt.rs/tags/half-life/</link>
    <description>Recent content in Half-Life on Ivan Molodetskikh’s Webpage</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 19 Aug 2023 11:25:00 +0400</lastBuildDate><atom:link href="https://bxt.rs/tags/half-life/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Motion Blur for Half-Life Video Recording with Vulkan</title>
      <link>https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/</link>
      <pubDate>Sat, 19 Aug 2023 11:25:00 +0400</pubDate>
      
      <guid>https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/</guid><description>&lt;figure&gt;
    &lt;video controls src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/sampling.mp4&#34;&gt;&lt;/video&gt;
    &lt;figcaption&gt;
        &lt;p&gt;Video of a Half-Life movement map run, recorded with motion blur.&lt;/p&gt;

    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&#34;https://store.steampowered.com/app/70/HalfLife/&#34;&gt;Half-Life&lt;/a&gt; is an award-winning first-person shooter from 1998.
One of the many things setting it apart is a fluid player movement system.
You can gradually build up speed in the air by turning left and right, and if you jump as soon as you hit the ground, you keep all of that speed.&lt;/p&gt;
&lt;p&gt;These techniques, called strafing and bunny-hopping, unlocked a whole new dimension to the game, and spawned a big community of mappers and players.
There are hundreds of custom maps with challenging obstacles designed to test one&amp;rsquo;s movement skills, and thousands of players competing to finish them as fast as possible.&lt;/p&gt;
&lt;p&gt;The main hubs for these maps and records are Xtreme-Jumps&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and &lt;a href=&#34;https://cosy-climbing.net&#34;&gt;Cosy-Climbing&lt;/a&gt;.
They are centered around Counter-Strike 1.6, which has similar movement mechanics to Half-Life, but paced slower with a jump-speed limit and some tweaks to the acceleration.&lt;/p&gt;
&lt;p&gt;People generally record their runs to in-game demo files.
They are very lightweight, making them easy to store and share.
Players can then capture demos to videos.
There are YouTube channels uploading videos of the best, or notable runs and edits, like &lt;a href=&#34;https://www.youtube.com/@XtremeJumps&#34;&gt;the Xtreme-Jumps channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since this gameplay style is focused on movement, it has been customary to use motion blur for video recordings.
When done right, it can make the video look smoother and nicer to watch; &lt;a href=&#34;https://www.youtube.com/watch?v=FRZKSkfOjwQ&#34;&gt;here&amp;rsquo;s such an edit&lt;/a&gt; (volume warning) for example.
Though, ultimately, motion blur is a subjective preference, and plenty of people will tell you how it is completely unwatchable.
Part of this, I suspect, comes from frequent cases of motion blur done &lt;em&gt;wrong&lt;/em&gt;.
I shudder at the vision of someone dropping a 60 frames-per-second (FPS) video into a 30 FPS Vegas project, and leaving frame blending on its default enabled setting.&lt;/p&gt;
&lt;h2 id=&#34;how-motion-blur-works&#34;&gt;How Motion Blur Works &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#how-motion-blur-works&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The simplest way to get motion blur is to capture the video at a higher frame rate, then blend together multiple frames for every output video frame.
And when dealing with a closed-source game engine, there actually isn&amp;rsquo;t much else you can do.
Thankfully, Half-Life demos play back smoothly at any frame rate, regardless of the FPS the player had when running&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, so this approach works perfectly.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s explore how several frames combine into the final frame.
The following interactive widget shows the final frame at the top, and a set of sixty consecutive sub-frames, or samples, below.
&lt;span class=&#34;green&#34;&gt;&lt;strong&gt;Green&lt;/strong&gt;&lt;/span&gt; outlines show which of the samples are blended together to form the final frame.
Even though motion blur is best experienced in motion, this still-frame demo should make it clear how it works under the hood.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Please visit &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/&#34;&gt;the blog post page&lt;/a&gt; to view this interactive element.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;There are two sliders corresponding to two of the most important parameters for controlling the motion blur.&lt;/p&gt;
&lt;p&gt;The top one controls the video capturing FPS, usually called &amp;ldquo;samples per second&amp;rdquo;, or &amp;ldquo;SPS&amp;rdquo; for short, in the context of frame blending.
A &lt;a href=&#34;#&#34; onclick=&#34;setLowSPS(); return false;&#34;&gt;low SPS value&lt;/a&gt; will produce clearly visible copies of the same objects, making it easy to tell apart the individual frames in the final composite.
A &lt;a href=&#34;#&#34; onclick=&#34;setHighSPS(); return false;&#34;&gt;high SPS value&lt;/a&gt; on the other hand will make the composite smooth and nice to look at in the final video.&lt;/p&gt;
&lt;p&gt;The bottom slider controls the amount of blur.
It is called &amp;ldquo;exposure&amp;rdquo; because it is analogous to exposure in photography and filming.
Higher exposure means more sub-frames are blended together.
Compare &lt;a href=&#34;#&#34; onclick=&#34;setLowExposure(); return false;&#34;&gt;low exposure&lt;/a&gt; giving a mostly-clear still frame and &lt;a href=&#34;#&#34; onclick=&#34;setHighExposure(); return false;&#34;&gt;high exposure&lt;/a&gt; resulting in a lot of blur as all samples are included.&lt;/p&gt;
&lt;p&gt;Real-world exposure lets the camera sensor take in light continuously while the shutter is open, but game video capturing is discrete and can only use the samples that were recorded.
This is why &lt;a href=&#34;#&#34; onclick=&#34;setLowSPS(); return false;&#34;&gt;low SPS&lt;/a&gt; makes individual sub-frames visible&amp;mdash;they are the only samples we have, with no in-between contents available.&lt;/p&gt;
&lt;p&gt;So, high SPS is &lt;em&gt;extremely important&lt;/em&gt; for good motion blur.
When the player is moving or spinning fast, you need a lot of samples to blend together a smooth-looking frame without obvious edges.
This means recording the video at a very high FPS.
For Half-Life movement-oriented maps, you want to go up to at least around 3600 FPS to get a decent result regardless of what&amp;rsquo;s happening on the screen.
If you can only capture the video at 60 real-time FPS, it will take you &lt;em&gt;sixty times longer&lt;/em&gt; to capture the demo at 3600 FPS compared to its real-time duration.
That is, &lt;em&gt;an hour&lt;/em&gt; of recording per every minute of the demo.
Basically, you really want your recording to go as fast as your computer allows, without being limited to real-time.&lt;/p&gt;
&lt;p&gt;This problem was one of the main drivers for me to explore and make my own Half-Life video recording tools, first &lt;a href=&#34;https://github.com/YaLTeR/hl-capture&#34;&gt;hl-capture&lt;/a&gt;, then &lt;a href=&#34;https://github.com/YaLTeR/bxt-rs&#34;&gt;bxt-rs&lt;/a&gt;.
Frame blending is included in the widely-used &lt;a href=&#34;https://www.advancedfx.org&#34;&gt;HLAE&lt;/a&gt; tool, which has been around for many years.
Unfortunately, HLAE had extremely slow recording speed back then (it is considerably better nowadays), making it unreasonable to use high FPS for motion blur.
This is why so many of the older movement videos have clearly visible frame blending artifacts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#specialized-recording-tools&#34;&gt;In the previous post&lt;/a&gt; about bxt-rs video recording, I wrote about how these kinds of tools can capture video much faster than real-time.
Now let&amp;rsquo;s see how I added motion blur to the process.&lt;/p&gt;
&lt;h2 id=&#34;frame-blending-in-bxt-rs&#34;&gt;Frame Blending in bxt-rs &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#frame-blending-in-bxt-rs&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Frame blending is really just per-pixel averaging of multiple frames.
If you know anything about how GPUs work, you can immediately see that this is the &lt;em&gt;perfect&lt;/em&gt; task to do on a GPU: a ton of mutually-independent computations that can be done in parallel.
Better still, the input frames are &lt;em&gt;already&lt;/em&gt; on the GPU: the game has just rendered them.
This means that we can avoid the costly data transfers between the GPU video memory and the main memory, making the whole process practically instantaneous. In fact, the interactive widget above is basically doing the same computation in real-time, as you&amp;rsquo;re dragging the sliders.&lt;/p&gt;
&lt;p&gt;In bxt-rs I &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#capturing-a-frame&#34;&gt;copy&lt;/a&gt; the frame rendered by the game into a texture &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#sharing-memory-with-opengl&#34;&gt;shared&lt;/a&gt; between OpenGL and Vulkan.
The Vulkan part then &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#color-conversion&#34;&gt;converts&lt;/a&gt; the pixel values from the RGB format to YUV 4:2:0 used in video files, downloads the result into the main memory, and &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#video-encoding&#34;&gt;hands it over&lt;/a&gt; to FFmpeg for video encoding.&lt;/p&gt;
&lt;p&gt;The frame blending step will live in Vulkan, between receiving a new frame from OpenGL and pixel format conversion.
We only need to output and encode the final blended frame, so intermediate sub-frames can stay in RGB.&lt;/p&gt;
&lt;h3 id=&#34;color-accumulation&#34;&gt;Color Accumulation &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#color-accumulation&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;We don&amp;rsquo;t actually need all sixty or so sub-frames at once in video memory.
We can allocate one buffer for the output frame (the &lt;em&gt;sampling buffer&lt;/em&gt;), then accumulate the intermediate frames into it one by one as they come in.
Averaging pixel values means summing them up and dividing by the total count, which is equivalent to dividing every value by the total count first, and summing them together afterwards.
Since we know the total count in advance (it&amp;rsquo;s SPS multiplied by exposure), we can do this division and addition as the frames come in, and get the correct averaged result in the end.&lt;/p&gt;
&lt;p&gt;I chose the 16-bit RGB format for the sampling buffer.
This allows up to 257 sub-frames with no precision loss due to quantization&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, which is more than enough.
By default, bxt-rs records at 7200 FPS, which means up to 120 sub-frames with an output FPS of 60, or up to 240 sub-frames with an output FPS of 30&amp;mdash;both below 257.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageCreateInfo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Use the 16-bit RGB format in UNORM mode.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;Format&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;R16G16B16A16_UNORM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usage&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// For updating during the sampling stage.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;STORAGE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For clearing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For reading during YUV conversion.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SAMPLED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;UNORM lets me treat pixel values as floating point numbers from 0 to 1 in the shader, without having to round them manually.&lt;/p&gt;
&lt;p&gt;The shader itself is pretty simple.
Its inputs are the new sub-frame from the game, the sampling buffer and the weight factor.
The code loads a pixel from the new sub-frame, multiplies it by the weight, and adds it into the sampling buffer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-glsl&#34; data-lang=&#34;glsl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#version 450&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Copied from the color conversion shader where it gave the best performance.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define WORKGROUP_SIZE 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_size_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WORKGROUP_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;local_size_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WORKGROUP_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;local_size_z&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Frames coming from the game are rgba8.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;binding&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rgba8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;uniform&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image2D&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Our intermediate buffer is rgba16.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;binding&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rgba16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;uniform&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image2D&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Weight is set for every frame at runtime.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_constant&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;uniform&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push_constants&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;float&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;ivec2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;imageSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gl_GlobalInvocationID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gl_GlobalInvocationID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;ivec2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;coords&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;ivec2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;frameColor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;imageLoad&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;coords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sampleColor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;imageLoad&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;coords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Accumulate the frame into the intermediate buffer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newColor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sampleColor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;frameColor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;imageStore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;coords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using multiplication instead of division is just a common thing to do.
A usual justification is that it&amp;rsquo;s faster this way.
I&amp;rsquo;m not sure how much this is still true, especially for shader code&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, but anyhow.&lt;/p&gt;
&lt;p&gt;I can use &lt;code&gt;image2D&lt;/code&gt; rather than &lt;code&gt;sampler2D&lt;/code&gt; for the input image, since in this shader I read every pixel independently of the rest.
This lets me avoid making the whole Vulkan combined image sampler required for a &lt;code&gt;sampler2D&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The weight can vary between frames, so I pass it as a Vulkan push constant.
This is because exposure can cut a sub-frame in half, causing its weight to be reduced.
That might seem like an edge case which can be solved by rounding the exposure to always cover full sub-frames.
You can indeed do that for capturing demos.
However, bxt-rs also supports capturing &lt;a href=&#34;http://tasvideos.org/WelcomeToTASVideos.html&#34;&gt;TAS&lt;/a&gt; playback where the game&amp;rsquo;s FPS cannot be changed, so the frame blending code must work with any timing thrown at it.&lt;/p&gt;
&lt;h3 id=&#34;recording-loop&#34;&gt;Recording Loop &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#recording-loop&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;As you may find &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#capturing-a-frame&#34;&gt;in the previous post&lt;/a&gt;, the video recording loop without frame blending looks somewhat like this:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!-- Do not edit this file with editors other than draw.io --&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;450px&#34; height=&#34;356px&#34; viewBox=&#34;-0.5 -0.5 450 356&#34; class=&#34;ge-export-svg-auto&#34; content=&#34;&amp;lt;mxfile host=&amp;quot;app.diagrams.net&amp;quot; agent=&amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0&amp;quot; version=&amp;quot;24.8.0&amp;quot; pages=&amp;quot;2&amp;quot; scale=&amp;quot;1&amp;quot; border=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Page-1&amp;quot; id=&amp;quot;d1g8u6Vk2-SD41G-Ihbw&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;2023&amp;quot; dy=&amp;quot;1564&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;1&amp;quot; parent=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-21&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;190&amp;quot; height=&amp;quot;355&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-8&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-9&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-12&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-27&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Copy to&amp;amp;lt;br&amp;amp;gt;intermediate&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-28&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-29&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-22&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-26&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Copy of Page-1&amp;quot; id=&amp;quot;sYl0cKrkGWZCpCTy2JTT&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;754&amp;quot; dy=&amp;quot;1424&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-2&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;414&amp;quot; height=&amp;quot;355&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-3&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-7&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture sub-frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-10&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-4&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot; target=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Accumulate&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-13&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-15&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-17&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-18&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-19&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Is frame complete?&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-7&amp;quot; value=&amp;quot;&amp;amp;lt;div&amp;amp;gt;Yes&amp;amp;lt;/div&amp;amp;gt;&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;485&amp;quot; y=&amp;quot;125&amp;quot; width=&amp;quot;42&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;&amp;lt;/mxfile&amp;gt;&amp;#xA;&#34;&gt;&lt;defs&gt;&lt;style type=&#34;text/css&#34;&gt;@media (prefers-color-scheme: dark) {&amp;#xa;svg.ge-export-svg-auto:not(mjx-container &amp;gt; svg) { filter: invert(100%) hue-rotate(180deg); }&amp;#xa;svg.ge-export-svg-auto foreignObject img,&amp;#xa;svg.ge-export-svg-auto image:not(svg.ge-export-svg-auto switch image),&amp;#xa;svg.ge-export-svg-auto svg:not(mjx-container &amp;gt; svg)&amp;#xa;{ filter: invert(100%) hue-rotate(180deg) }&amp;#xa;}&lt;/style&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id=&#34;0&#34;&gt;&lt;g data-cell-id=&#34;1&#34;&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-21&#34;&gt;&lt;g&gt;&lt;rect x=&#34;259&#34; y=&#34;0&#34; width=&#34;190&#34; height=&#34;355&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-5&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 98 Q 130 98 130 130.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 136.88 L 125.5 127.88 L 130 130.13 L 134.5 127.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-3&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;58&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 78px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: rgb(0, 0, 0); &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Run game tick&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;83&#34; fill=&#34;rgb(0, 0, 0)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-8&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 178 Q 130 178 130 210.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 216.88 L 125.5 207.88 L 130 210.13 L 134.5 207.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-4&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;138&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 158px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: rgb(0, 0, 0); &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Draw frame&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;163&#34; fill=&#34;rgb(0, 0, 0)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-9&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 258 Q 130 258 130 290.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 296.88 L 125.5 287.88 L 130 290.13 L 134.5 287.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-6&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;218&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 238px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Capture frame&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;243&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Capture frame&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-7&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;298&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 318px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: rgb(0, 0, 0); &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Swap buffers&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;323&#34; fill=&#34;rgb(0, 0, 0)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-12&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 338 Q 130 356 65 351 Q 0 346 0 201 Q 0 56 65 43 Q 130 30 130 50.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 56.88 L 125.5 47.88 L 130 50.13 L 134.5 47.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-27&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 98 Q 354 98 354 130.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 136.88 L 349.5 127.88 L 354 130.13 L 358.5 127.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-17&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;58&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 78px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Copy to&lt;br /&gt;intermediate&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;83&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Copy to...&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-28&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 178 Q 354 178 354 210.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 216.88 L 349.5 207.88 L 354 210.13 L 358.5 207.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-18&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;138&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 158px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Convert colors&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;163&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Convert colors&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-29&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 258 Q 354 258 354 290.13&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 296.88 L 349.5 287.88 L 354 290.13 L 358.5 287.88 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-19&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;218&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 238px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Transfer to CPU&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;243&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Transfer to CPU&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-20&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;298&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 318px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;&lt;font face=&#34;serif&#34;&gt;Send to FFmpeg&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;323&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Send to FFmpeg&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-22&#34;&gt;&lt;g&gt;&lt;rect x=&#34;286&#34; y=&#34;6&#34; width=&#34;136&#34; height=&#34;30&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 134px; height: 1px; padding-top: 21px; margin-left: 287px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0px; text-align: center;&#34; data-drawio-colors=&#34;color: rgb(0, 0, 0); &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;&#34;&gt;Second Thread&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;26&#34; fill=&#34;rgb(0, 0, 0)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Second Thread&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e-0E7eQsKeKwqEextsQo-26&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 210 238 Q 240 236 240 157 Q 240 78 266.13 78&#34; fill=&#34;none&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; stroke-dasharray=&#34;3 3&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 272.88 78 L 263.88 82.5 L 266.13 78 L 263.88 73.5 Z&#34; fill=&#34;rgb(0, 0, 0)&#34; stroke=&#34;rgb(0, 0, 0)&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;

&lt;p&gt;Every frame is copied to an intermediate buffer, because we don&amp;rsquo;t know its duration until the next frame.
Then, bxt-rs converts its colors from RGB to YUV 4:2:0 on the GPU, transfers the result to the main memory, and sends it to FFmpeg for encoding.&lt;/p&gt;
&lt;p&gt;With frame blending, the steps are a bit different:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!-- Do not edit this file with editors other than draw.io --&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background: transparent; background-color: transparent; color-scheme: light dark;&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;450px&#34; height=&#34;515px&#34; viewBox=&#34;-0.5 -0.5 450 515&#34; content=&#34;&amp;lt;mxfile host=&amp;quot;app.diagrams.net&amp;quot; agent=&amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0&amp;quot; version=&amp;quot;26.0.16&amp;quot; pages=&amp;quot;3&amp;quot; scale=&amp;quot;1&amp;quot; border=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Page-1&amp;quot; id=&amp;quot;d1g8u6Vk2-SD41G-Ihbw&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;1538&amp;quot; dy=&amp;quot;1424&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;1&amp;quot; parent=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-21&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;190&amp;quot; height=&amp;quot;355&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-8&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-9&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-12&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-27&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Copy to&amp;amp;lt;br&amp;amp;gt;intermediate&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-28&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-29&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-22&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-26&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Copy of Page-1&amp;quot; id=&amp;quot;reyh5qv1NCDdclKMQTgt&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;2023&amp;quot; dy=&amp;quot;1564&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-2&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;190&amp;quot; height=&amp;quot;514&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-3&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-7&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture sub-frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-10&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-1&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot; target=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Copy to intermediate&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-13&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-15&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-17&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;370&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;450&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-18&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-19&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-2&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-3&amp;quot; value=&amp;quot;Yes&amp;quot; style=&amp;quot;edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;e4IwKG6EhxNuk4HQo8EN-2&amp;quot; vertex=&amp;quot;1&amp;quot; connectable=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-0.45&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint as=&amp;quot;offset&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Is frame complete?&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;dashed=1;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-2&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot; target=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Accumulate&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Copy of Page-1&amp;quot; id=&amp;quot;sYl0cKrkGWZCpCTy2JTT&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;754&amp;quot; dy=&amp;quot;1424&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-2&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;414&amp;quot; height=&amp;quot;355&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-3&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-7&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture sub-frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-10&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-9&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-4&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-4&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot; target=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Accumulate&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-13&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-15&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-17&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-16&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;538&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-18&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-19&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-8&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-12&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot; source=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot; target=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-14&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-3&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Is frame complete?&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;a8X3TyM1PaIO5vLbuULQ-7&amp;quot; value=&amp;quot;&amp;amp;lt;div&amp;amp;gt;Yes&amp;amp;lt;/div&amp;amp;gt;&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;OY8x8Z2hVSDTFrxM6TFX-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;485&amp;quot; y=&amp;quot;125&amp;quot; width=&amp;quot;42&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;&amp;lt;/mxfile&amp;gt;&amp;#xA;&#34;&gt;&lt;defs/&gt;&lt;g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-0&#34;&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-1&#34;&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-2&#34;&gt;&lt;g&gt;&lt;rect x=&#34;259&#34; y=&#34;0&#34; width=&#34;190&#34; height=&#34;514&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-3&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 98 Q 130 98 130 130.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 136.88 L 125.5 127.88 L 130 130.13 L 134.5 127.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-4&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;58&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 78px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Run game tick&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;83&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-5&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 178 Q 130 178 130 210.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 216.88 L 125.5 207.88 L 130 210.13 L 134.5 207.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-6&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;138&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 158px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Draw frame&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;163&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-7&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 258 Q 130 258 130 290.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 296.88 L 125.5 287.88 L 130 290.13 L 134.5 287.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-8&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;218&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 238px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Capture sub-frame&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;243&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Capture sub-frame&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-9&#34;&gt;&lt;g&gt;&lt;rect x=&#34;50&#34; y=&#34;298&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 318px; margin-left: 51px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Swap buffers&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;130&#34; y=&#34;323&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-10&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 130 338 Q 130 356 65 351 Q 0 346 0 201 Q 0 56 65 43 Q 130 30 130 50.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 130 56.88 L 125.5 47.88 L 130 50.13 L 134.5 47.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;8WT170UZGHQjFb8un2Fj-1&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 98 Q 354 98 354 130.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 136.88 L 349.5 127.88 L 354 130.13 L 358.5 127.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-12&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;58&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 78px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Copy to intermediate&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;83&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Copy to intermediate&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-13&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 338 Q 354 338 354 370.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 376.88 L 349.5 367.88 L 354 370.13 L 358.5 367.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-14&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;298&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 318px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Convert colors&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;323&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Convert colors&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-15&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 418 Q 354 418 354 450.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 456.88 L 349.5 447.88 L 354 450.13 L 358.5 447.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-16&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;378&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 398px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Transfer to CPU&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;403&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Transfer to CPU&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-17&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;458&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 478px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Send to FFmpeg&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;483&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Send to FFmpeg&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-18&#34;&gt;&lt;g&gt;&lt;rect x=&#34;286&#34; y=&#34;6&#34; width=&#34;136&#34; height=&#34;30&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 134px; height: 1px; padding-top: 21px; margin-left: 287px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Second Thread&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;26&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Second Thread&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;GbUAvLM53m31CWMxQ_1v-19&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 210 238 Q 240 236 240 157 Q 240 78 266.13 78&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; stroke-dasharray=&#34;3 3&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 272.88 78 L 263.88 82.5 L 266.13 78 L 263.88 73.5 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e4IwKG6EhxNuk4HQo8EN-2&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 258 Q 354 258 354 290.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 296.88 L 349.5 287.88 L 354 290.13 L 358.5 287.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e4IwKG6EhxNuk4HQo8EN-3&#34;&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 270px; margin-left: 355px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; background-color: light-dark(#ffffff, var(--ge-dark-color, #121212)); white-space: nowrap; &#34;&gt;Yes&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;355&#34; y=&#34;274&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Yes&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;e4IwKG6EhxNuk4HQo8EN-0&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;218&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; stroke-dasharray=&#34;3 3&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 238px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Is frame complete?&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;243&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Is frame complete?&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;8WT170UZGHQjFb8un2Fj-2&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 354 178 Q 354 178 354 210.13&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 354 216.88 L 349.5 207.88 L 354 210.13 L 358.5 207.88 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;8WT170UZGHQjFb8un2Fj-0&#34;&gt;&lt;g&gt;&lt;rect x=&#34;274&#34; y=&#34;138&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; style=&#34;fill: light-dark(rgb(245, 245, 245), rgb(26, 26, 26)); stroke: light-dark(rgb(102, 102, 102), rgb(149, 149, 149));&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 158px; margin-left: 275px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #333333; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;Helvetica&amp;quot;; color: light-dark(#333333, #c1c1c1); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;font face=&#34;serif&#34;&gt;Accumulate&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;354&#34; y=&#34;163&#34; fill=&#34;#333333&#34; font-family=&#34;&amp;quot;Helvetica&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Accumulate&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;

&lt;p&gt;After obtaining the frame duration, bxt-rs computes the weight and accumulates the sub-frame into the sampling buffer.
For most frames this is where the process ends.
The recorder keeps track of accumulated frame time.
As soon as we&amp;rsquo;ve accumulated a full output frame worth of sub-frames, it&amp;rsquo;s sent through the usual steps of color conversion and FFmpeg encoding.
The sampling buffer is then cleared to zeroes, ready to accumulate for the next video frame.&lt;/p&gt;
&lt;p&gt;There are a few edge cases to take care of.
First, as I mentioned before, the sub-frame can be covered by the exposure time only partially.
This is solved simply by reducing its accumulation weight: instead of &lt;span class=&#34;fraction&#34;&gt;&lt;span class=&#34;top&#34;&gt;full sub-frame duration&lt;/span&gt;&lt;span class=&#34;bottom&#34;&gt;exposure&lt;/span&gt;&lt;/span&gt;, the weight becomes &lt;span class=&#34;fraction&#34;&gt;&lt;span class=&#34;top&#34;&gt;exposed sub-frame duration&lt;/span&gt;&lt;span class=&#34;bottom&#34;&gt;exposure&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Then, a sub-frame may actually be split in half by an output frame boundary, and even span several output frames all by itself.
For example, this can happen when a TAS uses a long 4 FPS (0.25 ms) frame for a trick, which needs to be recorded as several output frames in a 60 FPS video.
Turns out this is also easy to handle: since we store the frame in an intermediate buffer, we can just tell the sampling code to accumulate it multiple times with different weights, while writing output frames in between.&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!-- Do not edit this file with editors other than draw.io --&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background: transparent; background-color: transparent; color-scheme: light dark;&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;581px&#34; height=&#34;134px&#34; viewBox=&#34;-0.5 -0.5 581 134&#34; content=&#34;&amp;lt;mxfile host=&amp;quot;app.diagrams.net&amp;quot; agent=&amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0&amp;quot; version=&amp;quot;26.0.16&amp;quot; pages=&amp;quot;4&amp;quot; scale=&amp;quot;1&amp;quot; border=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Page-1&amp;quot; id=&amp;quot;d1g8u6Vk2-SD41G-Ihbw&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;1538&amp;quot; dy=&amp;quot;1424&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;1&amp;quot; parent=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-21&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;190&amp;quot; height=&amp;quot;355&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-8&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-9&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-12&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-7&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-3&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-27&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Copy to&amp;amp;lt;br&amp;amp;gt;intermediate&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-28&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-18&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-29&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-19&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-20&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-22&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e-0E7eQsKeKwqEextsQo-26&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot; source=&amp;quot;e-0E7eQsKeKwqEextsQo-6&amp;quot; target=&amp;quot;e-0E7eQsKeKwqEextsQo-17&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Copy of Page-1&amp;quot; id=&amp;quot;reyh5qv1NCDdclKMQTgt&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;1538&amp;quot; dy=&amp;quot;1424&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-2&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=none;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;299&amp;quot; y=&amp;quot;-8&amp;quot; width=&amp;quot;190&amp;quot; height=&amp;quot;514&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-3&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Run game tick&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-5&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-6&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Draw frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-7&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Capture sub-frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Swap buffers&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;90&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-10&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-9&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-4&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;106&amp;quot; y=&amp;quot;-37&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;156&amp;quot; y=&amp;quot;-87&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;348&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;338&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;40&amp;quot; y=&amp;quot;48&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;170&amp;quot; y=&amp;quot;22&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-1&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot; target=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Copy to intermediate&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;50&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-13&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Convert colors&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;290&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-15&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-17&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-16&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Transfer to CPU&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;370&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-17&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Send to FFmpeg&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;450&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-18&amp;quot; value=&amp;quot;Second Thread&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;326&amp;quot; y=&amp;quot;-2&amp;quot; width=&amp;quot;136&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;GbUAvLM53m31CWMxQ_1v-19&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;GbUAvLM53m31CWMxQ_1v-8&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-12&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;242&amp;quot; y=&amp;quot;208&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;292&amp;quot; y=&amp;quot;158&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;Array as=&amp;quot;points&amp;quot;&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;228&amp;quot; /&amp;gt;&amp;#xA;              &amp;lt;mxPoint x=&amp;quot;280&amp;quot; y=&amp;quot;70&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;/Array&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-2&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot; target=&amp;quot;GbUAvLM53m31CWMxQ_1v-14&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-3&amp;quot; value=&amp;quot;Yes&amp;quot; style=&amp;quot;edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; connectable=&amp;quot;0&amp;quot; parent=&amp;quot;e4IwKG6EhxNuk4HQo8EN-2&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-0.45&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint as=&amp;quot;offset&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Is frame complete?&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;dashed=1;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;210&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-2&amp;quot; style=&amp;quot;edgeStyle=none;curved=1;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=12;startSize=8;endSize=8;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot; source=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot; target=&amp;quot;e4IwKG6EhxNuk4HQo8EN-0&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;8WT170UZGHQjFb8un2Fj-0&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;Accumulate&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=1;whiteSpace=wrap;html=1;fontSize=16;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;GbUAvLM53m31CWMxQ_1v-1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;314&amp;quot; y=&amp;quot;130&amp;quot; width=&amp;quot;160&amp;quot; height=&amp;quot;40&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram id=&amp;quot;zeRAyFZfmWFLSPurE-ql&amp;quot; name=&amp;quot;Page-3&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;1279&amp;quot; dy=&amp;quot;585&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;1&amp;quot; parent=&amp;quot;0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-1&amp;quot; value=&amp;quot;&amp;amp;lt;font face=&amp;amp;quot;serif&amp;amp;quot;&amp;amp;gt;one long sub-frame&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/font&amp;amp;gt;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#ffe6cc;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-173.75&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;266.5&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-3&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#ffe6cc;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-241.75&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-4&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#ffe6cc;gradientColor=#ffe6cc00;gradientDirection=west;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-309.75&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-5&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#ffe6cc;gradientColor=#ffe6cc00;gradientDirection=east;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;163.75&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-6&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#ffe6cc;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;95.75&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-9&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#cccccc;gradientDirection=east;fontColor=#333333;gradientColor=#cccccc00;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;199&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-11&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;131&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-12&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;63&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-13&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-5&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-14&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-73&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-15&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-141&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-16&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-209&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-17&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-277&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-20&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#cccccc;fontColor=#333333;gradientColor=#cccccc00;gradientDirection=west;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-345&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-21&amp;quot; value=&amp;quot;output frames&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-136.5&amp;quot; y=&amp;quot;201&amp;quot; width=&amp;quot;193&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-22&amp;quot; value=&amp;quot;acc(0.5)&amp;amp;lt;br style=&amp;amp;quot;font-size: 10px;&amp;amp;quot;&amp;amp;gt;encode()&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-217&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;76&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-23&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;exitX=1;exitY=1;exitDx=0;exitDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-141&amp;quot; y=&amp;quot;262&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-141&amp;quot; y=&amp;quot;175&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-24&amp;quot; value=&amp;quot;acc(1.0)&amp;amp;lt;br style=&amp;amp;quot;font-size: 10px;&amp;amp;quot;&amp;amp;gt;encode()&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-149.4&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;76&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-25&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;exitX=1;exitY=1;exitDx=0;exitDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-73.4&amp;quot; y=&amp;quot;262&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-73.4&amp;quot; y=&amp;quot;175&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-26&amp;quot; value=&amp;quot;acc(1.0)&amp;amp;lt;br style=&amp;amp;quot;font-size: 10px;&amp;amp;quot;&amp;amp;gt;encode()&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-81.4&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;76&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-27&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;exitX=1;exitY=1;exitDx=0;exitDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-5.400000000000006&amp;quot; y=&amp;quot;262&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-5.400000000000006&amp;quot; y=&amp;quot;175&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-28&amp;quot; value=&amp;quot;acc(1.0)&amp;amp;lt;br style=&amp;amp;quot;font-size: 10px;&amp;amp;quot;&amp;amp;gt;encode()&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-13.400000000000006&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;76&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-29&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;exitX=1;exitY=1;exitDx=0;exitDy=0;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;62.599999999999994&amp;quot; y=&amp;quot;262&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;62.599999999999994&amp;quot; y=&amp;quot;175&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-30&amp;quot; value=&amp;quot;acc(0.5)&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontFamily=serif;&amp;quot; vertex=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;19.749999999999993&amp;quot; y=&amp;quot;261&amp;quot; width=&amp;quot;76&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;tqOXwo1LjQQfm3hKU_K3-31&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;dashed=1;&amp;quot; edge=&amp;quot;1&amp;quot; parent=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;95&amp;quot; y=&amp;quot;285&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;95.35&amp;quot; y=&amp;quot;175&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;  &amp;lt;diagram name=&amp;quot;Copy of Page-3&amp;quot; id=&amp;quot;UTpYkEWcy_Hk31CU2jBx&amp;quot;&amp;gt;&amp;#xA;    &amp;lt;mxGraphModel dx=&amp;quot;1556&amp;quot; dy=&amp;quot;665&amp;quot; grid=&amp;quot;0&amp;quot; gridSize=&amp;quot;10&amp;quot; guides=&amp;quot;1&amp;quot; tooltips=&amp;quot;1&amp;quot; connect=&amp;quot;1&amp;quot; arrows=&amp;quot;1&amp;quot; fold=&amp;quot;1&amp;quot; page=&amp;quot;0&amp;quot; pageScale=&amp;quot;1&amp;quot; pageWidth=&amp;quot;850&amp;quot; pageHeight=&amp;quot;1100&amp;quot; math=&amp;quot;0&amp;quot; shadow=&amp;quot;0&amp;quot;&amp;gt;&amp;#xA;      &amp;lt;root&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-0&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-4&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=light-dark(#FFE6CC,#663300);gradientColor=#ffe6cc00;gradientDirection=west;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-271&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-5&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=light-dark(#FFE6CC,#663300);gradientColor=#ffe6cc00;gradientDirection=east;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;95&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-7&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#cccccc;gradientDirection=east;fontColor=#333333;gradientColor=#cccccc00;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;169&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-12&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-278&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;148&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-15&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#cccccc;fontColor=#333333;gradientColor=#cccccc00;gradientDirection=west;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-345&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;66&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;6PiHB-ODzZdevmaQpSf4-16&amp;quot; value=&amp;quot;output frames&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-345&amp;quot; y=&amp;quot;201&amp;quot; width=&amp;quot;193&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-0&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-129&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;148&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-1&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=#CCCCCC;fontColor=#333333;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;20&amp;quot; y=&amp;quot;206&amp;quot; width=&amp;quot;148&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-2&amp;quot; value=&amp;quot;one long sub-frame&amp;quot; style=&amp;quot;rounded=0;whiteSpace=wrap;html=1;fontSize=16;strokeColor=none;fillColor=light-dark(#FFE6CC,#663300);fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-204&amp;quot; y=&amp;quot;175&amp;quot; width=&amp;quot;298&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-13&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;shape=curlyBracket;whiteSpace=wrap;html=1;rounded=1;flipH=1;labelPosition=right;verticalLabelPosition=middle;align=left;verticalAlign=middle;fontSize=16;direction=north;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-204&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;74&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-14&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;shape=curlyBracket;whiteSpace=wrap;html=1;rounded=1;flipH=1;labelPosition=right;verticalLabelPosition=middle;align=left;verticalAlign=middle;fontSize=16;direction=north;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-129&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;148&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-15&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;shape=curlyBracket;whiteSpace=wrap;html=1;rounded=1;flipH=1;labelPosition=right;verticalLabelPosition=middle;align=left;verticalAlign=middle;fontSize=16;direction=north;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;20&amp;quot; y=&amp;quot;231&amp;quot; width=&amp;quot;74&amp;quot; height=&amp;quot;20&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-16&amp;quot; value=&amp;quot;acc(0.5)&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;div&amp;amp;gt;encode()&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=top;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-228&amp;quot; y=&amp;quot;245&amp;quot; width=&amp;quot;122&amp;quot; height=&amp;quot;58&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-17&amp;quot; value=&amp;quot;acc(1.0)&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;div&amp;amp;gt;encode()&amp;amp;lt;br&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=top;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-116&amp;quot; y=&amp;quot;245&amp;quot; width=&amp;quot;122&amp;quot; height=&amp;quot;58&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-18&amp;quot; value=&amp;quot;acc(0.5)&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=top;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-4&amp;quot; y=&amp;quot;245&amp;quot; width=&amp;quot;122&amp;quot; height=&amp;quot;58&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-19&amp;quot; value=&amp;quot;&amp;quot; style=&amp;quot;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;entryX=1;entryY=1;entryDx=0;entryDy=0;exitX=0;exitY=1;exitDx=0;exitDy=0;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; source=&amp;quot;YFXpl05kMYIcAbYatawa-20&amp;quot; target=&amp;quot;YFXpl05kMYIcAbYatawa-20&amp;quot; edge=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot; relative=&amp;quot;1&amp;quot; as=&amp;quot;geometry&amp;quot;&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;-345&amp;quot; y=&amp;quot;358&amp;quot; as=&amp;quot;sourcePoint&amp;quot; /&amp;gt;&amp;#xA;            &amp;lt;mxPoint x=&amp;quot;228&amp;quot; y=&amp;quot;357&amp;quot; as=&amp;quot;targetPoint&amp;quot; /&amp;gt;&amp;#xA;          &amp;lt;/mxGeometry&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;        &amp;lt;mxCell id=&amp;quot;YFXpl05kMYIcAbYatawa-20&amp;quot; value=&amp;quot;time&amp;quot; style=&amp;quot;text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontFamily=serif;&amp;quot; parent=&amp;quot;6PiHB-ODzZdevmaQpSf4-1&amp;quot; vertex=&amp;quot;1&amp;quot;&amp;gt;&amp;#xA;          &amp;lt;mxGeometry x=&amp;quot;-345&amp;quot; y=&amp;quot;273&amp;quot; width=&amp;quot;146&amp;quot; height=&amp;quot;30&amp;quot; as=&amp;quot;geometry&amp;quot; /&amp;gt;&amp;#xA;        &amp;lt;/mxCell&amp;gt;&amp;#xA;      &amp;lt;/root&amp;gt;&amp;#xA;    &amp;lt;/mxGraphModel&amp;gt;&amp;#xA;  &amp;lt;/diagram&amp;gt;&amp;#xA;&amp;lt;/mxfile&amp;gt;&amp;#xA;&#34;&gt;&lt;defs&gt;&lt;linearGradient x1=&#34;100%&#34; y1=&#34;0%&#34; x2=&#34;0%&#34; y2=&#34;0%&#34; id=&#34;drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc00_36210a_-1-light-dark_ffe6cc_663300_-1-e-0&#34;&gt;&lt;stop offset=&#34;0%&#34; stop-color=&#34;#FFE6CC&#34; style=&#34;stop-color: light-dark(rgb(255, 230, 204), rgb(102, 51, 0)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;stop offset=&#34;100%&#34; stop-color=&#34;#ffe6cc00&#34; style=&#34;stop-color: light-dark(rgba(255, 230, 204, 0), rgb(54, 33, 10)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;/linearGradient&gt;&lt;linearGradient x1=&#34;0%&#34; y1=&#34;0%&#34; x2=&#34;100%&#34; y2=&#34;0%&#34; id=&#34;drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc_663300_-1-light-dark_ffe6cc00_36210a_-1-e-0&#34;&gt;&lt;stop offset=&#34;0%&#34; stop-color=&#34;#FFE6CC&#34; style=&#34;stop-color: light-dark(rgb(255, 230, 204), rgb(102, 51, 0)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;stop offset=&#34;100%&#34; stop-color=&#34;#ffe6cc00&#34; style=&#34;stop-color: light-dark(rgba(255, 230, 204, 0), rgb(54, 33, 10)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;/linearGradient&gt;&lt;linearGradient x1=&#34;0%&#34; y1=&#34;0%&#34; x2=&#34;100%&#34; y2=&#34;0%&#34; id=&#34;drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc_3e3e3e_-1-light-dark_cccccc00_3e3e3e_-1-e-0&#34;&gt;&lt;stop offset=&#34;0%&#34; stop-color=&#34;#cccccc&#34; style=&#34;stop-color: light-dark(rgb(204, 204, 204), rgb(62, 62, 62)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;stop offset=&#34;100%&#34; stop-color=&#34;#cccccc00&#34; style=&#34;stop-color: light-dark(rgba(204, 204, 204, 0), rgb(62, 62, 62)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;/linearGradient&gt;&lt;linearGradient x1=&#34;100%&#34; y1=&#34;0%&#34; x2=&#34;0%&#34; y2=&#34;0%&#34; id=&#34;drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc00_3e3e3e_-1-light-dark_cccccc_3e3e3e_-1-e-0&#34;&gt;&lt;stop offset=&#34;0%&#34; stop-color=&#34;#cccccc&#34; style=&#34;stop-color: light-dark(rgb(204, 204, 204), rgb(62, 62, 62)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;stop offset=&#34;100%&#34; stop-color=&#34;#cccccc00&#34; style=&#34;stop-color: light-dark(rgba(204, 204, 204, 0), rgb(62, 62, 62)); stop-opacity: 1;&#34; stop-opacity=&#34;1&#34;/&gt;&lt;/linearGradient&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-0&#34;&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-1&#34;&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-4&#34;&gt;&lt;g&gt;&lt;rect x=&#34;74&#34; y=&#34;0&#34; width=&#34;66&#34; height=&#34;20&#34; fill=&#34;url(#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc00_36210a_-1-light-dark_ffe6cc_663300_-1-e-0)&#34; style=&#34;fill: url(&amp;quot;#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc00_36210a_-1-light-dark_ffe6cc_663300_-1-e-0&amp;quot;);&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-5&#34;&gt;&lt;g&gt;&lt;rect x=&#34;440&#34; y=&#34;0&#34; width=&#34;66&#34; height=&#34;20&#34; fill=&#34;url(#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc_663300_-1-light-dark_ffe6cc00_36210a_-1-e-0)&#34; style=&#34;fill: url(&amp;quot;#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_ffe6cc_663300_-1-light-dark_ffe6cc00_36210a_-1-e-0&amp;quot;);&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-7&#34;&gt;&lt;g&gt;&lt;rect x=&#34;514&#34; y=&#34;31&#34; width=&#34;66&#34; height=&#34;20&#34; fill=&#34;url(#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc_3e3e3e_-1-light-dark_cccccc00_3e3e3e_-1-e-0)&#34; style=&#34;fill: url(&amp;quot;#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc_3e3e3e_-1-light-dark_cccccc00_3e3e3e_-1-e-0&amp;quot;);&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-12&#34;&gt;&lt;g&gt;&lt;rect x=&#34;67&#34; y=&#34;31&#34; width=&#34;148&#34; height=&#34;20&#34; fill=&#34;#cccccc&#34; style=&#34;fill: light-dark(rgb(204, 204, 204), rgb(62, 62, 62));&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-15&#34;&gt;&lt;g&gt;&lt;rect x=&#34;0&#34; y=&#34;31&#34; width=&#34;66&#34; height=&#34;20&#34; fill=&#34;url(#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc00_3e3e3e_-1-light-dark_cccccc_3e3e3e_-1-e-0)&#34; style=&#34;fill: url(&amp;quot;#drawio-svg-aXgiq4DgGLyjqbFvBqgh-gradient-light-dark_cccccc00_3e3e3e_-1-light-dark_cccccc_3e3e3e_-1-e-0&amp;quot;);&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;6PiHB-ODzZdevmaQpSf4-16&#34;&gt;&lt;g&gt;&lt;rect x=&#34;0&#34; y=&#34;26&#34; width=&#34;193&#34; height=&#34;30&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 191px; height: 1px; padding-top: 41px; margin-left: 2px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: left; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;output frames&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;2&#34; y=&#34;46&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34;&gt;output frames&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-0&#34;&gt;&lt;g&gt;&lt;rect x=&#34;216&#34; y=&#34;31&#34; width=&#34;148&#34; height=&#34;20&#34; fill=&#34;#cccccc&#34; style=&#34;fill: light-dark(rgb(204, 204, 204), rgb(62, 62, 62));&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-1&#34;&gt;&lt;g&gt;&lt;rect x=&#34;365&#34; y=&#34;31&#34; width=&#34;148&#34; height=&#34;20&#34; fill=&#34;#cccccc&#34; style=&#34;fill: light-dark(rgb(204, 204, 204), rgb(62, 62, 62));&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-2&#34;&gt;&lt;g&gt;&lt;rect x=&#34;141&#34; y=&#34;0&#34; width=&#34;298&#34; height=&#34;20&#34; fill=&#34;#ffe6cc&#34; style=&#34;fill: light-dark(rgb(255, 230, 204), rgb(102, 51, 0));&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 296px; height: 1px; padding-top: 10px; margin-left: 142px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;one long sub-frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;290&#34; y=&#34;15&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;one long sub-frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-13&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 188 29 L 183 29 Q 178 29 178 39 L 178 56 Q 178 66 173 66 L 170.5 66 Q 168 66 173 66 L 175.5 66 Q 178 66 178 76 L 178 93 Q 178 103 183 103 L 188 103&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; transform=&#34;translate(0,66)scale(1,-1)translate(0,-66)rotate(-270,178,66)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-14&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 300 -8 L 295 -8 Q 290 -8 290 2 L 290 56 Q 290 66 285 66 L 282.5 66 Q 280 66 285 66 L 287.5 66 Q 290 66 290 76 L 290 130 Q 290 140 295 140 L 300 140&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; transform=&#34;translate(0,66)scale(1,-1)translate(0,-66)rotate(-270,290,66)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-15&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 412 29 L 407 29 Q 402 29 402 39 L 402 56 Q 402 66 397 66 L 394.5 66 Q 392 66 397 66 L 399.5 66 Q 402 66 402 76 L 402 93 Q 402 103 407 103 L 412 103&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; transform=&#34;translate(0,66)scale(1,-1)translate(0,-66)rotate(-270,402,66)&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-16&#34;&gt;&lt;g&gt;&lt;rect x=&#34;117&#34; y=&#34;70&#34; width=&#34;122&#34; height=&#34;58&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 120px; height: 1px; padding-top: 77px; margin-left: 118px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;acc(0.5)&lt;br /&gt;&lt;div&gt;encode()&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;178&#34; y=&#34;93&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;acc(0.5)...&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-17&#34;&gt;&lt;g&gt;&lt;rect x=&#34;229&#34; y=&#34;70&#34; width=&#34;122&#34; height=&#34;58&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 120px; height: 1px; padding-top: 77px; margin-left: 230px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;acc(1.0)&lt;br /&gt;&lt;div&gt;encode()&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;290&#34; y=&#34;93&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;acc(1.0)...&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-18&#34;&gt;&lt;g&gt;&lt;rect x=&#34;341&#34; y=&#34;70&#34; width=&#34;122&#34; height=&#34;58&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 120px; height: 1px; padding-top: 77px; margin-left: 342px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;acc(0.5)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;402&#34; y=&#34;93&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;acc(0.5)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-19&#34;&gt;&lt;g&gt;&lt;path d=&#34;M 0 128 Q 0 128 138.13 128&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; style=&#34;stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 144.88 128 L 135.88 132.5 L 138.13 128 L 135.88 123.5 Z&#34; fill=&#34;#000000&#34; style=&#34;fill: light-dark(rgb(0, 0, 0), rgb(255, 255, 255)); stroke: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id=&#34;YFXpl05kMYIcAbYatawa-20&#34;&gt;&lt;g&gt;&lt;rect x=&#34;0&#34; y=&#34;98&#34; width=&#34;146&#34; height=&#34;30&#34; fill=&#34;none&#34; stroke=&#34;none&#34; pointer-events=&#34;all&#34;/&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 144px; height: 1px; padding-top: 113px; margin-left: 2px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: left; color: #000000; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: &amp;quot;serif&amp;quot;; color: light-dark(#000000, #ffffff); line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;time&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;2&#34; y=&#34;118&#34; fill=&#34;light-dark(#000000, #ffffff)&#34; font-family=&#34;&amp;quot;serif&amp;quot;&#34; font-size=&#34;16px&#34;&gt;time&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;

&lt;h3 id=&#34;synchronization&#34;&gt;Synchronization &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#synchronization&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Since we store the sub-frame in an intermediate buffer, the accumulation step can run in parallel to the rendering and capturing of the next game frame.
Here, &amp;ldquo;in parallel&amp;rdquo; means both on CPU (with a second thread) and on GPU.
We therefore need to synchronize the GPU access to the intermediate buffer, so that the accumulation step won&amp;rsquo;t try to read from it at the same time as the capturing step is writing to it.&lt;/p&gt;
&lt;p&gt;For that we use the Vulkan memory barriers&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.
The intermediate frame processing in the accumulation step starts with a transfer → shader barrier and ends with a shader → transfer barrier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;intermediate_frame_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make the memory write performed by a transfer available.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make the memory visible for a shader read.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_READ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_acquired&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_accumulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;intermediate_frame_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Do the processing...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;intermediate_frame_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We were not writing anything, no memory write to make available.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make the memory visible to a transfer write.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_acquired&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_accumulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;intermediate_frame_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this command buffer effectively returns the intermediate frame back to the same state it was in.
This trick lets me accumulate either once or multiple times in a row without dealing with any sort of synchronization edge cases.&lt;/p&gt;
&lt;p&gt;But wait, the intermediate frame is not the only resource used for accumulation.
What about the sampling buffer?
It has two possible paths: either it can go for color conversion, where it will be read from, or we might accumulate into it again next sub-frame.
Turns out this is not a problem: we can set the destination access mask on the closing barrier to both shader reads (if we go for color conversion) and shader writes (if we accumulate more).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// There&amp;#39;s no opening barrier, actually,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// as the sampling buffer is already synchronized.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Do the processing...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sampling_buffer_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make the accumulation shader writes available.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make the memory visible to both shader reads and writes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_READ&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_accumulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This barrier will wait for the compute shader to finish.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// The next compute shader should wait for this barrier.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sampling_buffer_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We use two buffer, and we synchronized both of them.
We&amp;rsquo;re done, right?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s what I thought when I wrote this code, and the &lt;a href=&#34;https://github.com/KhronosGroup/Vulkan-ValidationLayers&#34;&gt;validation layers&lt;/a&gt; seemed to agree.
However, recording a video crashed my AMD driver a few seconds into the process.&lt;/p&gt;
&lt;p&gt;After trying several things, re-reading the &lt;a href=&#34;https://themaister.net/blog/2019/08/14/yet-another-blog-explaining-vulkan-synchronization/&#34;&gt;Vulkan synchronization blog-post&lt;/a&gt; and quadruple-checking my barriers, I was out of ideas.
I was too lazy to make a C reproducer for a Mesa bug report, so I added a fence wait, blocking the CPU until the GPU finishes the accumulation step.
This had a performance cost, but seemed to fix the issue.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// XXX: As far as I can tell, waiting for a fence here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// should not be required (and it makes the process quite
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// slower). Unfortunately, I&amp;#39;m getting GPU fence timeouts if
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// I don&amp;#39;t do it. Maybe there&amp;#39;s a synchronization bug in the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// code, but I don&amp;#39;t see it, and the validation layers are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// silent too.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;FenceCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_accumulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SubmitInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue_submit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// I use tracing spans with tracing-chrome for profiling.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_span&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;info_span!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;wait for fence&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entered&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Block everything and wait until the GPU finishes the work.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wait_for_fences&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;max_value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroy_fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Several months passed, players were recording videos with motion blur just fine, but The Fence kept sitting in my head.
This recording code is supposed to be really fast, and I have this useless idle time right in the middle of the hottest loop.&lt;/p&gt;
&lt;p&gt;Just look at the performance profile&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; with no Fence:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-no-fence.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-no-fence.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The X axis on these graphs represents time, and colored rectangles correspond to particular ranges of code that I&amp;rsquo;ve annotated, usually functions.
So if the rectangle is short, that means the function took little time, and the longer a rectangle is, the longer that function took.
There are two distinct rows on the graph separated with a gray line&amp;mdash;these are the two threads: the recording thread at the top and the main game thread at the bottom.&lt;/p&gt;
&lt;p&gt;This graph above shows four sub-frames during one of the recording sessions.
All empty space between the occasional colored area is the game&amp;rsquo;s own processing.
That is, my video recording logic takes almost no time at all&amp;mdash;less than 10% of overhead.&lt;/p&gt;
&lt;p&gt;Now compare that to The Fence:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-fence.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-fence.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Ouch!
Almost all bxt-rs time is the wait, and sometimes it even eats into (and delays!) the next frame&amp;rsquo;s processing.
It&amp;rsquo;s helped only by the fact it happens on another thread.
Certainly in other recording scenarios this overhead will be much worse.
Hopefully you can see why this Fence had firmly leased a plot in the back of my mind.&lt;/p&gt;
&lt;p&gt;Around that time I was testing my relatively slow ThinkPad T495s with a 4K screen.
It&amp;rsquo;s got no discrete GPU and its AMD Ryzen 5 3500U CPU is an ultra-low-power model, which means lower performance.
I was occasionally getting random GPU crashes while using the desktop.
I found an &lt;a href=&#34;https://gitlab.freedesktop.org/drm/amd/-/issues/2447&#34;&gt;AMDGPU bug report&lt;/a&gt; about it and jumped in to help diagnose the problem.&lt;/p&gt;
&lt;p&gt;There seemed to be several underlying issues at play, but for my laptop I found a consistent reproducer with a heavy Blender file.
The developers pinned one of the issues down to a bug in the threaded graphics driver implementation.
The workaround was to disable the threads with &lt;code&gt;GALLIUM_THREAD=0&lt;/code&gt;, which for me fully fixed the Blender reproducer.&lt;/p&gt;
&lt;p&gt;This Blender crash visually looked exactly the same as my sampling video recording crash, so naturally I decided to give it a go.
I removed The Fence, set &lt;code&gt;GALLIUM_THREAD=0&lt;/code&gt;, started recording my test demo with frame blending.
It recorded fine.
Hooray, mystery solved!
It was a Mesa threading bug.
I &lt;a href=&#34;https://github.com/YaLTeR/bxt-rs/commit/4a00b772eb9d08874775ade287baf3e9ae7670a2&#34;&gt;committed&lt;/a&gt; the fence removal and documented the workaround in the README.&lt;/p&gt;
&lt;p&gt;A week later an NVIDIA user reports corrupted video frames during recording.&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Well.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try with The Fence back, I guess.&lt;/p&gt;
&lt;p&gt;No corruption.&lt;/p&gt;
&lt;p&gt;At this point I was rather lost.
For me, the validation layers were completely silent no matter what I tried, both when my GPU worked fine and when it crashed.
I decided to give it one last chance, and asked my NVIDIA user friend to record without the fence, and with the validation layers.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2023-07-11T15:31:23.886949Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xaded368, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xaded368[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.887111Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xaded368[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
2023-07-11T15:31:23.888095Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xadf1188, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xadf1188[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.888272Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xadf1188[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
2023-07-11T15:31:23.912888Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xaded368, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xaded368[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.913049Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xaded368[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
2023-07-11T15:31:23.914085Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xadf1188, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xadf1188[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.914266Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xadf1188[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
2023-07-11T15:31:23.920305Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xaded368, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xaded368[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.920462Z  INFO acquire:acquire_image: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xaded368[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
2023-07-11T15:31:23.920610Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkBeginCommandBuffer-commandBuffer-00049 ] Object 0: handle = 0xadf1188, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x84029a9f | vkBeginCommandBuffer() on active VkCommandBuffer 0xadf1188[] before it has completed. You must check command buffer fence before this call. The Vulkan spec states: commandBuffer must not be in the recording or pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00049)
2023-07-11T15:31:23.920780Z  INFO accumulate:accumulate{weight=0.008333333767950535}: bxt_rs::vulkan: ERROR VALIDATION Validation Error: [ VUID-vkQueueSubmit-pCommandBuffers-00071 ] Object 0: handle = 0xaed7188, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x2e2f4d65 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] VkCommandBuffer 0xadf1188[] is already in use and is not marked for simultaneous use. The Vulkan spec states: If any element of the pCommandBuffers member of any element of pSubmits was not recorded with the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, it must not be in the pending state (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkQueueSubmit-pCommandBuffers-00071)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip;oh.
The important part here is: &lt;code&gt;vkBeginCommandBuffer() on active VkCommandBuffer 0xaded368[] before it has completed&lt;/code&gt;.
Without The Fence, my recording is calling accumulate so fast that the GPU shader from the last call is still running.
🤦
To make matters worse, the same apparently happens with copying the game&amp;rsquo;s frame to the intermediate buffer.
The Fence avoided the issue by waiting for the shader completion right after starting it.&lt;/p&gt;
&lt;p&gt;Well!
The &lt;a href=&#34;https://github.com/YaLTeR/bxt-rs/commit/7ec7cd3e414236e0ef43eb59e66d1c7d9da99fca&#34;&gt;proper fix&lt;/a&gt; was rather straightforward, and in fact pretty similar to The Fence.
We still have to wait for the GPU to finish, but we don&amp;rsquo;t have to wait right &lt;em&gt;after&lt;/em&gt; starting the work.
Instead, we can get a bit of parallelization back by waiting right &lt;em&gt;before&lt;/em&gt; starting the next batch of work.
This gets most of the fence-less performance back while working perfectly fine on both AMD and NVIDIA.
The Mesa bug was not involved after all.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the performance graph to confirm it:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Looks almost the same as the fence-less graph above, save for the tiny pink areas where the GPU is waiting for the previous frame&amp;rsquo;s command buffer.&lt;/p&gt;
&lt;p&gt;Actually, further into the recording my GPU starts exhibiting some funny behavior where the waits gradually increase, and then reset back to nothing at an output frame boundary:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence-2.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence-2.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;My guess here is that the GPU heats up and starts downclocking, so the shaders start taking longer to run.
And at an output frame boundary the long main memory transfer gives the GPU some breathing room to cool back down.&lt;/p&gt;
&lt;p&gt;And on my NVIDIA user friend&amp;rsquo;s setup the wait times seem straight up random:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence-nvidia.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/perf-new-fence-nvidia.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Well, either way, the issue is fixed, and I&amp;rsquo;m parallelizing as much as possible, as confirmed by the performance measurements.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still not sure why the validation layers didn&amp;rsquo;t catch the bug on my system.
Maybe they weren&amp;rsquo;t recent enough, so this check hadn&amp;rsquo;t been added yet?
Regardless, it seems a good idea to run the validation layers on different drivers and GPU vendors before declaring the code working fine.&lt;/p&gt;
&lt;h3 id=&#34;overhead&#34;&gt;Overhead &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#overhead&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Measuring overall video recording performance in Half-Life is difficult because, when the recording overhead is sufficiently low, the speed is fully dominated by how fast your computer can actually play a particular demo file.
It&amp;rsquo;s especially challenging on AMD GPUs which are known to have worse performance for legacy OpenGL games such as Half-Life, compared to NVIDIA.
Like, here on my system I can look into one corner of the map and get 2000 FPS, then look into a different corner and get 200 FPS.&lt;/p&gt;
&lt;p&gt;To get a somewhat reasonable measure of performance, I picked a specific demo (my kz_ytt_ancient TAS, same as the video at the very top of this post) and played it with and without capturing on two of my laptops.
I used a resolution of 2560×1440 with 60 output FPS, which is a fairly normal recording target for today.&lt;/p&gt;
&lt;p&gt;For these measurements I used the &lt;a href=&#34;https://github.com/wolfpld/tracy&#34;&gt;Tracy&lt;/a&gt; profiler, which is a low-overhead game-oriented profiler.
It automatically shows histograms and statistics for frame times and regions, making it very convenient for performance analysis.&lt;/p&gt;
&lt;p&gt;First, the results on my fast laptop: Lenovo Legion 7 Gen 7 AMD with a Ryzen 7 6800H CPU with an RX 6700M discrete GPU.
Here I used 7200 SPS, the bxt-rs default.
During recording, the demo is played at a fixed timestep of 7200 FPS, so to measure the recording overhead, for the non-recording run I also play the demo at 7200 FPS.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with normal demo playback with no recording.
Please note that all histograms below use &lt;em&gt;logarithmic scale&lt;/em&gt; for the X axis.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-playback-fps.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-playback-fps.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;These are frame time statistics: they show a histogram of how long each individual frame took to process, as well as the mean and the median, and the equivalent FPS values.&lt;/p&gt;
&lt;p&gt;As you can see there&amp;rsquo;s quite a bit of variation in frame times (note the logarithmic scale!), but the median frame time is 1.21 ms, or 828 FPS.
This is measured across 211,876 total frames.&lt;/p&gt;
&lt;p&gt;Next, let&amp;rsquo;s run the same demo while recording a video with motion blur.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-fps.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-fps.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The distribution looks similar, but there&amp;rsquo;s a tail on the right.
This tail contains the one-in-120 frames which complete the sampling buffer and cause an output frame to be transferred to the main memory and sent to FFmpeg for encoding.
However, this happens infrequently enough, so the median frame time increased by just 0.16 ms, or 160 µs, compared to no recording.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the overhead specifically.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-overhead.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-overhead.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;These are statistics for just the bxt-rs recording code.
They correspond to extra work done on the main thread during recording on top of the normal game rendering.&lt;/p&gt;
&lt;p&gt;As you can see, this overhead is mostly sitting at around 113 µs, just like the frame time difference told us.
And once again there&amp;rsquo;s a small tail on the right, corresponding to the output frame main memory transfer and encoding.&lt;/p&gt;
&lt;p&gt;Overall this overhead accounts for 27.89 s out of 4:12.9 of recording time, or about 11% for this demo and setup.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s look at the results from my ThinkPad T495s with its Ryzen 5 3500U CPU and no discrete GPU.
I reduced the SPS from 7200 to 1800 here because the rendering was just too slow unfortunately, and I didn&amp;rsquo;t feel like waiting that long.&lt;/p&gt;
&lt;p&gt;First, the statistics without video recording.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-playback-fps.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-playback-fps.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;You can immediately see the FPS taking a 4× drop compared to the beefier laptop.
There&amp;rsquo;s also a tail on the right: I found that the map contains one specific spot that the integrated GPU really struggles with.
In fact, it&amp;rsquo;s clearly visible as red on the frame times chart that Tracy provides:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-playback-frametimes.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-playback-frametimes.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s look at the graphs while recording with motion blur.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-fps.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-fps.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Here you can see the median frame time increased from 4.92 ms all the way up to 15.32 ms.
Looks like bxt-rs recording has a sizeable overhead on this setup.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-overhead.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-overhead.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Hm, doesn&amp;rsquo;t look too bad, just 1.36 ms in the median.
Now, one thing to remember is that since we&amp;rsquo;re recording at four times fewer SPS, we&amp;rsquo;re having a long output frame once every 30 frames rather than once every 120 frames, so they have a larger compounding impact.&lt;/p&gt;
&lt;p&gt;But it seems that there&amp;rsquo;s a more important issue at play.
My guess is that the GPU work for accumulating the sampling buffer every frame overlaps with and slows down the GPU work that goes into rendering the game&amp;mdash;the integrated GPU isn&amp;rsquo;t powerful enough to do both at the same time without a slowdown.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-waits.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-waits.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Looking at the fence wait statistics, which show how long the second thread is waiting for the last frame&amp;rsquo;s GPU work to finish, seems to confirm this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-fence.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-tp-sampling-fence.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;While plenty of waits are very short (the previous frame&amp;rsquo;s GPU work had already completed by the time the next frame has started, so there&amp;rsquo;s no wait), there&amp;rsquo;s also a big chunk in the higher ranges, up to 10 ms.
Compare this to the statistics on the fast laptop:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-fence.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/stats-sampling-fence.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Yeah, the discrete GPU has got no problem at all doing sampling accumulation and game rendering at the same time.&lt;/p&gt;
&lt;p&gt;To sum up, for this particular testing scenario I&amp;rsquo;m seeing about 15% recording overhead for a laptop with a discrete GPU, and about 200% recording overhead for a laptop with a weak integrated GPU.
Since with this setup the fast laptop manages around 730 real-time FPS during recording, and the demo plays back at 7200 FPS, the whole process goes about ten times slower than real-time.&lt;/p&gt;
&lt;p&gt;Sidenote: I &lt;em&gt;love&lt;/em&gt; how snappy everything in Tracy is.
All UI zooming and panning and resizing works in real-time with little dropped frames on my 165 Hz screen, despite the seemingly huge amounts of data involved.
I guess Tracy developers put their own work to excellent use on Tracy itself.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#conclusion&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I released video recording with motion blur as part of &lt;a href=&#34;https://github.com/YaLTeR/bxt-rs/releases/tag/4.0&#34;&gt;bxt-rs 4.0&lt;/a&gt;.
It ended up a bit overshadowed by the big new piece of functionality that is the TAS Editor 2, but most of the people who needed video recording have already been using the development snapshots anyway.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/JEwbtaIajOI&#34;&gt;There&lt;/a&gt; &lt;a href=&#34;https://youtu.be/uPIO_Em-DNQ&#34;&gt;have&lt;/a&gt; &lt;a href=&#34;https://youtu.be/f2hqHGSAxPI&#34;&gt;been&lt;/a&gt; a &lt;a href=&#34;https://youtu.be/nCbt7eA8IiI&#34;&gt;bunch&lt;/a&gt; of &lt;a href=&#34;https://youtu.be/lL_bHezFoBE&#34;&gt;videos&lt;/a&gt; recorded with this motion blur implementation already, and I&amp;rsquo;m glad to see that it had caught on, with some channels using it even for &lt;a href=&#34;https://youtu.be/9AZ75_THwSU&#34;&gt;the most recent uploads&lt;/a&gt;.
This is mainly thanks to my aforementioned NVIDIA user friend recommending the tool to people in the Counter-Strike circles, while also implementing several features they&amp;rsquo;ve been asking for.&lt;/p&gt;
&lt;p&gt;I personally used the motion blur recording for my most recent TASes at 8K60 resolution just fine with no issues.
This is roughly how fast that goes:&lt;/p&gt;
&lt;figure&gt;
    &lt;video controls src=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/recording-speed.mp4&#34;&gt;&lt;/video&gt;
&lt;/figure&gt;

&lt;p&gt;Remember that this is recording &lt;em&gt;at 8K resolution, that is 7680×4320 pixels, at 7200 FPS&lt;/em&gt;.
The short pauses you might notice are the moments when an output frame is completed and sent over to the main memory and to FFmpeg.
Furthermore, this is on an AMD GPU which is known to have poorer performance with the legacy OpenGL used by Half-Life.
Pretty fast all things considered.&lt;/p&gt;
&lt;p&gt;The final output video for that is &lt;a href=&#34;https://youtu.be/GnUh6b5NxNo&#34;&gt;https://youtu.be/GnUh6b5NxNo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;rsquo;s still potential for improvement.&lt;/p&gt;
&lt;p&gt;For one thing, as I noted in the previous post, it&amp;rsquo;s possible to do encoding on the GPU using a hardware encoder.
This will eliminate the CPU transfer of the full unencoded frame, which is very likely the main contributing factor to those short pauses you see on the video above.
For very high resolutions it would also be potentially faster than libx264 (although I guess it would run into the hardware encoder size limits), while allowing to use newer compression standards, like AV1, which are &lt;em&gt;much&lt;/em&gt; more efficient at high resolution.&lt;/p&gt;
&lt;p&gt;Then there&amp;rsquo;s the question of SPS.
My chosen default of 7200 SPS is probably way too high for most demos, and you can get the same quality video with lower values.
This would mean the game has fewer frames to render, which is the biggest bottleneck in the recording process.&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s quite difficult to estimate a good SPS value ahead of time as it would require something like computing the optical flow (pixel movement vectors) for every frame of the demo to find the largest jump.
You have to do it ahead of time because Half-Life&amp;rsquo;s demo interpolation for some reason &lt;em&gt;really dislikes it&lt;/em&gt; when you change the FPS mid-playback, and produces very uneven videos.
I went with a default SPS this high as a safe option, because the relatively small recording overhead allows me.&lt;/p&gt;
&lt;p&gt;One very interesting idea is exposure greater than a single frame.
It might not make much sense with the real world film, but in-game you just need to take some samples from the previous frames and accumulate them into the next frame.
This would allow, for example, having the same amount of blur on a 120 FPS video as on a 60 FPS video with a full-frame exposure.
A full-frame exposure on a 120 FPS video is equivalent to a half-frame exposure on a 60 FPS video, so right now the best you can get is half the blur.&lt;/p&gt;
&lt;p&gt;Unfortunately, as far as I can tell, the general multi-frame exposure case requires keeping around &lt;em&gt;all&lt;/em&gt; individual sub-frames to be able to pick and accumulate them for the next frame.
If exposure is limited to whole frames, then it should be possible to only keep around one partially-accumulated frame for every whole frame of exposure, which is much more reasonable, but still complicated to implement.&lt;/p&gt;
&lt;p&gt;Either way, I&amp;rsquo;m glad to have this code released and this blog post out.
It&amp;rsquo;s been a good Vulkan diving practice and an interesting parallelism and correctness exercise.
I hope you enjoyed the read and learned something useful!&lt;/p&gt;
&lt;h2 id=&#34;appendix-interactive-widget&#34;&gt;Appendix: Interactive Widget &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#appendix-interactive-widget&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/#samplingPlayground&#34;&gt;interactive widget&lt;/a&gt; above uses WebGL and a frame averaging shader to simulate the sampling process in real-time.
You can take a look at the page source code, it shouldn&amp;rsquo;t be too complicated.&lt;/p&gt;
&lt;p&gt;All 60 input frames are packed into &lt;a href=&#34;https://bxt.rs/blog/motion-blur-for-half-life-video-recording-with-vulkan/atlas.jpg&#34;&gt;one big 3840×3600 atlas&lt;/a&gt; which the shader reads from.
Apparently, Chrome on Android (but not Firefox on Android) limits texture sizes to 4096×4096 for all devices due to an issue on some specific GPUs, so the atlas had to fit into that limit.&lt;/p&gt;
&lt;p&gt;The whole interactive widget thing was inspired by the &lt;em&gt;fantastic, spectacular&lt;/em&gt; posts by Bartosz Ciechanowski.
Make sure to check them out at &lt;a href=&#34;https://ciechanow.ski/&#34;&gt;https://ciechanow.ski/&lt;/a&gt; if you somehow haven&amp;rsquo;t stumbled upon them yet.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Who unfortunately seem to have just recently lost access to their domain, &lt;a href=&#34;https://xtreme-jumps.eu&#34;&gt;https://xtreme-jumps.eu&lt;/a&gt;.
They&amp;rsquo;re in process of rebuilding the site from scratch.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;This is possible thanks to interpolation done by the Half-Life engine during demo playback.
When watching a demo, the engine looks at recorded demo frames around the current playback timestamp, and interpolates the player&amp;rsquo;s position and angles, as well as other entities&amp;rsquo; positions and angles.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Frames coming from the game are in 8-bit RGB format, which means the lowest color component value is &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;255&lt;/sub&gt;.
The 16-bit RGB format expands this to represent values as low as &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;65535&lt;/sub&gt;.
When averaging together 257 color component values through accumulation, we divide every incoming value by 257.
In the worst case we end up with the resulting value of &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;255&lt;/sub&gt; × &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;257&lt;/sub&gt; = &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;65535&lt;/sub&gt;, which is still representable in our intermediate RGB-16 format.
Many frames will have pixel values bigger than the one-above-black &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;255&lt;/sub&gt;, which can be divided by even higher numbers while remaining representable.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Even if it matters only for CPU code, it is still useful, as bxt-rs implements the same operations with the same multiplication on the CPU for the fallback path.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;I heavily recommend &lt;a href=&#34;https://themaister.net/blog/2019/08/14/yet-another-blog-explaining-vulkan-synchronization/&#34;&gt;this blog post&lt;/a&gt; explaining how to use Vulkan synchronization and memory barriers.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;I use &lt;a href=&#34;https://crates.io/crates/tracing&#34;&gt;tracing&lt;/a&gt; and &lt;a href=&#34;https://crates.io/crates/tracing-chrome&#34;&gt;tracing-chrome&lt;/a&gt; to generate Chrome-tracing-compatible performance traces, then view them in &lt;a href=&#34;https://ui.perfetto.dev/&#34;&gt;Perfetto&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Fast Half-Life Video Recording with Vulkan</title>
      <link>https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/</link>
      <pubDate>Tue, 27 Jul 2021 16:51:00 +0300</pubDate>
      
      <guid>https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/</guid><description>&lt;p&gt;&lt;a href=&#34;https://store.steampowered.com/app/70/HalfLife/&#34;&gt;Half-Life&lt;/a&gt; is a famous first-person shooter released in 1998. These days Half-Life has a &lt;a href=&#34;https://www.speedrun.com/hl1&#34;&gt;vibrant speedrunning community&lt;/a&gt; where players try their best to complete the game as fast as humanly possible. Single-sitting speedruns, when people play through the game from start to finish, are usually streamed and recorded live. But &lt;a href=&#34;https://www.youtube.com/sourceruns&#34;&gt;segmented&lt;/a&gt; or &lt;a href=&#34;https://docs.google.com/spreadsheets/d/1J53EGbAl3dASEsda0gEg-oVqtPm9sGHmy59sORU3GJM/edit?usp=sharing&#34;&gt;tool-assisted&lt;/a&gt; speedruns—big projects that take weeks or months to complete—use demo files, which capture player actions and can be played back in-game. The demos are recorded to videos post-factum, typically at high resolution and quality. This video recording of demos can be done faster than real-time, which can save multiple real-life hours.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;ll show how I implemented a tool capable of recording 1920×1080@60 Half-Life footage at up to 3 times faster than real-time on a reasonably powerful PC.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; The tool uses the &lt;a href=&#34;https://en.wikipedia.org/wiki/Vulkan_%28API%29&#34;&gt;Vulkan&lt;/a&gt; graphics API to capture the game&amp;rsquo;s frames and convert their color space before encoding.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll also show an example of how to share an image between OpenGL and Vulkan, as the information on this admittedly uncommon use-case is still rather scarce.&lt;/p&gt;
&lt;figure&gt;
    &lt;video controls src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/capturing.mp4&#34;&gt;&lt;/video&gt;
    &lt;figcaption&gt;
        &lt;p&gt;Recording a 1920×1080@60 video of a Half-Life speedrun demo in 3× real-time&lt;/p&gt;

    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;specialized-recording-tools&#34;&gt;Specialized Recording Tools &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#specialized-recording-tools&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;One question you might immediately ask is: why is a special tool needed for recording video game footage, what&amp;rsquo;s the difference from screen recording tools like &lt;a href=&#34;https://obsproject.com/&#34;&gt;Open Broadcaster Software&lt;/a&gt;? The answer is that while those tools are great for live video recording, when dealing with in-game demos, we can do much better. In-game demos contain gameplay recordings and can be deterministically played back at any speed, which means that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can record them into videos much faster than real-time because we control the demo playback speed.&lt;/li&gt;
&lt;li&gt;We can set the target video frame-rate and record at that frame-rate exactly, guaranteeing there are no frame drops, even if the computer can&amp;rsquo;t keep up in real-time.&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;re not wasting any performance while recording: every single frame the game draws goes into the video.&lt;/li&gt;
&lt;li&gt;We can add special effects, for example motion blur by recording at a much higher frame-rate and blending the frames together.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;prior-art&#34;&gt;Prior Art &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#prior-art&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The most well-known Half-Life video recording tool is &lt;a href=&#34;https://www.advancedfx.org/&#34;&gt;Half-Life Advanced Effects&lt;/a&gt;, or HLAE for short. It has lots of movie-making features, such as custom camera paths or depth map dumping, but its video recording is fairly basic. HLAE gets the frame buffer contents with &lt;code&gt;glReadPixels&lt;/code&gt; and passes them to &lt;a href=&#34;https://ffmpeg.org/&#34;&gt;FFmpeg&lt;/a&gt; for encoding.&lt;/p&gt;
&lt;p&gt;HLAE implemented the FFmpeg encoding only in summer of 2020. Prior to that it would dump every single frame as a TGA file, which was a big recording performance bottleneck and lead to massive disk space consumption (uncompressed frames weigh a lot!). With FFmpeg the performance is much better, but still far from optimal.&lt;/p&gt;
&lt;p&gt;Another video recording tool is my previous project, &lt;a href=&#34;https://github.com/YaLTeR/hl-capture&#34;&gt;hl-capture&lt;/a&gt;. It used &lt;a href=&#34;https://en.wikipedia.org/wiki/OpenCL&#34;&gt;OpenCL&lt;/a&gt; to capture frames and convert them to a YUV color space, then passed them to FFmpeg for encoding. The performance was very good, but due to lack of OpenCL-OpenGL interoperability implementation in &lt;a href=&#34;https://mesa3d.org/&#34;&gt;Mesa&lt;/a&gt;, this fast path only worked on NVIDIA GPUs.&lt;/p&gt;
&lt;h2 id=&#34;implementation&#34;&gt;Implementation &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#implementation&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I implemented the video recording on top of &lt;a href=&#34;https://github.com/YaLTeR/bxt-rs&#34;&gt;bxt-rs&lt;/a&gt;, a base library which hooks into the Half-Life process and provides utilities for intercepting functions and interfacing with the game. I won&amp;rsquo;t go into too much detail here; the main point is that bxt-rs allows me to add in-game console commands and run my own code when the game calls some function.&lt;/p&gt;
&lt;h3 id=&#34;overview&#34;&gt;Overview &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#overview&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Video recording comprises several steps. After Half-Life draws a frame with OpenGL, we need to take the frame&amp;rsquo;s pixel data, feed it to a compute shader which will convert the colors from RGB to YUV, then send the YUV frame to an FFmpeg process for encoding.&lt;/p&gt;
&lt;p&gt;To make recording as fast as possible, we want to overlap the maximum amount of work with the game rendering the next frame. To do that, the only operation we will do on Half-Life&amp;rsquo;s main thread is copying the frame contents into our own GPU buffer. The game will then continue working on the next frame, while we process the recorded contents on a second thread. Luckily, Vulkan was designed with multithreading in mind and provides the necessary guarantees and synchronization primitives.&lt;/p&gt;
&lt;p&gt;All operations on the second thread use Vulkan. We will create a Vulkan image for storing the pixel data and share it with OpenGL on the main thread. Once the main thread copies the frame contents into that image, the second thread will run the color conversion compute shader, transfer the result from the GPU memory into RAM and send it off to FFmpeg.&lt;/p&gt;
&lt;h3 id=&#34;choosing-the-vulkan-crate&#34;&gt;Choosing the Vulkan Crate &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#choosing-the-vulkan-crate&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;In my past Rust projects I used both raw Vulkan bindings and &lt;a href=&#34;https://lib.rs/crates/vulkano&#34;&gt;vulkano&lt;/a&gt;. The raw bindings were, expectedly, way too verbose and boilerplate-heavy. Vulkano on the other hand was very nice to work with, however for this project I wanted a lower level of control to better understand the inner workings of the system I was building. Besides, the external memory extension that I was planning to use for interoperating with OpenGL is rather new, and Vulkano hasn&amp;rsquo;t yet added support for it. Thus, for interfacing with Vulkan, I went with the &lt;a href=&#34;https://lib.rs/crates/ash&#34;&gt;ash&lt;/a&gt; crate.&lt;/p&gt;
&lt;p&gt;Ash turned out to be the perfect fit for the project. It is essentially the raw Vulkan API, made as convenient as possible to use from Rust. Ash had only partial support for the external memory extension, but due to the low-level nature of the crate, I could use the underlying Vulkan functions directly for the parts that ash didn&amp;rsquo;t have wrappers for.&lt;/p&gt;
&lt;h3 id=&#34;choosing-the-gpu&#34;&gt;Choosing the GPU &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#choosing-the-gpu&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;As a small aside, I don&amp;rsquo;t recommend tinkering with Vulkan on AMD (at least on Linux) because the drivers, following Vulkan&amp;rsquo;s raw nature, do only a bare minimum of checks. Practically, this means your session will crash very frequently, leaving you with a pretty picture like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/vulkan-programming.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/vulkan-programming.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;After a few days I ended up temporarily switching to my previous GPU, an NVIDIA GTX 970, and finishing the Vulkan part there. NVIDIA&amp;rsquo;s proprietary driver proved to be very stable and hasn&amp;rsquo;t crashed once during my development.&lt;/p&gt;
&lt;h3 id=&#34;sharing-memory-with-opengl&#34;&gt;Sharing Memory with OpenGL &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#sharing-memory-with-opengl&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Memory sharing between graphics APIs works by allocating a piece of GPU memory in one API and sending a &amp;ldquo;pointer&amp;rdquo; to it to the other API. Specifically, we will create an image in Vulkan and export the underlying memory to OpenGL, where we will bind it to an OpenGL texture. We will also need a shared semaphore to synchronize access to the image between the APIs.&lt;/p&gt;
&lt;p&gt;The Vulkan side uses the &lt;a href=&#34;https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_KHR_external_memory&#34;&gt;&lt;code&gt;VK_KHR_external_memory&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_KHR_external_semaphore&#34;&gt;&lt;code&gt;VK_KHR_external_semaphore&lt;/code&gt;&lt;/a&gt; extensions to export a memory handle and a semaphore respectively, then the OpenGL side imports them using the &lt;a href=&#34;https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_external_objects.txt&#34;&gt;&lt;code&gt;EXT_external_objects&lt;/code&gt;&lt;/a&gt; extension. On Linux exporting is done via file descriptors, and on Windows via handles.&lt;/p&gt;
&lt;p&gt;This is how we create an image for sharing with OpenGL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(unix)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_image_create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryImageCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(windows)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_image_create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryImageCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_SRC&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SAMPLED&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;STORAGE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR_ATTACHMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;INPUT_ATTACHMENT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_image_create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The usage flags include all possible usage types as per a note in &lt;code&gt;EXT_external_objects&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The agreed resolution is to use the final option: Require all supported usage flags be specified by the application on the Vulkan side if the image is intended to alias with an OpenGL texture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then we allocate memory for the image:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(unix)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_memory_allocate_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExportMemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(windows)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_memory_allocate_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExportMemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_dedicated_allocate_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryDedicatedAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_memory_allocate_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_dedicated_allocate_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocate_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Bind our image to the allocated memory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bind_image_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Allocating memory for external use requires checking the dedicated memory allocation flag. It can either suggest, or require a dedicated allocation, but it cannot require a non-dedicated allocation. Thus for simplicity I always do a dedicated allocation.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s export a handle to this memory. I mentioned that ash has partial support for external memory: specifically, it supports Linux file descriptor exporting.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_fd&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ash&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;khr&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryFd&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryGetFdInfoKHR&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_handle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_memory_fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Windows, we have to use the raw API directly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_win32_fn&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;KhrExternalMemoryWin32Fn&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;transmute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_device_proc_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryGetWin32HandleInfoKHR&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalMemoryHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_handle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ptr&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;null_mut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_memory_win32_fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_memory_win32_handle_khr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can import the handle on the OpenGL side:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CreateMemoryObjectsEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We&amp;#39;re using a dedicated allocation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryObjectParameterivEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DEDICATED_MEMORY_OBJECT_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(unix)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ImportMemoryFdEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HANDLE_TYPE_OPAQUE_FD_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(windows)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ImportMemoryWin32HandleEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HANDLE_TYPE_OPAQUE_WIN32_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Create a texture and bind it to the imported memory.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GenTextures&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BindTexture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TEXTURE_2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TexStorageMem2DEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TEXTURE_2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;RGBA8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have a Vulkan image and an OpenGL texture backed by the same GPU memory. This means that we can write pixels into the OpenGL texture, then read them back from the Vulkan image just fine, as long as we do synchronization correctly.&lt;/p&gt;
&lt;p&gt;This is where a semaphore comes into play. The semaphore can be signaled from one API upon completion of a GPU operation (like writing pixels), and waited-for in the other API before starting another GPU operation (like reading pixels back). This way we can guarantee that the reading operation sees the completed result of the writing operation with no data races.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll do a similar exporting-importing dance for the semaphore, created on the Vulkan side:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(unix)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_semaphore_create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExportSemaphoreCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalSemaphoreHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(windows)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_semaphore_create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExportSemaphoreCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalSemaphoreHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SemaphoreCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;export_semaphore_create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case ash doesn&amp;rsquo;t include a wrapper for either Linux or Windows, so we use the raw API for both:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Linux
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_semaphore_fd_fn&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;KhrExternalSemaphoreFdFn&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;transmute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_device_proc_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SemaphoreGetFdInfoKHR&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalSemaphoreHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_semaphore_fd_fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_semaphore_fd_khr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Windows
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_semaphore_win32_fn&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;KhrExternalSemaphoreWin32Fn&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;transmute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_device_proc_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SemaphoreGetWin32HandleInfoKHR&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ExternalSemaphoreHandleTypeFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ptr&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;null_mut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;external_semaphore_win32_fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_semaphore_win32_handle_khr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Importing from the OpenGL side is simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GenSemaphoresEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(unix)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ImportSemaphoreFdEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HANDLE_TYPE_OPAQUE_FD_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#[cfg(windows)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ImportSemaphoreWin32HandleEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HANDLE_TYPE_OPAQUE_WIN32_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;capturing-a-frame&#34;&gt;Capturing a Frame &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#capturing-a-frame&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Here&amp;rsquo;s a simplified diagram of the Half-Life&amp;rsquo;s game loop operation:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background-color: rgb(255, 255, 255);&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;151px&#34; height=&#34;241px&#34; viewBox=&#34;-0.5 -0.5 151 241&#34;&gt;&lt;defs/&gt;&lt;g&gt;&lt;path d=&#34;M 90 140 Q 90 140 90 173.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 90 178.88 L 86.5 171.88 L 90 173.63 L 93.5 171.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;100&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Draw frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;90&#34; y=&#34;125&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 90 220 Q 90 240 45 240 Q 0 240 0 120 Q 0 0 45 0 Q 90 0 90 13.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 90 18.88 L 86.5 11.88 L 90 13.63 L 93.5 11.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;180&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Swap buffers&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;90&#34; y=&#34;205&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 90 60 Q 90 60 90 93.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 90 98.88 L 86.5 91.88 L 90 93.63 L 93.5 91.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;20&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 40px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Run game tick&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;90&#34; y=&#34;45&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;/&gt;&lt;a transform=&#34;translate(0,-5)&#34; xlink:href=&#34;https://www.diagrams.net/doc/faq/svg-export-text-problems&#34; target=&#34;_blank&#34;&gt;&lt;text text-anchor=&#34;middle&#34; font-size=&#34;10px&#34; x=&#34;50%&#34; y=&#34;100%&#34;&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;

&lt;p&gt;We&amp;rsquo;ll capture the pixel contents of a frame by running some code just before the game swaps buffers to show it on the screen:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background-color: rgb(255, 255, 255);&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;161px&#34; height=&#34;321px&#34; viewBox=&#34;-0.5 -0.5 161 321&#34;&gt;&lt;defs/&gt;&lt;g&gt;&lt;path d=&#34;M 100 140 Q 100 140 100 173.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 100 178.88 L 96.5 171.88 L 100 173.63 L 103.5 171.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;100&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Draw frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;100&#34; y=&#34;125&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 100 300 Q 100.03 320 50.03 320 Q 0.03 320 0.03 160 Q 0.03 0 50.03 0 Q 100.03 0 100.01 13.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 100 18.88 L 96.51 11.88 L 100.01 13.63 L 103.51 11.89 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;260&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 280px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Swap buffers&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;100&#34; y=&#34;285&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 100 60 Q 100 60 100 93.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 100 98.88 L 96.5 91.88 L 100 93.63 L 103.5 91.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;20&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 40px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Run game tick&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;100&#34; y=&#34;45&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 100 220 Q 100 220 100 253.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 100 258.88 L 96.5 251.88 L 100 253.63 L 103.5 251.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;180&#34; width=&#34;120&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Capture frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;100&#34; y=&#34;205&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Capture frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;/&gt;&lt;a transform=&#34;translate(0,-5)&#34; xlink:href=&#34;https://www.diagrams.net/doc/faq/svg-export-text-problems&#34; target=&#34;_blank&#34;&gt;&lt;text text-anchor=&#34;middle&#34; font-size=&#34;10px&#34; x=&#34;50%&#34; y=&#34;100%&#34;&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;

&lt;p&gt;We need to synchronize access to the shared memory between OpenGL and Vulkan. The memory will be written by OpenGL, then read by Vulkan, then written by OpenGL again next frame, then read by Vulkan again, and so on in a loop. On each of these steps the corresponding API will &amp;ldquo;acquire&amp;rdquo; the memory by waiting for the semaphore, do the operation, then &amp;ldquo;release&amp;rdquo; the memory by signaling the semaphore again.&lt;/p&gt;
&lt;p&gt;On the OpenGL side I blit (copy) the current framebuffer (which contains the frame Half-Life is about to show on screen) to the OpenGL texture bound to the shared memory via an auxiliary framebuffer. I am also careful to restore the previously-bound framebuffer so the game continues working properly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Acquire shared memory ownership from Vulkan.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WaitSemaphoreEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We keep the image in the general layout between using it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;LAYOUT_GENERAL_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Save previously-bound framebuffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;previous_framebuffer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetIntegerv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DRAW_FRAMEBUFFER_BINDING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;previous_framebuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Bind a destination framebuffer targeting our texture.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BindFramebuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DRAW_FRAMEBUFFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;framebuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FramebufferTexture2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DRAW_FRAMEBUFFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR_ATTACHMENT0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TEXTURE_2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Copy pixel contents from the game&amp;#39;s framebuffer to ours.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BlitFramebuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR_BUFFER_BIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;NEAREST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Restore the framebuffer that the game had bound as the destination.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BindFramebuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DRAW_FRAMEBUFFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;previous_framebuffer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Transfer shared memory ownership to Vulkan.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SignalSemaphoreEXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Transfer it back to the general layout.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;LAYOUT_GENERAL_EXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Submit the commands to the GPU.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the Vulkan side, acquisition and release with another graphics API (OpenGL) require barriers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;CommandBufferBeginInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;CommandBufferUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;ONE_TIME_SUBMIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_command_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_sampling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Acquire the image from OpenGL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We keep the image in the general layout between using it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_SRC_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// QUEUE_FAMILY_EXTERNAL indicates a different graphics API.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_EXTERNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_sampling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TOP_OF_PIPE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// (additional commands to blit the image to another intermediate buffer)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Transfer image_frame back to OpenGL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We can erase the image_frame contents now, we already read them.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;UNDEFINED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Transfer the layout back to general.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;GENERAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_EXTERNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_sampling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;BOTTOM_OF_PIPE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_frame_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_command_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_sampling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphores&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_sampling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SubmitInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Wait for our semaphore before starting.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wait_semaphores&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphores&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wait_dst_stage_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;ALL_COMMANDS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Signal the semaphore after completion.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signal_semaphores&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;semaphores&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue_submit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;Fence&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how the process looks now:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background-color: rgb(255, 255, 255);&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;462px&#34; height=&#34;481px&#34; viewBox=&#34;-0.5 -0.5 462 481&#34;&gt;&lt;defs/&gt;&lt;g&gt;&lt;path d=&#34;M 120 140 Q 120 140 120 173.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 178.88 L 116.5 171.88 L 120 173.63 L 123.5 171.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;100&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 120px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Draw frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;125&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 120 460 Q 120 480 60 480 Q 0 480 0 240 Q 0 0 60 0 Q 120 0 120 13.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 18.88 L 116.5 11.88 L 120 13.63 L 123.5 11.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;420&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 440px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Swap buffers&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;445&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 120 60 Q 120 60 120 93.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 98.88 L 116.5 91.88 L 120 93.63 L 123.5 91.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;20&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 40px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Run game tick&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;45&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 120 380 Q 120 380 120 413.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 418.88 L 116.5 411.88 L 120 413.63 L 123.5 411.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;path d=&#34;M 200 360 Q 240 360 240 280 Q 240 200 273.63 200&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; stroke-dasharray=&#34;3 3&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 278.88 200 L 271.88 203.5 L 273.63 200 L 271.88 196.5 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;340&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 360px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Signal semaphore&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;365&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Signal semaphore&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 360 220 Q 360 220 360 253.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 360 258.88 L 356.5 251.88 L 360 253.63 L 363.5 251.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;280&#34; y=&#34;180&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 200px; margin-left: 281px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Acquire semaphore&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;360&#34; y=&#34;205&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Acquire semaphore&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 120 220 Q 120 220 120 253.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 258.88 L 116.5 251.88 L 120 253.63 L 123.5 251.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;180&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 200px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Acquire semaphore&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;205&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Acquire semaphore&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 120 300 Q 120 300 120 333.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 120 338.88 L 116.5 331.88 L 120 333.63 L 123.5 331.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;40&#34; y=&#34;260&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 280px; margin-left: 41px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Blit to image&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;120&#34; y=&#34;285&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Blit to image&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 360 300 Q 360 300 360 333.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 360 338.88 L 356.5 331.88 L 360 333.63 L 363.5 331.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;280&#34; y=&#34;260&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 280px; margin-left: 281px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Copy from image&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;360&#34; y=&#34;285&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Copy from image&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x=&#34;280&#34; y=&#34;340&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 360px; margin-left: 281px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Signal semaphore&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;360&#34; y=&#34;365&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Signal semaphore&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 260 130 L 260 130 L 460 130 L 460 130&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;path d=&#34;M 260 130 L 260 400 L 460 400 L 460 130&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 260 130 L 460 130&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 150px; margin-left: 360px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; &#34;&gt;Second Thread&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;360&#34; y=&#34;155&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Second Thread&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;/&gt;&lt;a transform=&#34;translate(0,-5)&#34; xlink:href=&#34;https://www.diagrams.net/doc/faq/svg-export-text-problems&#34; target=&#34;_blank&#34;&gt;&lt;text text-anchor=&#34;middle&#34; font-size=&#34;10px&#34; x=&#34;50%&#34; y=&#34;100%&#34;&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;

&lt;p&gt;As you can see, I&amp;rsquo;m actually using another intermediate image rather than running the compute shader on &lt;code&gt;image_frame&lt;/code&gt; directly. This is to handle the case when the game&amp;rsquo;s rendering framerate doesn&amp;rsquo;t match the video output framerate. There are two common scenarios which cause this to happen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We&amp;rsquo;re doing motion blur via frame blending. The game runs at a higher FPS, e.g. output video FPS times 64, and each 64 captured frames are blended together to produce one output video frame. In this case every frame we&amp;rsquo;d accumulate pixel values of &lt;code&gt;image_frame&lt;/code&gt; into the intermediate buffer, and only run color conversion once per the output video frame.&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;re recording a video of a &lt;a href=&#34;http://tasvideos.org/WelcomeToTASVideos.html&#34;&gt;tool-assisted speedrun&lt;/a&gt; (TAS). This is a script describing keyboard and mouse inputs to the game which can be played back deterministically, similarly to a demo file. There&amp;rsquo;s one important difference: a TAS script must set its own in-game FPS, so video recording (which wants constant output video FPS) needs to deal with it by duplicating or dropping output video frames, very much like regular screen recording software deals with varying FPS of a game it&amp;rsquo;s recording. In this case we don&amp;rsquo;t actually know for how long &lt;code&gt;image_frame&lt;/code&gt; should be shown in the video until Half-Life renders the next frame, which means that we can only start the next processing stage right when we already need to capture the next frame. To add a bit of pipelining in this case, we save &lt;code&gt;image_frame&lt;/code&gt; into the intermediate buffer right away, freeing the shared memory for the next capture, then process the intermediate buffer later when we know the duration.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;color-conversion&#34;&gt;Color Conversion &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#color-conversion&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;I chose to output MP4 videos encoded in H.264 with YUV 4:2:0 pixel format and limited-range &lt;a href=&#34;https://en.wikipedia.org/wiki/Rec._709&#34;&gt;BT.709&lt;/a&gt; color space. H.264 in an MP4 container with YUV 4:2:0 pixel format is playable on the most setups out of the currently available reasonable formats, while limited-range BT.709 should generally be selected as the color space by video players (for video resolutions that people will likely record), resulting in correct colors even if the video player ignores explicit color space tags.&lt;/p&gt;
&lt;p&gt;Color space conversion is best done on the GPU as it&amp;rsquo;s a massively parallel operation (each pixel is essentially processed separately from the others), which GPUs are really good at. Thus, I implemented it with a compute shader:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-glsl&#34; data-lang=&#34;glsl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#version 450&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#extension GL_EXT_shader_8bit_storage: require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// I selected the value that gave the best performance on this workflow.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define WORKGROUP_SIZE 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_size_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WORKGROUP_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;local_size_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WORKGROUP_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;local_size_z&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Our intermediate buffer with the RGB image.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;binding&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;uniform&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sampler2D&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// The output buffer in I420 format, ready to go into FFmpeg.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;layout&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;binding&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OutputBuffer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;vec2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;textureSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gl_GlobalInvocationID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gl_GlobalInvocationID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;color&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// The OpenGL coordinate system is upside-down compared to the usual video coordinate systems.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Let&amp;#39;s invert it here in the shader.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y_inv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Compute luminocity in accordance with the BT.709 specification.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;float&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rgb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.2126&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.7152&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.0722&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;235&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;output_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y_inv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint8_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;round&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 4:2:0 subsampling means we compute one output color pixel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// per each 2×2 square of input color pixels.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Subsample the color values assuming center chroma location.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;vec4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;d&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;texture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;color&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Convert color values in accordance with the BT.709 specification.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;float&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;U&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;128&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rgb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.2126&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.7152&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;mf&#34;&gt;0.9278&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.8556&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;240&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;float&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;V&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;128&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rgb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;vec3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.7874&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.7152&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.0722&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5748&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;240&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Write the values into the output buffer in the I420 format (planar YUV 4:2:0).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;output_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y_inv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;uint8_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;round&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;U&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;output_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y_inv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;uint8_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;round&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;V&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m using the &lt;a href=&#34;https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_KHR_8bit_storage&#34;&gt;&lt;code&gt;VK_KHR_8bit_storage&lt;/code&gt;&lt;/a&gt; extension to write directly into a byte buffer from a shader. Without the extension I would have to make a regular image and then carefully write to the right pixel color values in the shader in such a way that, when interpreted as bytes, I&amp;rsquo;d get the correct I420 frame, but this would be very awkward. &lt;code&gt;VK_KHR_8bit_storage&lt;/code&gt; is reasonably well supported so there are little compatibility concerns.&lt;/p&gt;
&lt;p&gt;I get color values from the input frame, convert them to YUV with numeric constants from &lt;a href=&#34;https://web.archive.org/web/20170908185504if_/http://www.itu.int:80/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf&#34;&gt;the specification&lt;/a&gt; and write the results out into the byte buffer in &lt;a href=&#34;https://www.fourcc.org/pixel-format/yuv-i420/&#34;&gt;I420&lt;/a&gt; order.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how the input image and the output buffer are created.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Intermediate image, input to the color conversion shader.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageCreateInfo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_type&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageType&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TYPE_2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Format suitable for frame blending, if I implement it in the future.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;Format&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;R16G16B16A16_UNORM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extent&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;Extent3D&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;depth&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mip_levels&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array_layers&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;samples&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SampleCountFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TYPE_1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tiling&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageTiling&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usage&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;STORAGE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For updating in-place during frame blending.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For copying from image_frame.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SAMPLED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For reading from the color conversion shader.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sharing_mode&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SharingMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXCLUSIVE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;Default&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Allocate memory for the image.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_requirements&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_image_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_type_index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_memorytype_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryPropertyFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DEVICE_LOCAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocation_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocate_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Bind them together.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bind_image_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To read from an image in a shader, we also need a sampler (which controls coordinate normalization and reading past the edge behavior) and an image view:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Sampler.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SamplerCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Reads past the edge return the edge pixel value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_mode_u&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SamplerAddressMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_mode_v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SamplerAddressMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_mode_w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SamplerAddressMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We&amp;#39;ll use coordinates from 0 to width/height, rather than from 0 to 1.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unnormalized_coordinates&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sampler_sample&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_sampler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Image view.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageViewCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;view_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageViewType&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TYPE_2D&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;Format&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;R16G16B16A16_UNORM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_view_sample&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_image_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now for the output buffer. Actually, we&amp;rsquo;ll need two buffers: one device-local buffer which the shader will write to directly, and one &amp;ldquo;staging&amp;rdquo; CPU-accessible buffer that we&amp;rsquo;ll copy the results to for reading into RAM.&lt;/p&gt;
&lt;p&gt;This might seem strange: why use two buffers instead of one? As it turns out, CPU-accessible buffers can be &lt;em&gt;really slow&lt;/em&gt; to use for shader output, making the two-buffer scheme orders of magnitude faster.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Buffer for color conversion shader output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 4:2:0 subsampling: full-resolution Y + quarter-resolution U, V.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For using as the shader output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;STORAGE_BUFFER&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For using as a source of a copy operation into the CPU-accessible buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_SRC&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sharing_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SharingMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXCLUSIVE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory_requirements&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_buffer_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory_type_index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_memorytype_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This buffer resides on the GPU.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryPropertyFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;DEVICE_LOCAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocation_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocate_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bind_buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// CPU-accessible staging buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Same size as the buffer above.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// For using it as a destination of a copy operation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sharing_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SharingMode&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;EXCLUSIVE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_requirements&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_buffer_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_type_index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_memorytype_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This buffer is CPU-accessible.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryPropertyFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HOST_VISIBLE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryPropertyFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HOST_CACHED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryAllocateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocation_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_requirements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_type_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allocate_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bind_buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use all these objects in the shader we also need a descriptor set allocated from a descriptor pool with a descriptor set layout and filled with our sampler and buffer, as well as the shader itself, and a pipeline encompassing all of those objects, however all of that is fairly standard with nothing interesting to point out.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at how the pipeline is launched.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;CommandBufferBeginInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;CommandBufferUsageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;ONE_TIME_SUBMIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_command_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Set a barrier for the color conversion stage.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We were copying from image_frame to this intermediate image.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We will be reading from this image in a shader.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_READ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// The layouts reflect this too.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_READ_ONLY_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// To run the color conversion shader, we need to bind its pipeline and descriptor sets.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_bind_pipeline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineBindPoint&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pipeline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_bind_descriptor_sets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineBindPoint&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pipeline_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;descriptor_set_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Run the shader.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_dispatch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Our workgroup size is 4, this subdivision reflects that.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Barrier for the device-local buffer to copy it to the CPU-accessible buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We were writing to the device-local buffer in a shader.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;SHADER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We will be reading from it with a copy operation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_READ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;WHOLE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// The copy command itself.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_copy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferCopy&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_copy_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_color_conversion_output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Barrier for the CPU-accessible buffer to read it from the host.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;BufferMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We were copying into the buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We will be reading it from the host.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HOST_READ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;WHOLE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;HOST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// While we&amp;#39;re at it, also prepare the intermediate image for another iteration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// by transferring it back to the original TRANSFER_DST layout.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_barrier&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageMemoryBarrier&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_access_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;AccessFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// We don&amp;#39;t care about the contents any more.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;UNDEFINED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageLayout&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER_DST_OPTIMAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst_queue_family_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;QUEUE_FAMILY_IGNORED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subresource_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageSubresourceRange&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aspect_mask&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;ImageAspectFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COLOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_mip_level&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_array_layer&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;layer_count&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cmd_pipeline_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;COMPUTE_SHADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;PipelineStageFlags&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;TRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;DependencyFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_sample_memory_barrier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_command_buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the command buffer set up, we&amp;rsquo;re almost ready to send it to the GPU. However, this time we want to read the pixel values back on the CPU to send them to the video encoder, which means that we need to wait for the GPU to complete these operations. This is where a Vulkan fence comes into play: the GPU can signal a fence upon finishing a command buffer, and the CPU can wait for the fence. After that we&amp;rsquo;re free to map the CPU-accessible buffer and read from it as normal.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// To wait for GPU operation completion on the host, we need a fence.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;FenceCreateInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffer_color_conversion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;SubmitInfo&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;command_buffers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue_submit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;queue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;submit_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// The fence will be signaled upon completion of the command buffer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Wait for the fence to be signalled.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wait_for_fences&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u64&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;max_value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Map the CPU-accessible buffer to read from it normally.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pixels&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;WHOLE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MemoryMapFlags&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Invalidate it to make sure we&amp;#39;re reading up-to-date data.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mapped_memory_range&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;MappedMemoryRange&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vk&lt;/span&gt;::&lt;span class=&#34;no&#34;&gt;WHOLE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;invalidate_mapped_memory_ranges&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mapped_memory_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Now we can treat it as a regular array of pixels.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pixels&lt;/span&gt;: &lt;span class=&#34;kp&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slice&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;from_raw_parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pixels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;usize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;usize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Send it to the encoder, possibly multiple times (for the TAS playback case).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frames&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;muxer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write_video_frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pixels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Unmap the memory and free the fence.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unmap_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroy_fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All in all, this is the simplified diagram of the complete video recording process:&lt;/p&gt;
&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;!DOCTYPE svg PUBLIC &#34;-//W3C//DTD SVG 1.1//EN&#34; &#34;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&#34;&gt;
&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; style=&#34;background-color: rgb(255, 255, 255);&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; version=&#34;1.1&#34; width=&#34;451px&#34; height=&#34;351px&#34; viewBox=&#34;-0.5 -0.5 451 351&#34;&gt;&lt;defs/&gt;&lt;g&gt;&lt;path d=&#34;M 110 170 Q 110 170 110 203.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 110 208.88 L 106.5 201.88 L 110 203.63 L 113.5 201.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;130&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 150px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Draw frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;110&#34; y=&#34;155&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Draw frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 110 330 Q 110 350 55 350 Q 0 350 0 190 Q 0 30 55 30 Q 110 30 110 43.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 110 48.88 L 106.5 41.88 L 110 43.63 L 113.5 41.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;290&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 310px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;&lt;div&gt;Swap buffers&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;110&#34; y=&#34;315&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Swap buffers&amp;#xa;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 110 90 Q 110 90 110 123.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 110 128.88 L 106.5 121.88 L 110 123.63 L 113.5 121.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;50&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 70px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Run game tick&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;110&#34; y=&#34;75&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Run game tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 350 90 Q 350 90 350 123.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;stroke&#34;/&gt;&lt;path d=&#34;M 350 128.88 L 346.5 121.88 L 350 123.63 L 353.5 121.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;rect x=&#34;270&#34; y=&#34;50&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;all&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 70px; margin-left: 271px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; &#34;&gt;Copy to intermediate&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;350&#34; y=&#34;75&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Copy to intermediate&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 250 0 L 250 0 L 450 0 L 450 0&#34; fill=&#34;#ffffff&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;all&#34;/&gt;&lt;path d=&#34;M 250 0 L 250 350 L 450 350 L 450 0&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 250 0 L 450 0&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 20px; margin-left: 350px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; &#34;&gt;Second Thread&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;350&#34; y=&#34;25&#34; fill=&#34;#000000&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Second Thread&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 110 250 Q 110 250 110 283.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 110 288.88 L 106.5 281.88 L 110 283.63 L 113.5 281.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 190 230 Q 230 230 230 150 Q 230 70 263.63 70&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; stroke-dasharray=&#34;3 3&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 268.88 70 L 261.88 73.5 L 263.63 70 L 261.88 66.5 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;rect x=&#34;30&#34; y=&#34;210&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 230px; margin-left: 31px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; &#34;&gt;Capture frame&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;110&#34; y=&#34;235&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Capture frame&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 350 170 Q 350 170 350 203.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 350 208.88 L 346.5 201.88 L 350 203.63 L 353.5 201.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;rect x=&#34;270&#34; y=&#34;130&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 150px; margin-left: 271px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; &#34;&gt;Convert colors&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;350&#34; y=&#34;155&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Convert colors&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x=&#34;270&#34; y=&#34;290&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 310px; margin-left: 271px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; &#34;&gt;Send to FFmpeg&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;350&#34; y=&#34;315&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Send to FFmpeg&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d=&#34;M 350 250 Q 350 250 350 283.63&#34; fill=&#34;none&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;path d=&#34;M 350 288.88 L 346.5 281.88 L 350 283.63 L 353.5 281.88 Z&#34; fill=&#34;#000000&#34; stroke=&#34;#000000&#34; stroke-miterlimit=&#34;10&#34; pointer-events=&#34;none&#34;/&gt;&lt;rect x=&#34;270&#34; y=&#34;210&#34; width=&#34;160&#34; height=&#34;40&#34; rx=&#34;6&#34; ry=&#34;6&#34; fill=&#34;#f5f5f5&#34; stroke=&#34;#666666&#34; pointer-events=&#34;none&#34;/&gt;&lt;g transform=&#34;translate(-0.5 -0.5)&#34;&gt;&lt;switch&gt;&lt;foreignObject style=&#34;overflow: visible; text-align: left;&#34; pointer-events=&#34;none&#34; width=&#34;100%&#34; height=&#34;100%&#34; requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;&gt;&lt;div xmlns=&#34;http://www.w3.org/1999/xhtml&#34; style=&#34;display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 230px; margin-left: 271px;&#34;&gt;&lt;div style=&#34;box-sizing: border-box; font-size: 0; text-align: center; &#34;&gt;&lt;div style=&#34;display: inline-block; font-size: 16px; font-family: serif; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; &#34;&gt;Transfer to CPU&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x=&#34;350&#34; y=&#34;235&#34; fill=&#34;#333333&#34; font-family=&#34;serif&#34; font-size=&#34;16px&#34; text-anchor=&#34;middle&#34;&gt;Transfer to CPU&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures=&#34;http://www.w3.org/TR/SVG11/feature#Extensibility&#34;/&gt;&lt;a transform=&#34;translate(0,-5)&#34; xlink:href=&#34;https://www.diagrams.net/doc/faq/svg-export-text-problems&#34; target=&#34;_blank&#34;&gt;&lt;text text-anchor=&#34;middle&#34; font-size=&#34;10px&#34; x=&#34;50%&#34; y=&#34;100%&#34;&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;

&lt;h3 id=&#34;staging-buffer-memory-type&#34;&gt;Staging Buffer Memory Type &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#staging-buffer-memory-type&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;For the staging buffer I went with the &lt;code&gt;HOST_VISIBLE | HOST_CACHED&lt;/code&gt; memory type. &lt;code&gt;HOST_VISIBLE&lt;/code&gt; is required to access it from the CPU, while &lt;code&gt;HOST_CACHED&lt;/code&gt; brought a big performance boost. &lt;code&gt;HOST_COHERENT&lt;/code&gt;, the third available flag, did not seem to bring any benefit.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a performance visualization of several ways of reading memory from the GPU. The measurements were done recording at the 2560×1440 resolution and 60 FPS.&lt;/p&gt;
&lt;p&gt;First, no staging buffer. The shader writes directly to a CPU-accessible buffer:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-no-staging-buffer.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-no-staging-buffer.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;The green rectangle is waiting for the Vulkan fence, while the rest (not filled on this particular trace) is reading from the buffer and writing it to the pipe. The whole process takes 107 ms which is&amp;hellip; quite underwhelming. This adds up to about 0.16× real-time speed of capturing.&lt;/p&gt;
&lt;p&gt;Next, I&amp;rsquo;ll add a staging buffer, but without the &lt;code&gt;HOST_CACHED&lt;/code&gt; flag. I didn&amp;rsquo;t have the next performance traces left from the time when I did the initial measurements, so I captured new ones on the latest version, where color conversion and muxing live on the second thread, but otherwise nothing changed in this function.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-staging-host-visible.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-staging-host-visible.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;20 ms, much better! The process got more than five times faster. Note how the time waiting for the fence (so GPU work duration) went down too: the GPU can write to a device-local buffer much faster.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;rsquo;s add &lt;code&gt;HOST_CACHED&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-staging-host-cached.png&#34;&gt;
    &lt;img src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/profile-staging-host-cached.png&#34; alt=&#34;&#34;  /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Just 3.4 ms, almost six times faster than before, wow! This time the improvement comes mainly from reading the buffer on the CPU side with no change to the GPU work duration. And we&amp;rsquo;re definitely exceeding the real-time encoding threshold here, by a factor of more than four.&lt;/p&gt;
&lt;p&gt;The key takeaways are to use an extra staging buffer instead of writing from a shader directly to a CPU-accessible buffer and use &lt;code&gt;HOST_CACHED&lt;/code&gt; for much faster memory reading.&lt;/p&gt;
&lt;h3 id=&#34;video-encoding&#34;&gt;Video Encoding &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#video-encoding&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;For video encoding I use FFmpeg by running the &lt;code&gt;ffmpeg&lt;/code&gt; binary and sending it content through a pipe. A more natural solution might seem to use the FFmpeg API as a library (in fact, I did just that in hl-capture), however this option has some drawbacks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When using FFmpeg as a library, video encoding happens in-process. Since Half-Life is a 32-bit application, this means the RAM is heavily limited. In practice, 4K recording in hl-capture already starts hitting out of memory situations, and higher resolutions are straight up impossible. One of the goals for the new video recording was to lift this restriction.&lt;/li&gt;
&lt;li&gt;The FFmpeg API has an over a decade long history, which &lt;em&gt;really shows&lt;/em&gt;. It&amp;rsquo;s full of different ways of doing the same thing, each filled with gotchas and compatibility traps. The best way of working with FFmpeg seems to be to delegate all this trouble to the official binaries, which have at least some hope of working properly in most situations.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://lib.rs/crates/ffmpeg&#34;&gt;Rust FFmpeg wrapper&lt;/a&gt; have not seen updates since 2015, although it seems that recently &lt;a href=&#34;https://lib.rs/search?q=ffmpeg&#34;&gt;a few new crates have appeared&lt;/a&gt; to fill that gap; I haven&amp;rsquo;t looked at them thoroughly though.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus, I spawn &lt;code&gt;ffmpeg&lt;/code&gt; with the correct arguments (notably, specifying the color space parameters) and pipe video and audio data to it, manually muxed into the &lt;a href=&#34;https://www.ffmpeg.org/~michael/nut.txt&#34;&gt;NUT container format&lt;/a&gt;. The &lt;code&gt;ffmpeg&lt;/code&gt; command line I&amp;rsquo;m using looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ffmpeg -f nut             &lt;span class=&#34;c1&#34;&gt;# Input format.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -i pipe:           &lt;span class=&#34;c1&#34;&gt;# Data comes on the standard input.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -c:v libx264       &lt;span class=&#34;c1&#34;&gt;# Use libx264 for H.264 encoding.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -crf &lt;span class=&#34;m&#34;&gt;15&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;# For all intents and purposes, CRF 15 is visually lossless.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -preset ultrafast  &lt;span class=&#34;c1&#34;&gt;# Speed is a priority to avoid bottlenecks on encoding.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;# We&amp;#39;re using BT.709…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -color_primaries bt709
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -color_trc bt709
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -colorspace bt709
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;# …with limited color range…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -color_range tv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;# …and center chroma location.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -chroma_sample_location center
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;# Move the MP4 index to the start of the file for fast playback start when streaming.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -movflags +faststart
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;# Overwrite the file if it exists.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       output_filename.mp4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion &lt;a href=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/#conclusion&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The new Half-Life video recording works well on Linux and Windows and across a wide range of GPUs. Thanks to running FFmpeg out of process, it&amp;rsquo;s easy to record at very high resolutions such as &lt;a href=&#34;https://youtu.be/iGVXP-gZ4xc&#34;&gt;8K&lt;/a&gt; and possibly even 16K, all while running extremely fast thanks to GPU color conversion and a pipelined architecture.&lt;/p&gt;
&lt;p&gt;To sum up, here are the main factors contributing to the performance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Running most of the processing on a second thread so it runs parallel to the game working on the next frame.&lt;/li&gt;
&lt;li&gt;Converting the color space from RGB to YUV on the GPU which is extremely well suited for this sort of task.&lt;/li&gt;
&lt;li&gt;Using a &lt;code&gt;HOST_CACHED&lt;/code&gt; staging buffer for best performance of getting data from the GPU to the CPU.&lt;/li&gt;
&lt;li&gt;Encoding with &lt;code&gt;libx264&lt;/code&gt; using the &lt;code&gt;ultrafast&lt;/code&gt; preset to avoid encoding bottlenecks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A very interesting potential improvement is to do encoding on the GPU. &lt;code&gt;libx264&lt;/code&gt;, even if very fast, is still a software encoder; besides, transferring compressed bitstream from the GPU should be faster than transferring full uncompressed YUV 4:2:0 frames. I&amp;rsquo;m looking forward to the &lt;a href=&#34;https://www.khronos.org/blog/an-introduction-to-vulkan-video&#34;&gt;Vulkan video extensions proposal&lt;/a&gt; which exposes GPU decoding and encoding through the Vulkan API, which I&amp;rsquo;m conveniently already using.&lt;/p&gt;
&lt;p&gt;Even if the current encoding speed is &amp;ldquo;fast enough&amp;rdquo;, GPU encoding might allow using newer video compression formats by bringing the encoding performance on par with &lt;code&gt;libx264&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, if you&amp;rsquo;re doing any sort of Vulkan development, I heavily recommend using the &lt;a href=&#34;https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers&#34;&gt;validation layers&lt;/a&gt; as they automatically catch many mistakes and subtle errors in Vulkan usage.&lt;/p&gt;
&lt;figure&gt;
    &lt;video controls src=&#34;https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/vulkan-programming.webm&#34;&gt;&lt;/video&gt;
    &lt;figcaption&gt;
        &lt;p&gt;Average day writing Vulkan on AMD&lt;/p&gt;

    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I did most of the development and optimization on my machine with an Intel i7-3770k CPU (overclocked to 4.2 GHz) and an AMD RX 580 GPU.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
  </channel>
</rss>
