<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>入門 on ながむしメモ</title><link>https://nagakagachi.github.io/lab/webgpu/introduction/</link><description>Recent content in 入門 on ながむしメモ</description><generator>Hugo</generator><language>ja-JP</language><atom:link href="https://nagakagachi.github.io/lab/webgpu/introduction/index.xml" rel="self" type="application/rss+xml"/><item><title>Test00</title><link>https://nagakagachi.github.io/lab/webgpu/introduction/test00/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://nagakagachi.github.io/lab/webgpu/introduction/test00/</guid><description>&lt;p&gt;学習用にAgentCodingで生成したデモです&lt;/p&gt;&#10;&lt;p&gt;WebGPUの初期化と、最小限の描画パイプラインを確認する。下のボタンでGPUを取得し、WGSLの頂点シェーダーとフラグメントシェーダーで三角形を描画します。&lt;/p&gt;&#10;&lt;p&gt;描画は一度だけ実行します。未対応や初期化失敗の場合は、状態欄に理由を表示します。&lt;/p&gt;&#10;&lt;!-- demo --&gt;&#10;&lt;h2 id="コードの解説"&gt;コードの解説&lt;/h2&gt;&#10;&lt;p&gt;以下は実装の抜粋です。DirectX 12との対応は役割の比較であり、APIの一対一対応ではありません。全文は末尾の「ソース」から確認できます。&lt;/p&gt;&#10;&lt;h3 id="htmlの描画先とモジュール"&gt;HTMLの描画先とモジュール&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#7ee787"&gt;canvas&lt;/span&gt; id&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;gpu-canvas&amp;#34;&lt;/span&gt; width&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;960&amp;#34;&lt;/span&gt; height&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;540&amp;#34;&lt;/span&gt; &lt;span style="color:#f85149"&gt;...&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#7ee787"&gt;canvas&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#7ee787"&gt;script&lt;/span&gt; type&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;module&amp;#34;&lt;/span&gt; src&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;.../main.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#7ee787"&gt;script&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;canvas&lt;/code&gt;はHTML内の描画領域です。widthとheightは内部の描画解像度で、CSSの表示サイズとは別です。ウィンドウと表示サーフェスを用意する役割に近いものです。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt;でJavaScriptをモジュールとして読み込みます。このコードはブラウザのCPU側で動き、WGSLだけがGPUで実行されます。&lt;code&gt;...&lt;/code&gt;は抜粋のための省略です。&lt;/p&gt;&#10;&lt;h3 id="html要素の取得とクリック処理"&gt;HTML要素の取得とクリック処理&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; button &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; document.querySelector(&lt;span style="color:#a5d6ff"&gt;&amp;#39;#gpu-start&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; canvas &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; document.querySelector(&lt;span style="color:#a5d6ff"&gt;&amp;#39;#gpu-canvas&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;button.addEventListener(&lt;span style="color:#a5d6ff"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style="color:#ff7b72"&gt;async&lt;/span&gt; () =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;document&lt;/code&gt;はブラウザが用意するHTML文書のオブジェクトです。&lt;code&gt;querySelector&lt;/code&gt;はCSSセレクターで要素を探し、&lt;code&gt;#&lt;/code&gt;はidを指定します。取得したbuttonへクリックのコールバックを登録します。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;async&lt;/code&gt;関数内の&lt;code&gt;await&lt;/code&gt;は非同期処理の結果を待ちます。UIスレッドを同期的にブロックする待ちではなく、処理を中断して結果が届いたら続きを実行します。&lt;/p&gt;&#10;&lt;h3 id="アダプターとデバイス"&gt;アダプターとデバイス&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;if&lt;/span&gt; (&lt;span style="color:#ff7b72;font-weight:bold"&gt;!&lt;/span&gt;navigator.gpu) &lt;span style="color:#ff7b72"&gt;throw&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;new&lt;/span&gt; Error(&lt;span style="color:#a5d6ff"&gt;&amp;#39;このブラウザ環境ではWebGPUを利用できません&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; adapter &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;await&lt;/span&gt; navigator.gpu.requestAdapter();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; currentDevice &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;await&lt;/span&gt; adapter.requestDevice();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;navigator.gpu&lt;/code&gt;はブラウザ組み込みのWebGPU APIの入口です。役割として、アダプター取得とD3D12デバイス作成に近い順序です。実装ではadapterがnullの場合も確認しています。deviceからリソースやパイプラインを作ります。&lt;/p&gt;&#10;&lt;h3 id="canvasを表示先として設定"&gt;Canvasを表示先として設定&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;context &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; canvas.getContext(&lt;span style="color:#a5d6ff"&gt;&amp;#39;webgpu&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; format &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; navigator.gpu.getPreferredCanvasFormat();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;context.configure({ device, format, alphaMode&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#39;opaque&amp;#39;&lt;/span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CanvasのWebGPUコンテキストを取得し、デバイスと表示用フォーマットを関連付けます。swap chainの設定に近い役割ですが、DXGIのswap chainを直接操作するものではありません。&lt;code&gt;opaque&lt;/code&gt;はCanvasの表示を不透明として扱う指定です。&lt;/p&gt;&#10;&lt;h3 id="wgslファイルの取得"&gt;WGSLファイルの取得&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; shaderResponse &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;await&lt;/span&gt; fetch(&lt;span style="color:#ff7b72"&gt;new&lt;/span&gt; URL(&lt;span style="color:#a5d6ff"&gt;&amp;#39;./triangle.wgsl&amp;#39;&lt;/span&gt;, &lt;span style="color:#ff7b72"&gt;import&lt;/span&gt;.meta.url));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; shader &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; device.createShaderModule({ code&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;await&lt;/span&gt; shaderResponse.text() });&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt;はURLからファイルを取得するブラウザAPIです。&lt;code&gt;import.meta.url&lt;/code&gt;は実行中のmain.jsのURLなので、そこを基準に同じフォルダのWGSLを解決します。OSのファイルパスを開いているわけではありません。&lt;/p&gt;</description></item><item><title>Test01</title><link>https://nagakagachi.github.io/lab/webgpu/introduction/test01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://nagakagachi.github.io/lab/webgpu/introduction/test01/</guid><description>&lt;p&gt;学習用にAgentCodingで生成したデモです&lt;/p&gt;&#10;&lt;p&gt;Uniform BufferでCPU側から角度を渡し、頂点シェーダーで三角形を回転させる。初期化から描画まで、このTest内で独立して実装します。&lt;/p&gt;&#10;&lt;h2 id="操作"&gt;操作&lt;/h2&gt;&#10;&lt;p&gt;「開始」でGPUを初期化して回転を開始します。「停止」で回転を止めます。停止中でも角度スライダーで描画を更新できます。「再開」でその角度から回転を再開します。回転速度は毎秒45度です。別タブへ移ると自動で停止します。&lt;/p&gt;&#10;&lt;!-- demo --&gt;&#10;&lt;h2 id="コードの解説"&gt;コードの解説&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="../test00/"&gt;Test00&lt;/a&gt;で説明したデバイス・Canvas・Shader Module・基本のDraw処理は省略し、追加した部分を抜粋します。実装自体はTest00のコードを参照せず、このTestだけで完結しています。&lt;/p&gt;&#10;&lt;h3 id="htmlの角度入力"&gt;HTMLの角度入力&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#7ee787"&gt;input&lt;/span&gt; id&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;gpu-angle&amp;#34;&lt;/span&gt; type&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;range&amp;#34;&lt;/span&gt; min&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; max&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;360&amp;#34;&lt;/span&gt; step&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;1&amp;#34;&lt;/span&gt; value&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; disabled&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ブラウザ標準のスライダーです。0～360度を1度刻みで入力します。初期化成功後にdisabledを解除します。HTMLの入力値は文字列なので、JavaScriptで数値へ変換します。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;slider.addEventListener(&lt;span style="color:#a5d6ff"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;, () =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; angle &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; Number(slider.value);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;input&lt;/code&gt;は値を変更している途中にも届くイベントです。停止中もこのイベントからdrawを1回呼び、CPU→GPUの値の更新を確認できます。&lt;/p&gt;&#10;&lt;h3 id="cpu側のデータとgpubuffer"&gt;CPU側のデータとGPUBuffer&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;const&lt;/span&gt; uniformData &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#ff7b72"&gt;new&lt;/span&gt; Float32Array(&lt;span style="color:#a5d6ff"&gt;4&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;uniformBuffer &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; device.createBuffer({ size&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;16&lt;/span&gt;, usage&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; GPUBufferUsage.UNIFORM &lt;span style="color:#ff7b72;font-weight:bold"&gt;|&lt;/span&gt; GPUBufferUsage.COPY_DST });&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Float32Arrayは32ビットfloatを連続配置するJavaScriptのTyped Arrayです。GPU用のメモリそのものではなく、CPU側の転送元です。4要素・16バイトを確保します。GPUBufferにはuniform用途と書き込み先用途を指定します。&lt;/p&gt;&#10;&lt;h3 id="wgslの定数バッファ"&gt;WGSLの定数バッファ&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-wgsl" data-lang="wgsl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;struct&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;Uniforms&lt;span style="color:#6e7681"&gt; &lt;/span&gt;{&lt;span style="color:#6e7681"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;rotation:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;vec4f,&lt;span style="color:#6e7681"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&lt;span style="color:#6e7681"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d2a8ff;font-weight:bold"&gt;@group&lt;/span&gt;(&lt;span style="color:#a5d6ff"&gt;0&lt;/span&gt;)&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#d2a8ff;font-weight:bold"&gt;@binding&lt;/span&gt;(&lt;span style="color:#a5d6ff"&gt;0&lt;/span&gt;)&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#ff7b72"&gt;var&lt;/span&gt;&lt;span style="color:#ff7b72;font-weight:bold"&gt;&amp;lt;&lt;/span&gt;uniform&lt;span style="color:#ff7b72;font-weight:bold"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;uniforms:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;Uniforms;&lt;span style="color:#6e7681"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;HLSLのcbufferに近い宣言です。4成分の内容は角度・アスペクト比・未使用・未使用です。group/bindingはWebGPUのバインド番号で、HLSLのregisterやspaceの番号へ直接対応するわけではありません。&lt;/p&gt;&#10;&lt;h3 id="リソースのレイアウト"&gt;リソースのレイアウト&lt;/h3&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;binding&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;0&lt;/span&gt;, visibility&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; GPUShaderStage.VERTEX,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;buffer&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; { type&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#39;uniform&amp;#39;&lt;/span&gt;, minBindingSize&lt;span style="color:#ff7b72;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;16&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;createBindGroupLayout&lt;/code&gt;のentryです。binding 0がuniform bufferで、頂点ステージから読み、少なくとも16バイトを必要とする契約を定義します。Root Signatureでリソースの種類・位置・Shader Visibilityを記述する役割に近いものです。&lt;/p&gt;</description></item></channel></rss>