<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Etnaviv on Christian Gmeiner</title>
    <link>https://christian-gmeiner.info/tags/etnaviv/</link>
    <description>Recent content in Etnaviv on Christian Gmeiner</description>
    <image>
      <title>Christian Gmeiner</title>
      <url>https://christian-gmeiner.info/papermod-cover.png</url>
      <link>https://christian-gmeiner.info/papermod-cover.png</link>
    </image>
    <generator>Hugo -- 0.159.0</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://christian-gmeiner.info/tags/etnaviv/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The Diagonal Seam</title>
      <link>https://christian-gmeiner.info/2026-06-19-the-diagonal-seam/</link>
      <pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2026-06-19-the-diagonal-seam/</guid>
      <description>&lt;p&gt;Two more dEQP tests down:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag -- Pass
dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_min -- Pass
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one was a fun geometry puzzle.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Mesa&amp;rsquo;s &lt;code&gt;u_blitter&lt;/code&gt; is the utility that drivers use for framebuffer blits &amp;ndash; copying pixel data between surfaces, optionally scaling and filtering. It works by drawing a textured quad: set up the source as a texture, the destination as a render target, and draw a rectangle with the appropriate texture coordinates. Simple.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Two more dEQP tests down:</p>
<pre tabindex="0"><code>dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag -- Pass
dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_min -- Pass
</code></pre><p>This one was a fun geometry puzzle.</p>
<h2 id="the-problem">The problem</h2>
<p>Mesa&rsquo;s <code>u_blitter</code> is the utility that drivers use for framebuffer blits &ndash; copying pixel data between surfaces, optionally scaling and filtering. It works by drawing a textured quad: set up the source as a texture, the destination as a render target, and draw a rectangle with the appropriate texture coordinates. Simple.</p>
<p>Except the quad is made of two triangles. And that diagonal seam between them is where the trouble starts.</p>
<pre tabindex="0"><code> v2 -------- v3
  |  \   T2  |
  | T1  \    |
  |       \  |
 v0 -------- v1
</code></pre><p>For LINEAR filtering, this is fine &ndash; the interpolation across the seam is smooth enough that nobody notices. But for NEAREST filtering, a texel is selected based on which texel center is closest to the interpolated texture coordinate. At the diagonal seam, the two triangles can produce <em>slightly different</em> texture coordinates for pixels that sit right on the boundary. Different coordinates mean different nearest-texel selection, and that means an inconsistent stripe of wrong texels running diagonally across the blit.</p>
<p>The dEQP <code>nearest_consistency</code> tests specifically check for this: they blit with NEAREST filtering and verify that every pixel picks the same texel regardless of which triangle it fell into.</p>
<p><img alt="tags" loading="lazy" src="/img/diagonal-seam.png"></p>
<h2 id="what-others-do">What others do</h2>
<p>This isn&rsquo;t a new problem. V3D already has a workaround in <code>u_blitter</code>: it sets <code>use_index_buffer</code> to reorder the triangle indices so that the shared edge of the two triangles is along a different diagonal. This changes which pixels land on the seam and can be enough to pass the tests on some hardware.</p>
<p>On GC7000, that wasn&rsquo;t sufficient. The floating-point interpolation differences are large enough that the seam remains visible regardless of which diagonal you pick.</p>
<h2 id="what-the-blob-does">What the blob does</h2>
<p>Looking at command stream traces from the proprietary Vivante driver, the answer was clear: they don&rsquo;t draw a quad at all. They draw a <strong>single oversized triangle</strong> and let the scissor clip it to the destination rectangle.</p>
<p>No seam, no problem.</p>
<h2 id="the-single-triangle-transform">The single triangle transform</h2>
<p>The idea is simple: take a rectangle and find a single triangle that fully covers it. The smallest such triangle is a right triangle with legs twice the width and twice the height of the rectangle:</p>
<pre tabindex="0"><code> v2
  |\
  |  \
  | rect\
  |------+\
  |      |  \
 v0 -----|--- v1
</code></pre><p>Vertex 0 stays at the rectangle&rsquo;s top-left corner. Vertex 1 extends to twice the rectangle width. Vertex 2 extends to twice the rectangle height. The original rectangle is fully contained within this triangle.</p>
<p>The math for transforming the blitter&rsquo;s 4-vertex quad into a 3-vertex triangle is:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="n">a</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>      <span class="cm">/* pos and texcoord */</span>
</span></span><span class="line"><span class="cl">   <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">c</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">c</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>   <span class="cm">/* xyzw components */</span>
</span></span><span class="line"><span class="cl">      <span class="kt">float</span> <span class="n">v0</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">vertices</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">c</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">      <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">vertices</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="mf">2.0f</span> <span class="o">*</span> <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">vertices</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">c</span><span class="p">]</span> <span class="o">-</span> <span class="n">v0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">vertices</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="mf">2.0f</span> <span class="o">*</span> <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">vertices</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="n">a</span><span class="p">][</span><span class="n">c</span><span class="p">]</span> <span class="o">-</span> <span class="n">v0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This transforms both position and texture coordinates consistently, so the texture mapping across the visible (scissored) region is identical to what the full quad would have produced &ndash; minus the seam.</p>
<h2 id="scissor-is-essential">Scissor is essential</h2>
<p>The oversized triangle extends beyond the destination rectangle, so we need scissor to clip it. The blitter doesn&rsquo;t always have a scissor set up, so when <code>use_single_triangle</code> is enabled, we synthesize one from the destination box:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">.</span><span class="n">use_single_triangle</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">scissor</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">synth_scissor</span><span class="p">.</span><span class="n">minx</span> <span class="o">=</span> <span class="nf">MAX2</span><span class="p">(</span><span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">x</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="n">synth_scissor</span><span class="p">.</span><span class="n">miny</span> <span class="o">=</span> <span class="nf">MAX2</span><span class="p">(</span><span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">y</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="n">synth_scissor</span><span class="p">.</span><span class="n">maxx</span> <span class="o">=</span> <span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">x</span> <span class="o">+</span> <span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="n">synth_scissor</span><span class="p">.</span><span class="n">maxy</span> <span class="o">=</span> <span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">y</span> <span class="o">+</span> <span class="n">dstbox</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="n">scissor</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">synth_scissor</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="keeping-it-scoped">Keeping it scoped</h2>
<p>The single-triangle transform should only apply to blit operations, not to clears or other blitter draws. A transient <code>single_triangle_active</code> flag is set around the actual blit draw calls and checked in the vertex emission code. Drivers opt in by setting <code>use_single_triangle</code> on the blitter context at creation time.</p>
<p>For etnaviv, that&rsquo;s a single line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">blitter</span><span class="o">-&gt;</span><span class="n">use_single_triangle</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="the-design">The design</h2>
<p>The implementation is split into two commits: the <code>u_blitter.c</code> infrastructure (vertex transform, synthesized scissor, gating flag, 3-vertex draw path) that any driver can opt into, and the one-line etnaviv enablement. Keeping them separate means another driver hitting the same seam can flip the flag without touching u_blitter code.</p>
<p>The work landed upstream in <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39973">u_blitter: Add single-triangle draw mode for NEAREST blit consistency</a>.</p>
<h2 id="the-takeaway">The takeaway</h2>
<p>Sometimes the fix for a rendering artifact isn&rsquo;t better math or tighter tolerances &ndash; it&rsquo;s removing the geometric feature that causes the problem in the first place. Two triangles have a seam. One triangle doesn&rsquo;t.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fixing the R/B swap the right way</title>
      <link>https://christian-gmeiner.info/2026-06-10-fixing-the-rb-swap-the-right-way/</link>
      <pubDate>Wed, 10 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2026-06-10-fixing-the-rb-swap-the-right-way/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;ve ever looked at a GPU render and seen blue where red should be, you&amp;rsquo;ve met the R/B swap problem. For etnaviv this has been a long-standing source of complexity. We were solving it in the shader, but the proprietary blob driver had a simpler approach all along. As part of my work at &lt;a href=&#34;https://www.igalia.com/&#34;&gt;Igalia&lt;/a&gt;, I finally sat down and did it properly.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Vivante GPUs have a quirk: the Pixel Engine (PE) always writes pixels in BGRA byte order. When your API says &amp;ldquo;render to R8G8B8A8_UNORM&amp;rdquo;, what actually lands in memory is B, G, R, A. Every byte of every pixel, every frame. The hardware just works that way.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>If you&rsquo;ve ever looked at a GPU render and seen blue where red should be, you&rsquo;ve met the R/B swap problem. For etnaviv this has been a long-standing source of complexity. We were solving it in the shader, but the proprietary blob driver had a simpler approach all along. As part of my work at <a href="https://www.igalia.com/">Igalia</a>, I finally sat down and did it properly.</p>
<h2 id="the-problem">The problem</h2>
<p>Vivante GPUs have a quirk: the Pixel Engine (PE) always writes pixels in BGRA byte order. When your API says &ldquo;render to R8G8B8A8_UNORM&rdquo;, what actually lands in memory is B, G, R, A. Every byte of every pixel, every frame. The hardware just works that way.</p>
<p>The question is: where do you fix it?</p>
<p>The etnaviv driver was doing it in the shader. Before the fragment shader writes its output, a <a href="https://docs.mesa3d.org/nir/index.html">NIR</a> lowering pass swaps the R and B channels:</p>
<pre tabindex="0"><code>   alu-&gt;src[0].swizzle[0] = 2;   /* .r reads from .b */
   alu-&gt;src[0].swizzle[2] = 0;   /* .b reads from .r */
</code></pre><p>This works, until it doesn&rsquo;t. The shader key needs a <code>frag_rb_swap</code> bitmask per render target. The blend color needs per-RT R/B swapping to match. And it falls apart entirely for scalar outputs - if a shader writes a single float, there&rsquo;s no <code>.z</code> component to swizzle into <code>.x</code>. That&rsquo;s exactly the NIR validation failure we hit:</p>
<pre tabindex="0"><code>Test case &#39;dEQP-GLES3.functional.fragment_out.basic.fixed.rgb8_lowp_float&#39;..
NIR validation failed after etna_lower_io in ../mesa/src/gallium/drivers/etnaviv/etnaviv_compiler_nir.c:1296
1 errors:
shader: MESA_SHADER_FRAGMENT
source_blake3: {0x4d463d73, 0x4b27d742, 0x27a92b64, 0x375c010f, 0xb2ce3767, 0x2adc55cc, 0x6da8105b, 0x5b9fce29}
name: GLSL1
prev_stage: MESA_SHADER_VERTEX
inputs_read: 32
outputs_written: 4
perspective_varyings: 32
max_subgroup_size: 128
min_subgroup_size: 1
api_subgroup_size_draw_uniform: true
first_ubo_is_default_ubo: true
known_interpolation_qualifiers: true
flrp_lowered: true
inputs: 1
outputs: 1
decl_var shader_in INTERP_MODE_SMOOTH none highp float packed:var0 (VARYING_SLOT_VAR0.x, 0, 0)
decl_var shader_out INTERP_MODE_NONE none mediump float out0 (FRAG_RESULT_DATA0.x, 0, 0)
decl_function main () (entrypoint)

impl main {
    block b0:  // preds:
    32    %3 = load_const (0x00000000)
    32    %4 = @load_input (%3 (0x0)) (base=0, range=1, component=0, dest_type=float32, io location=VARYING_SLOT_VAR0 slots=1)  // packed:var0
    32    %2 = deref_var &amp;out0 (shader_out mediump float)
    32    %5 = mov %4.z
error: src-&gt;swizzle[i] &lt; num_components (../mesa/src/compiler/nir/nir_validate.c:217)

               @store_deref (%2, %5) (wrmask=x, access=none)
               // succs: b1
    block b1:
}

FATAL ERROR: Test program crashed
</code></pre><h2 id="what-the-blob-does">What the blob does</h2>
<p>Looking at command stream traces from the proprietary driver, the answer is almost disappointingly simple. Instead of this:</p>
<pre tabindex="0"><code>  Texture format: A8B8G8R8     (read BGRA as BGRA)
  PE format:      A8B8G8R8     (write BGRA)
  Shader:         swap R &lt;-&gt; B
</code></pre><p>The blob does this:</p>
<pre tabindex="0"><code>  Texture format: A8R8G8B8     (read BGRA as RGBA - hardware swaps on read)
  PE format:      A8B8G8R8     (write BGRA - unchanged)
  Shader:         nothing
</code></pre><p>That&rsquo;s it. Tell the texture sampler the data is A8R8G8B8, and it will correctly interpret the BGRA bytes as RGBA channels. The PE keeps writing BGRA because that&rsquo;s what it does. No shader modification needed.</p>
<p>In our format table, the change is a single field:</p>
<pre tabindex="0"><code>  -  VT(R8G8B8A8_UNORM, UNSIGNED_BYTE, A8B8G8R8, A8B8G8R8)
  +  VT(R8G8B8A8_UNORM, UNSIGNED_BYTE, A8R8G8B8, A8B8G8R8)
                                        ^^^^^^^^
                                     texture format
</code></pre><h2 id="the-data-flow">The data flow</h2>
<p>To understand why this works, trace a red pixel through the pipeline:</p>
<pre tabindex="0"><code>                          BGRA-internal byte order
                         +------------------------+
                         |                        |
  API: glClear(1,0,0,1)  |   Memory: [0,0,255,255]|   CPU: expects [255,0,0,255]
  &#34;red = 1.0&#34;            |   (B=0, G=0, R=255,    |   &#34;RGBA order&#34;
                         |    A=255)              |
                         +------------------------+

  +-----------+     +--------+     +--------+     +---------+
  | Shader    |     | PE     |     | Memory |     | Sampler |
  | out=RGBA  | --&gt; | writes | --&gt; | stores | --&gt; | reads   |
  | (1,0,0,1) |     | BGRA   |     | BGRA   |     | as      |
  |           |     |        |     | bytes  |     | A8R8G8B8|
  +-----------+     +--------+     +--------+     +---------+
       |                |               |              |
    R=1.0            B=0x00          [00 00 FF FF]   R=1.0
    G=0.0            G=0x00                          G=0.0
    B=0.0            R=0xFF                          B=0.0
    A=1.0            A=0xFF                          A=1.0
</code></pre><p>The shader writes (1,0,0,1). The PE swaps R/B on write, so memory gets [0,0,255,255] in BGRA order. The sampler, told the format is A8R8G8B8, reads those same bytes back as (1,0,0,1). Round-trip complete, no shader involvement.</p>
<h2 id="the-cpu-boundary-problem">The CPU boundary problem</h2>
<p>GPU-to-GPU is clean. But what happens at the CPU boundary - <code>glReadPixels</code>, <code>glTexSubImage</code>, <code>glBlitFramebuffer</code> to a CPU-mapped buffer? The CPU expects RGBA byte order. Memory has BGRA. Something needs to swap.</p>
<p>This is where the hardware copy/resolve engines come in - <code>RS</code> and <code>BLT</code>. Both can perform R/B swapping during their copy operations. The RS engine has a <code>swap_rb</code> bit. The BLT engine has per-side swizzle fields. We just need to activate this at the right moment.</p>
<p>The key insight: only transfer blits (tiled-to-linear copies for CPU access) need the swap. GPU-internal blits - glBlitFramebuffer between two render targets, TS resolve, mipmap generation - are all operating on data already in BGRA order on both sides. Swapping there would be wrong.</p>
<p>So we gate it with a context flag:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">in_transfer_blit</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nf">etna_copy_resource_box</span><span class="p">(</span><span class="n">pctx</span><span class="p">,</span> <span class="n">trans</span><span class="o">-&gt;</span><span class="n">rsc</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">rsc</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">,</span> <span class="p">...);</span>
</span></span><span class="line"><span class="cl"><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">in_transfer_blit</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span></code></pre></div><p>And in the RS blit path:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="p">.</span><span class="n">swap_rb</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">-&gt;</span><span class="n">in_transfer_blit</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">           <span class="nf">translate_pe_format_rb_swap</span><span class="p">(</span><span class="n">blit_info</span><span class="o">-&gt;</span><span class="n">src</span><span class="p">.</span><span class="n">format</span><span class="p">),</span>
</span></span></code></pre></div><h2 id="the-texture-shadow-trap">The texture shadow trap</h2>
<p>With the basic approach working, tests passed on GC7000 (BLT engine). But GC2000 (RS engine) had a regression: <code>fbo-blit</code> showed blue where red should be.</p>
<p>After adding debug prints and tracing the code paths, the culprit was the texture shadow. Some resources can&rsquo;t be sampled directly by the texture unit - for example, a render target might use a layout the sampler doesn&rsquo;t understand. For these, the driver allocates a second copy of the resource in a sampler-compatible tiled layout. This is the &ldquo;texture shadow&rdquo;.</p>
<p>The shadow is a workaround that hurts performance - it means extra memory and extra copies. Ideally we wouldn&rsquo;t need it at all. But while it exists, the driver uses it as a shortcut for CPU transfers: read directly from the shadow and detile in software, skipping the blit engine:</p>
<pre tabindex="0"><code>Passing probes:  PATH=temp_resource+RS_blit    swap_rb=1   -&gt; correct
Failing probes:  PATH=texture_shadow                       -&gt; R/B swapped
</code></pre><p>The texture shadow path does a software detile - raw byte copy, no R/B swap. With BGRA-internal byte order, that gives you BGRA bytes on the CPU side. Wrong.</p>
<p>The fix: skip the texture shadow shortcut for formats that need R/B swap, forcing through the blit engine path which handles the conversion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">rsc</span><span class="o">-&gt;</span><span class="n">texture</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nf">etna_resource_newer</span><span class="p">(</span><span class="n">rsc</span><span class="p">,</span> <span class="nf">etna_resource</span><span class="p">(</span><span class="n">rsc</span><span class="o">-&gt;</span><span class="n">texture</span><span class="p">))</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">    <span class="o">!</span><span class="nf">translate_pe_format_rb_swap</span><span class="p">(</span><span class="n">prsc</span><span class="o">-&gt;</span><span class="n">format</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="cm">/* Use texture shadow - safe, no R/B swap needed */</span>
</span></span><span class="line"><span class="cl">   <span class="n">rsc</span> <span class="o">=</span> <span class="nf">etna_resource</span><span class="p">(</span><span class="n">rsc</span><span class="o">-&gt;</span><span class="n">texture</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="cm">/* Use blit engine - handles R/B swap correctly */</span>
</span></span><span class="line"><span class="cl">   <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="results">Results</h2>
<p>This is a net-negative patch series - 15 files changed, 76 insertions, 113 deletions. The <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38710">etnaviv: Remove RB swap logic in the fragment shader</a> contains all that&rsquo;s needed:</p>
<ol>
<li><strong>blt: Use img-&gt;swizzle for CONFIG SWIZ fields</strong> - preparation for per-image swizzle support</li>
<li><strong>Add translate_pe_internal_format helper</strong> - maps RGBA pipe formats to BGRA equivalents for clear color packing</li>
<li><strong>Use BGRA-internal texture format with BLT/RS R/B swizzle</strong> - the main change</li>
<li><strong>Compute blend color directly in etna_set_blend_color</strong> - simplifies blend color, no deferred update needed</li>
</ol>
<p>Fixes the NIR validation failure with scalar fragment outputs. And as a nice side effect, removing the shader-based swap means fewer shader variants, fewer instructions and less overhead. <a href="https://github.com/glmark2/glmark2">glmark2</a>-es2-wayland improves from ~835 to ~874 FPS - a 4.7% performance increase.</p>
<p>Sometimes matching what the hardware vendor does is the right answer. The blob driver figured this out years ago. We just needed to look at the traces.</p>
<h2 id="thats-where-i-thought-the-story-ended">That&rsquo;s where I thought the story ended</h2>
<p>The texture-format trick has a hidden assumption baked into it: that the GPU both writes <em>and</em> reads every resource. The PE writes BGRA, the sampler is told the format is A8R8G8B8, and the byte order cancels out. It&rsquo;s a closed loop, and as long as the data never leaves the GPU, nobody outside ever sees the BGRA bytes.</p>
<p><a href="https://docs.kernel.org/driver-api/dma-buf.html">dmabuf</a> breaks the loop.</p>
<p>When a buffer is shared with another process - a Wayland compositor, a video decoder, a camera - the byte order is no longer our private business. It&rsquo;s mandated by the <a href="https://docs.kernel.org/userspace-api/dma-buf-alloc-exchange.html">DRM FourCC</a>. An external producer writes honest RGBA bytes into the buffer. Then our sampler, still convinced the format is A8R8G8B8, reads them as BGRA. Red and blue swap. And on the way out, a transfer blit happily swaps data that was already correct. The optimization that made GPU-internal rendering clean made buffer sharing wrong.</p>
<pre tabindex="0"><code>  GPU-internal (closed loop):       dmabuf (loop broken):

  PE writes BGRA                    external producer writes RGBA
       |                                  |
  sampler reads as A8R8G8B8         sampler reads as A8R8G8B8
       |                                  |
  cancels out -&gt; correct            reads RGBA as BGRA -&gt; swapped
</code></pre><h2 id="step-back-out-for-shared-resources">Step back out for shared resources</h2>
<p>The first fix is the obvious one: when a resource is shared, don&rsquo;t play the trick. Use the native A8B8G8R8 texture format so the sampler reads RGBA bytes as RGBA, skip the R/B swizzle in the BLT and RS transfer blits, and re-enable the texture shadow shortcut that the swizzle had forced us to disable. Internal resources keep the BGRA-internal optimization untouched.</p>
<p>That handles imports. But there&rsquo;s a case it doesn&rsquo;t cover: a resource <em>we</em> rendered into and then export. The PE wrote BGRA, because that&rsquo;s all the PE knows how to do. The external consumer expects native order.</p>
<p>Here a second kind of shadow shows up. Just as the sampler gets a <em>texture shadow</em> when it can&rsquo;t read the base layout, the PE gets a <em>render shadow</em> - a render-compatible copy - when it can&rsquo;t draw into the base layout. (On some GPUs, like GC2000, no single tiling satisfies both the texture engine and the pixel engine, so a resource can end up carrying both shadows.) When an exported resource is flushed, that render shadow is resolved back to the base. So we hook <code>etna_flush_resource()</code> and do the R/B swap during that copy - using the BLT destination swizzle or the RS <code>SWAP_RB</code> bit. The swap rides along on a copy we were doing anyway.</p>
<h2 id="one-buffer-two-byte-orders">One buffer, two byte orders</h2>
<p>Now the same shared buffer can be in one of two states. Just imported, or just flushed for export? Native RGBA. Freshly rendered by the PE, not yet flushed? PE-internal BGRA. A static texture format chosen at sampler-view creation can&rsquo;t be right for both.</p>
<p>So the format choice becomes dynamic. A <code>shared_native_order</code> flag tracks which order the bytes are currently in, and the sampler-view format follows from it:</p>
<table>
  <thead>
      <tr>
          <th><code>shared_native_order</code></th>
          <th>How you get there</th>
          <th>Bytes in buffer</th>
          <th>Sampler format</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>true</code></td>
          <td>set on import, and again after <code>flush_resource()</code> swaps on export</td>
          <td>native RGBA</td>
          <td><code>A8B8G8R8</code> (native)</td>
      </tr>
      <tr>
          <td><code>false</code></td>
          <td>cleared when the PE renders straight into the buffer with no render shadow, and no shader swap fixed up the bytes (see below)</td>
          <td>PE-internal BGRA</td>
          <td><code>A8R8G8B8</code> (the trick)</td>
      </tr>
  </tbody>
</table>
<p>Both texture paths - state-based and descriptor-based - pre-compute the native format variant at sampler-view creation, so picking the right one at emit time costs a single branch, not a per-frame format recompute.</p>
<h2 id="the-shader-swap-comes-back">The shader swap comes back</h2>
<p>Which brings us to LINEAR_PE GPUs, and a twist I didn&rsquo;t see coming.</p>
<p>On these GPUs, a linear shared resource is render-compatible. There is no render shadow - the PE writes straight into the buffer that gets handed to the compositor. So after a draw, the buffer holds BGRA, and <code>flush_resource()</code> would have to issue a full-surface blit to swap it. That&rsquo;s real bandwidth, on every frame, that the old shadow-based path never paid.</p>
<p>There&rsquo;s a cheaper place to do the swap: in the shader, on the way out. Which is exactly the thing this whole series set out to delete.</p>
<p>So it comes back - but only for this one case, and done properly. A per-RT <code>frag_rb_swap</code> bitmask in the shader key drives a NIR lowering pass that swaps channels 0 and 2 on the fragment output. The original shader swap fell over on scalar outputs, because there was no <code>.z</code> to swizzle from. This one widens the output variable to vec4 first, padding the missing components with undef, then applies the swizzle with an adjusted writemask:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">   <span class="cm">/* Pad source to 4 components (undef for missing) */</span>
</span></span><span class="line"><span class="cl">   <span class="n">nir_def</span> <span class="o">*</span><span class="n">padded</span> <span class="o">=</span> <span class="nf">nir_pad_vec4</span><span class="p">(</span><span class="o">&amp;</span><span class="n">b</span><span class="p">,</span> <span class="n">src</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="cm">/* Swap R and B channels */</span>
</span></span><span class="line"><span class="cl">   <span class="kt">unsigned</span> <span class="n">swiz</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span>
</span></span></code></pre></div><p>That&rsquo;s the scalar <code>rgb8_lowp_float</code> crash from the top of this post - fixed, in the one path that now needs a shader swap at all.</p>
<p>Wiring it up is a check in <code>etna_draw_vbo()</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="nf">VIV_FEATURE</span><span class="p">(</span><span class="n">screen</span><span class="p">,</span> <span class="n">ETNA_FEATURE_LINEAR_PE</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">pfb</span><span class="o">-&gt;</span><span class="n">nr_cbufs</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">struct</span> <span class="n">etna_resource</span> <span class="o">*</span><span class="n">rsc</span> <span class="o">=</span> <span class="nf">etna_resource</span><span class="p">(</span><span class="n">pfb</span><span class="o">-&gt;</span><span class="n">cbufs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">texture</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">         <span class="k">if</span> <span class="p">(</span><span class="n">rsc</span><span class="o">-&gt;</span><span class="n">shared</span> <span class="o">&amp;&amp;</span> <span class="n">rsc</span><span class="o">-&gt;</span><span class="n">layout</span> <span class="o">==</span> <span class="n">ETNA_LAYOUT_LINEAR</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">             <span class="nf">translate_pe_format_rb_swap</span><span class="p">(</span><span class="n">pfb</span><span class="o">-&gt;</span><span class="n">cbufs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">format</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="n">key</span><span class="p">.</span><span class="n">frag_rb_swap</span> <span class="o">|=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span></code></pre></div><p>The bitmask is per-RT, so an MRT setup with a mix of shared and private targets does the right thing for each. And because the shader produced native bytes directly, <code>shared_native_order</code> stays true and <code>flush_resource()</code> skips its blit entirely.</p>
<p>The fixes for all of this live in a follow-up series, <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40029">etnaviv: Fix dmabuf R/B byte order for PE_FORMAT_RB_SWAP formats</a>.</p>
<h2 id="so-was-removing-the-shader-swap-a-mistake">So was removing the shader swap a mistake?</h2>
<p>No - but it wasn&rsquo;t the whole answer either.</p>
<p>The shader swap was wrong as the <em>universal</em> solution. It cost a shader-key dimension, per-RT blend-color fixups, and it crashed on scalar outputs. The texture-format trick is genuinely better for the common case, where a resource lives and dies on the GPU.</p>
<p>What the dmabuf work showed is that there is no single right place to fix R/B order. There&rsquo;s a place that&rsquo;s cheapest for each path: the texture format for GPU-internal resources, a transfer-blit swap at the CPU boundary, a flush-time swap for exported render targets, and - for LINEAR_PE, where the PE writes straight into a shared buffer - the shader, after all. The trick isn&rsquo;t picking one. It&rsquo;s knowing which boundary you&rsquo;re standing on, and swapping there.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Multiple Render Targets for etnaviv</title>
      <link>https://christian-gmeiner.info/2025-01-16-mrt/</link>
      <pubDate>Thu, 16 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2025-01-16-mrt/</guid>
      <description>&lt;p&gt;Modern graphics programming revolves around achieving high-performance rendering and visually stunning effects. Among OpenGL’s capabilities, Multiple Render Targets (MRTs) are particularly valuable for enabling advanced rendering techniques with greater efficiency.&lt;/p&gt;
&lt;p&gt;With the latest release of &lt;a href=&#34;https://docs.mesa3d.org/relnotes/24.3.0.html&#34;&gt;Mesa 24.03&lt;/a&gt; and the commitment from &lt;a href=&#34;https://www.igalia.com/&#34;&gt;Igalia&lt;/a&gt;, the etnaviv GPU driver now includes support for MRTs. If you’ve ever wondered how MRTs can transform your graphics pipeline or are curious about the challenges of implementing this feature, this blog post is for you.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Modern graphics programming revolves around achieving high-performance rendering and visually stunning effects. Among OpenGL’s capabilities, Multiple Render Targets (MRTs) are particularly valuable for enabling advanced rendering techniques with greater efficiency.</p>
<p>With the latest release of <a href="https://docs.mesa3d.org/relnotes/24.3.0.html">Mesa 24.03</a> and the commitment from <a href="https://www.igalia.com/">Igalia</a>, the etnaviv GPU driver now includes support for MRTs. If you’ve ever wondered how MRTs can transform your graphics pipeline or are curious about the challenges of implementing this feature, this blog post is for you.</p>
<h1 id="understanding-multiple-render-targets-mrts">Understanding Multiple Render Targets (MRTs)</h1>
<p>At its core, MRTs allow rendering to multiple images or &ldquo;render targets&rdquo; simultaneously during a single rendering pass. These render targets are buffers or textures that store various scene data such as color, depth, or normals. By writing to multiple targets at once, MRTs enable developers to:</p>
<ul>
<li>Enhance efficiency by reducing the number of rendering passes.</li>
<li>Implement sophisticated rendering techniques, such as deferred shading, which decouples geometry processing from lighting and shading.</li>
</ul>
<p>Here’s a simple OpenGLES shader example demonstrating how to use MRTs:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// Vertex Shader
</span></span></span><span class="line"><span class="cl"><span class="nf">layout</span><span class="p">(</span><span class="n">location</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">in</span> <span class="n">vec2</span> <span class="n">inPosition</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">gl_Position</span> <span class="o">=</span> <span class="nf">vec4</span><span class="p">(</span><span class="n">inPosition</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Fragment Shader
</span></span></span><span class="line"><span class="cl"><span class="nf">layout</span><span class="p">(</span><span class="n">location</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">out</span> <span class="n">vec4</span> <span class="n">fragColor1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nf">layout</span><span class="p">(</span><span class="n">location</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span> <span class="n">out</span> <span class="n">vec4</span> <span class="n">fragColor2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">fragColor1</span> <span class="o">=</span> <span class="nf">vec4</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span> <span class="c1">// Red
</span></span></span><span class="line"><span class="cl">    <span class="n">fragColor2</span> <span class="o">=</span> <span class="nf">vec4</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span> <span class="c1">// Blue
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This code renders two render targets: one red and one blue, by declaring two output locations in the fragment shader and writing different colors to each of them.</p>
<h1 id="how-mrts-are-used">How MRTs Are Used</h1>
<p>MRTs play an important role in graphics applications. Here are some of their most common use cases:</p>
<h3 id="1-deferred-rendering">1. <strong>Deferred Rendering</strong></h3>
<p>MRTs are the backbone of deferred shading, a technique where scene geometry is rendered to multiple targets, storing data like positions, normals, and albedo. This data is then processed in a second pass to calculate lighting, enabling advanced effects like dynamic shadows and screen-space reflections.</p>
<h3 id="2-post-processing-effects">2. <strong>Post-Processing Effects</strong></h3>
<p>By writing intermediate results to multiple targets, MRTs facilitate a wide range of effects, including bloom, depth of field, and ambient occlusion.</p>
<h3 id="3-debugging-and-visualization">3. <strong>Debugging and Visualization</strong></h3>
<p>Developers can output different types of scene data simultaneously for debugging or creating visualizations.</p>
<h1 id="implementing-mrts-in-etnaviv">Implementing MRTs in etnaviv</h1>
<p>Adding MRT support to the etnaviv driver involved significant reverse engineering and experimentation. Here’s a look at some of the challenges and solutions:</p>
<h2 id="reverse-engineering-the-gpu">Reverse Engineering the GPU</h2>
<p>The reverse engineering process begins with examining the limits exposed by the binary blob driver, such as the value returned by <code>GL_MAX_DRAW_BUFFERS</code>. Different Vivante GPU generations (HALTI) support varying numbers of render targets, requiring repeated testing and analysis.</p>
<h3 id="lay-the-foundation">Lay the foundation</h3>
<p>I started with Freedreno’s <a href="https://gitlab.freedesktop.org/freedreno/freedreno/-/blob/master/tests-3d/test-mrt-fbo.c?ref_type=heads">test-mrt-fbo</a> to get a rought idea of what needed to be done. Hours later, I identified most of the necessary bits and GPU states I had seen in the command stream dumps generated by the proprietary driver.</p>
<p>The first goal was to get a very basic piglit MRT test working on the GC7000 (HALTI5) GPU, rendering correctly with etnaviv. In this phase of reverse engineering, I usually hack around in the driver and my git commit history is full of &lsquo;hack/wip&rsquo; commits. This helps me keep track of the (breaking) changes I make during the process.</p>
<p>Looking at the changes I had made until here, it was clear that I had touched nearly every part of the gallium driver. It started with compiler changes to handle the extra color outputs and ended with the extra MRT states that needed to be emitted. And, to be honest, at this stage I also had broken some other CTS and piglit tests, but that was something to be taken care of later.</p>
<p>When I tried some more complex piglit tests that used sparse render targets, I saw that they failed and realized, after reverse-engineering the proprietary driver some more, that I needed to work on remapping some information provided by NIR in Mesa about fragment shader outputs into compressed info the driver needed. That didn&rsquo;t make all relevant Piglit tests pass, but I was getting close.</p>
<h3 id="will-it-work-on-another-gpu">Will it work on another GPU?</h3>
<p>The branch was then tested on older Vivante GPUs, like the GC3000 (HALTI2). None of the tests passed initially, as state emissions differed and the maximum MRT count was lower (4 vs. 8). Updating the state emission logic addressed these issues.</p>
<h3 id="whats-wrong-with-the-tile-status">Whats wrong with the Tile Status?</h3>
<p>As I always want to provide the best experience for all etnaviv users, I wanted to support this shiny new feature even on a much older Vivante GPU generation - GC2000 (HALT0) found in i.MX6 boards.</p>
<p>My hopes where high that my git branch would just work but, as usual, I was wrong. The traces from the vendor driver showed something interesting. There was no tile status (TS) usage found in the traces and I could confirm piglit was happy when I used <code>ETNA_MESA_DEBUG=no_ts</code>.</p>
<p>You might wonder that the ominous <code>Tile Status</code> might be. Let me give you a quick summary.</p>
<p>A render target is divided in tiles, and every tile has a couple of status flags. An auxiliary buffer - the so called <code>Tile Status</code> buffer - associated with each render surface keeps track of these tile status flags. One of these flags is the clear flag, that signifies that the tile has been cleared. For example, a fast clear happens by setting the clear bit for each tile instead of clearing the actual surface data.</p>
<p>I found a way to fix this problem too and then moved to CI.</p>
<h2 id="ci-to-test-them-all">CI to test them all</h2>
<p>If you&rsquo;ve followed me until here, you know that I worked on one HALTI and moved to another and never tested if I had broken any of the other HALTI&rsquo;s. It was time to let etnaviv&rsquo;s CI do its work and, as expected, I discovered I had broken HALTI5. After a local debugging session I got it into a working state. While I was very close to being ready to submit an MR and incorporate review feedback, there was one last thing I need to take care of&hellip;</p>
<h2 id="halti5-enhancements-for-mrts">HALTI5+ Enhancements for MRTs</h2>
<p>It turns out that a HALTI5 GPU can support more OpenGL extensions as it has even more GPU states that fall under the MRT umbrella. The MRT ground work that was already in place allowed me to implement the following ones:</p>
<h3 id="1-gl_">1. <strong>GL_EXT_draw_buffers2</strong></h3>
<p>This extension allows independent blending and write masking for each render target in an MRT setup. Developers can specify unique blending equations and masks for each target, offering unparalleled control over how data is combined.</p>
<h3 id="2-gl_">2. <strong>GL_ARB_draw_buffers_blend</strong></h3>
<p>This feature extends blending capabilities even further, enabling per-buffer blending equations and functions. It’s especially useful for advanced rendering pipelines, such as deferred shading and post-processing, where different render targets may require entirely distinct blending behaviors.</p>
<h1 id="conclusion">Conclusion</h1>
<p>With the addition of <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26565">MRT support</a> and the powerful HALTI5+ enhancements like <code>GL_EXT_draw_buffers2</code> and <code>GL_ARB_draw_buffers_blend</code>, the etnaviv driver has reached a significant milestone.</p>
<p>MRT support is also a key feature for achieving full GLES3 compliance, marking a step forward in modernizing the capabilities of the etnaviv driver.</p>
<p>For detailed reverse engineering results, check out this <a href="https://github.com/etnaviv/etna_vi">repository</a>, which uses the rnndb format to describe GPU states and bits. The MRT specific changes can be found in this <a href="https://github.com/etnaviv/etna_viv/commit/ce1ddcd09b7e15a8893722214bb668f890fcf486">commit</a>.</p>
<p><strong>What’s next?</strong> Stay tuned for more updates on the etnaviv driver as we continue to push more features upstream.</p>
]]></content:encoded>
    </item>
    <item>
      <title>CI-Tron: A Long Road to a Better Board Farm</title>
      <link>https://christian-gmeiner.info/2024-10-30-ci-tron-a-long-road-to-a-better-board-farm/</link>
      <pubDate>Wed, 30 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2024-10-30-ci-tron-a-long-road-to-a-better-board-farm/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m a big supporter of finding problems before they get into the code base. The earlier you catch issues, the easier they are to fix. One of the main tools that helps with this is a Continuous Integration (CI) farm. A CI farm allows you to run extensive tests like &lt;a href=&#34;https://github.com/KhronosGroup/VK-GL-CTS&#34;&gt;deqp&lt;/a&gt; or &lt;a href=&#34;https://piglit.freedesktop.org&#34;&gt;piglit&lt;/a&gt; on a merge request or even on a private git branch before any code is merged, which significantly helps catch problems early.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;m a big supporter of finding problems before they get into the code base. The earlier you catch issues, the easier they are to fix. One of the main tools that helps with this is a Continuous Integration (CI) farm. A CI farm allows you to run extensive tests like <a href="https://github.com/KhronosGroup/VK-GL-CTS">deqp</a> or <a href="https://piglit.freedesktop.org">piglit</a> on a merge request or even on a private git branch before any code is merged, which significantly helps catch problems early.</p>
<p>I&rsquo;m not the first one at <a href="https://www.igalia.com">Igalia</a> to think this is really important. We already have a large Raspberry Pi board farm available on freedesktop&rsquo;s GitLab instance that serves as a powerful tool for validating changes before they hit the main branch.</p>
<p>For a while, however, the etnaviv board farm has been offline. The main reason? I needed to clean up the setup: re-house it in a proper rack, redo all the wiring, and add more devices. What initially seemed like a few days&rsquo; worth of work spiraled into months of delay, mostly because I wanted to transition to using <a href="https://gitlab.freedesktop.org/gfx-ci/ci-tron">ci-tron</a>.</p>
<h1 id="getting-familiar-with-the-ci-tron-setup">Getting Familiar with the Ci-Tron Setup</h1>
<p>Before diving into my journey, let’s quickly cover what makes up a ci-tron board farm.</p>
<ul>
<li><strong>Ci-Tron Gateway</strong>: This component is the central hub that manages devices.</li>
<li><strong>PDU (Power Delivery Unit)</strong>: A PDU is a device that manages the electrical power distribution to all the components in the CI farm. It allows you to remotely control the power, including power cycling devices, which is crucial for automating device management.</li>
<li><strong>DUT (Device Under Test)</strong>: The heart of the CI farm—these are the devices where the actual testing happens.</li>
</ul>
<h1 id="the-long-road-to-a-working-farm">The Long Road to a Working Farm</h1>
<p>Over the past few months, I’ve been slowly preparing for the big ci-tron transition. The first step was ensuring my <a href="https://www.robot-electronics.co.uk/eth008b.html">PDU</a> was compatible. It wasn&rsquo;t initially supported, but after some hacking, I got it working and submitted a <a href="https://gitlab.freedesktop.org/gfx-ci/ci-tron/-/merge_requests/715">merge request (MR)</a>. After a few rounds of revisions, it was merged, expanding ci-tron’s PDU support significantly.</p>
<p>The next and most critical step was getting a DUT to boot up correctly. Initially, ci-tron only supported iPXE as a boot method, but my devices are using U-Boot. I tried to make it work anyway, but the network initialization failed too often, and I found myself sinking hours into debugging.</p>
<p>Thankfully, rudimentary support for a <a href="https://www.u-boot.org">U-Boot</a> based boot flow was eventually added. After some tweaks, I managed to get my DUTs booting — but not without complications. A major problem was getting the correct Device Tree Blob (DTB) to load, which was needed for ci-tron&rsquo;s training rounds. A Device Tree Blob (DTB) is a binary representation of the hardware layout of a device. The DTB is used by the Linux kernel to understand the hardware configuration, including components like the CPU, memory, and peripherals. In my case, ensuring that the correct DTB was provided was crucial for the DUT to boot and be correctly managed by ci-tron. While integrating the DTB into U-Boot was suggested, it wasn’t ideal. Updating the bootloader just to change a DTB is cumbersome, especially with multiple devices in the farm.</p>
<p>With the booting issue taking up too much time, I decided to put it on hold and focus on something else: gfxinfo.</p>
<h1 id="gfxinfo-integration-challenges">Gfxinfo Integration Challenges</h1>
<p>gfxinfo is a neat feature that automatically tags a DUT based on the GPU model in the system, avoiding the need for manually assigning tags like <code>gc2000</code>. In theory, it’s very convenient—but in practice, there were hurdles.</p>
<p>gfxinfo tags Vivante GPUs using the device tree node information. However, since Vivante GPUs are quite generic, they don’t have a specific model property that uniquely identifies them. The plan was to pull this information using <code>ioctl()</code> calls to the etnaviv kernel driver. It took a lot of back and forth in review due to the internal gfxinfo API being under-documented, but after a lot of effort, I finally got the necessary code merged. You can find all of it in this <a href="https://gitlab.freedesktop.org/gfx-ci/ci-tron/-/merge_requests/758">MR</a>.</p>
<h1 id="final-push-getting-everything-to-boot">Final Push: Getting Everything to Boot</h1>
<p>There was still one major obstacle — getting the DUT to boot reliably. Luckily, <a href="https://gitlab.freedesktop.org/mupuf">mupuf</a> was already working on it and made a significant <a href="https://gitlab.freedesktop.org/gfx-ci/ci-tron/-/merge_requests/781">MR</a> with over 80 patches to address the boot issues. Introducing &ldquo;boots db,&rdquo; a feature designed to decouple the boot process, granting full control over DHCP, TFTP, and HTTP servers to each job. This is paired with YAML configurations to flexibly define the boot specifics for each board.</p>
<p>As of a few days ago, the latest official ci-tron gateway image contains everything needed to get an etnaviv DUT up and running successfully.</p>
<p><img alt="tags" loading="lazy" src="/img/ci-tron.png"></p>
<p>I have to say, I’m very impressed with the end result. It took a lot longer than I had anticipated, but we finally have a plug-and-play CI farm solution for etnaviv. There are still a few missing features—like Network Block Device (NBD) support and some advanced statistics—but the ci-tron team is doing an excellent job, and I&rsquo;m optimistic about what&rsquo;s coming next.</p>
<h1 id="conclusion-a-long-road-but-worth-it">Conclusion: A Long Road, but Worth It</h1>
<p>The journey to get the etnaviv board farm back online was longer than expected, full of unexpected challenges and technical hurdles. But it was worth it. The result is a robust, automated solution that makes CI testing easier and more reliable for everyone. With ci-tron, it’s easier to find and fix problems before they ever make it into the code base, which is exactly what a good CI setup should be all about. There is still some work to be done on the GitLab side to switch all etnaviv jobs to the new board farm.</p>
<p>If you&rsquo;re thinking about setting up your own CI farm or migrating to ci-tron, I hope my experience helps smooth the road for you a bit. It might be a long journey, but the end results are absolutely worth it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>It All Started With a Nop - Part I</title>
      <link>https://christian-gmeiner.info/2024-07-11-it-all-started-with-a-nop-part1/</link>
      <pubDate>Thu, 11 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2024-07-11-it-all-started-with-a-nop-part1/</guid>
      <description>&lt;style type=&#34;text/css&#34;&gt;
     
    .notice {
        --title-color: #fff;
        --title-background-color: #6be;
        --content-color: #444;
        --content-background-color: #e7f2fa;
    }

    .notice.info {
        --title-background-color: #fb7;
        --content-background-color: #fec;
    }

    .notice.tip {
        --title-background-color: #5a5;
        --content-background-color: #efe;
    }

    .notice.warning {
        --title-background-color: #c33;
        --content-background-color: #fee;
    }

     
    @media (prefers-color-scheme:dark) {
        .notice {
            --title-color: #fff;
            --title-background-color: #069;
            --content-color: #ddd;
            --content-background-color: #023;
        }

        .notice.info {
            --title-background-color: #a50;
            --content-background-color: #420;
        }

        .notice.tip {
            --title-background-color: #363;
            --content-background-color: #121;
        }

        .notice.warning {
            --title-background-color: #800;
            --content-background-color: #400;
        }
    }

    body.dark .notice {
        --title-color: #fff;
        --title-background-color: #069;
        --content-color: #ddd;
        --content-background-color: #023;
    }

    body.dark .notice.info {
        --title-background-color: #a50;
        --content-background-color: #420;
    }

    body.dark .notice.tip {
        --title-background-color: #363;
        --content-background-color: #121;
    }

    body.dark .notice.warning {
        --title-background-color: #800;
        --content-background-color: #400;
    }

     
    .notice {
        padding: 18px;
        line-height: 24px;
        margin-bottom: 24px;
        border-radius: 4px;
        color: var(--content-color);
        background: var(--content-background-color);
    }

    .notice p:last-child {
        margin-bottom: 0
    }

     
    .notice-title {
        margin: -18px -18px 12px;
        padding: 4px 18px;
        border-radius: 4px 4px 0 0;
        font-weight: 700;
        color: var(--title-color);
        background: var(--title-background-color);
    }

     
    .icon-notice {
        display: inline-flex;
        align-self: center;
        margin-right: 8px;
    }

    .icon-notice img,
    .icon-notice svg {
        height: 1em;
        width: 1em;
        fill: currentColor;
    }

    .icon-notice img,
    .icon-notice.baseline svg {
        top: .125em;
        position: relative;
    }
&lt;/style&gt;&lt;div class=&#34;notice note&#34; &gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 128 300 300&#34;&gt;
  &lt;path d=&#34;M150 128c82.813 0 150 67.188 150 150 0 82.813-67.188 150-150 150C67.187 428 0 360.812 0 278c0-82.813 67.188-150 150-150Zm25 243.555v-37.11c0-3.515-2.734-6.445-6.055-6.445h-37.5c-3.515 0-6.445 2.93-6.445 6.445v37.11c0 3.515 2.93 6.445 6.445 6.445h37.5c3.32 0 6.055-2.93 6.055-6.445Zm-.39-67.188 3.515-121.289c0-1.367-.586-2.734-1.953-3.516-1.172-.976-2.93-1.562-4.688-1.562h-42.968c-1.758 0-3.516.586-4.688 1.563-1.367.78-1.953 2.148-1.953 3.515l3.32 121.29c0 2.734 2.93 4.882 6.64 4.882h36.134c3.515 0 6.445-2.148 6.64-4.883Z&#34;/&gt;
&lt;/svg&gt;

        &lt;/span&gt;Note&lt;/p&gt;</description>
      <content:encoded><![CDATA[<style type="text/css">
     
    .notice {
        --title-color: #fff;
        --title-background-color: #6be;
        --content-color: #444;
        --content-background-color: #e7f2fa;
    }

    .notice.info {
        --title-background-color: #fb7;
        --content-background-color: #fec;
    }

    .notice.tip {
        --title-background-color: #5a5;
        --content-background-color: #efe;
    }

    .notice.warning {
        --title-background-color: #c33;
        --content-background-color: #fee;
    }

     
    @media (prefers-color-scheme:dark) {
        .notice {
            --title-color: #fff;
            --title-background-color: #069;
            --content-color: #ddd;
            --content-background-color: #023;
        }

        .notice.info {
            --title-background-color: #a50;
            --content-background-color: #420;
        }

        .notice.tip {
            --title-background-color: #363;
            --content-background-color: #121;
        }

        .notice.warning {
            --title-background-color: #800;
            --content-background-color: #400;
        }
    }

    body.dark .notice {
        --title-color: #fff;
        --title-background-color: #069;
        --content-color: #ddd;
        --content-background-color: #023;
    }

    body.dark .notice.info {
        --title-background-color: #a50;
        --content-background-color: #420;
    }

    body.dark .notice.tip {
        --title-background-color: #363;
        --content-background-color: #121;
    }

    body.dark .notice.warning {
        --title-background-color: #800;
        --content-background-color: #400;
    }

     
    .notice {
        padding: 18px;
        line-height: 24px;
        margin-bottom: 24px;
        border-radius: 4px;
        color: var(--content-color);
        background: var(--content-background-color);
    }

    .notice p:last-child {
        margin-bottom: 0
    }

     
    .notice-title {
        margin: -18px -18px 12px;
        padding: 4px 18px;
        border-radius: 4px 4px 0 0;
        font-weight: 700;
        color: var(--title-color);
        background: var(--title-background-color);
    }

     
    .icon-notice {
        display: inline-flex;
        align-self: center;
        margin-right: 8px;
    }

    .icon-notice img,
    .icon-notice svg {
        height: 1em;
        width: 1em;
        fill: currentColor;
    }

    .icon-notice img,
    .icon-notice.baseline svg {
        top: .125em;
        position: relative;
    }
</style><div class="notice note" >
    <p class="notice-title">
        <span class="icon-notice baseline">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 128 300 300">
  <path d="M150 128c82.813 0 150 67.188 150 150 0 82.813-67.188 150-150 150C67.187 428 0 360.812 0 278c0-82.813 67.188-150 150-150Zm25 243.555v-37.11c0-3.515-2.734-6.445-6.055-6.445h-37.5c-3.515 0-6.445 2.93-6.445 6.445v37.11c0 3.515 2.93 6.445 6.445 6.445h37.5c3.32 0 6.055-2.93 6.055-6.445Zm-.39-67.188 3.515-121.289c0-1.367-.586-2.734-1.953-3.516-1.172-.976-2.93-1.562-4.688-1.562h-42.968c-1.758 0-3.516.586-4.688 1.563-1.367.78-1.953 2.148-1.953 3.515l3.32 121.29c0 2.734 2.93 4.882 6.64 4.882h36.134c3.515 0 6.445-2.148 6.64-4.883Z"/>
</svg>

        </span>Note</p><p>This blog post is part <strong>1</strong> of a series of blog posts about isaspec and its usage in the etnaviv GPU stack.</p>
<p>I will add here links to the other blog posts, once they are published.</p></div>

<p>The first time I heard about isaspec, I was blown away by the possibilities it opens. I am really thankful that <a href="https://www.igalia.com/">Igalia</a> made it possible to complete this crucial piece of core infrastructure for the etnaviv GPU stack.</p>
<p>If isaspec is new to you, here is what <a href="https://docs.mesa3d.org/isaspec.html">the Mesa docs</a> have to tell about it:</p>
<blockquote>
<p>isaspec provides a mechanism to describe an instruction set in XML, and generate a disassembler and assembler. The intention is to describe the instruction set more formally than hand-coded assembler and disassembler, and better decouple the shader compiler from the underlying instruction encoding to simplify dealing with instruction encoding differences between generations of GPU.</p>
<p>Benefits of a formal ISA description, compared to hand-coded assemblers and disassemblers, include easier detection of new bit combinations that were not seen before in previous generations due to more rigorous description of bits that are expect to be ‘0’ or ‘1’ or ‘x’ (dontcare) and verification that different encodings don’t have conflicting bits (i.e. that the specification cannot result in more than one valid interpretation of any bit pattern).</p>
</blockquote>
<p>If you are interested in more details, I highly recommend Rob Clark&rsquo;s <a href="https://www.youtube.com/watch?v=o0npIiIF-Dw">introduction to isaspec</a> presentation.</p>
<h1 id="target-isa">Target ISA</h1>
<p>Vivante uses a fixed-size (128 bits), predictable instruction format with explicit inputs and outputs.</p>
<p>As of today, there are three different encodings seen in the wild:</p>
<ul>
<li>Base Instruction Set</li>
<li>Extended Instruction Set</li>
<li>Enhanced Vision Instruction Set (EVIS)</li>
</ul>
<h1 id="why-do-i-want-to-switch-to-isaspec">Why do I want to switch to isaspec</h1>
<p>There are several reasons..</p>
<h2 id="the-current-state">The current state</h2>
<p>The <a href="https://github.com/etnaviv/etna_viv/blob/master/rnndb/isa.xml">current ISA documentation</a> is not very explicit and leaves lot of room for interpretation and speculation. One thing that it provides, are some nice explanations what an instruction does. isaspec does not support <code>&lt;doc&gt;</code> tags yet, but I there is a <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23763">PoC MR</a> that generates really nice looking and information ISA documentation based on the xml.</p>
<p>I think soon you might find all etnaviv&rsquo;s isaspec documentation at <a href="https://docs.mesa3d.org">docs.mesa3d.org</a>.</p>
<h2 id="no-unit-tests">No unit tests</h2>
<p>There are no unit tests based on instructions generated by the blob driver. This might not sound too bad, but it opens the door to generating &lsquo;bad&rsquo; encoded instructions that could trigger all sorts of weird and hard-to-debug problems. Such breakages could be caused by some compiler rework, etc.</p>
<p>In an ideal world, there would be a unit test that does the following:</p>
<ul>
<li>Disassembles the binary representation of an instruction from the blob to a string representation.</li>
<li>Verifies that it matches our expectation.</li>
<li>Assembles the string representation back to 128 bits.</li>
<li>Verifies that it matches the binary representation from the blob driver.</li>
</ul>
<p>This is our ultimate goal, which we <em>really</em> must reach. etnaviv will not be the only driver that does such deep unit testing - e.g. <a href="https://docs.mesa3d.org/drivers/freedreno.html">freedreno</a> <a href="https://cgit.freedesktop.org/mesa/mesa/tree/src/freedreno/ir3/tests/disasm.c#n581">does it too</a>.</p>
<h2 id="easier-to-understand-code">Easier to understand code</h2>
<p>Do you remember the rusticl OpenCL attempt for etnaviv? It contains lines like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nf">nir_src_is_const</span><span class="p">(</span><span class="n">intr</span><span class="o">-&gt;</span><span class="n">src</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">inst</span><span class="p">.</span><span class="n">tex</span><span class="p">.</span><span class="n">swiz</span> <span class="o">=</span> <span class="mi">128</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="n">rmode</span> <span class="o">==</span> <span class="n">nir_rounding_mode_rtz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="n">inst</span><span class="p">.</span><span class="n">tex</span><span class="p">.</span><span class="n">amode</span> <span class="o">=</span> <span class="mh">0x4</span> <span class="o">+</span> <span class="n">INST_ROUND_MODE_RTZ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">else</span> <span class="cm">/*if (rmode == nir_rounding_mode_rtne)*/</span>
</span></span><span class="line"><span class="cl">         <span class="n">inst</span><span class="p">.</span><span class="n">tex</span><span class="p">.</span><span class="n">amode</span> <span class="o">=</span> <span class="mh">0x4</span> <span class="o">+</span> <span class="n">INST_ROUND_MODE_RTNE</span><span class="p">;</span>
</span></span></code></pre></div><p>Do you clearly see what is going on? Why do we need to set tex.amode for an ALU instruction?</p>
<p>I always found it quite disappointing to see such code snippets. Sure, they mimic what the blob driver is doing, but you might lose all the knowledge about why these bits are used that way days after you worked on it. There must be a cleaner, more understandable, and thus more maintainable way to document the ISA better.</p>
<p>This situation might become even worse if we want to support the other encodings and could end up with more of these bad patterns, resulting in a maintenance nightmare.</p>
<p>Oh, and if you wonder what happened to OpenCL and etnaviv - I promise there will be an update later this year.</p>
<h2 id="python-opens-the-door-to-generate-lot-of-code">Python opens the door to generate lot of code</h2>
<p>As isaspec is written in Python, it is really easy to extend it and add support for new functionality.</p>
<p>At its core, we can generate a disassembler and an assembler based on isaspec. This alone saves us from writing a lot of code that needs to be kept in sync with all the ISA reverse engineering findings that happen over time.</p>
<p>As isaspec is just an ordinary XML file, you can use any programming language you like to work with it.</p>
<h2 id="one-source-of-truth">One source of truth</h2>
<p>I really fell in love with the idea of having <em>one</em> source of truth that models our target ISA, contains written documentation, and extends each opcode with meta information that can be used in the upper layers of the compiler stack.</p>
<h1 id="missing-features">Missing Features</h1>
<p>I think I have sold you the idea quite well, so it must be a matter of some days to switch to it.
Sadly no, as there are some missing features:</p>
<ul>
<li>Only max 64 bits width ISAs are supported</li>
<li>Its home in src/freedreno</li>
<li>Alignment support is missing</li>
<li>No <code>&lt;meta&gt;</code> tags are supported</li>
</ul>
<h1 id="add-support-for-128-bit-wide-instructions">Add support for 128 bit wide instructions</h1>
<p>The first big <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11321">MR</a> I worked on, extended  <a href="https://cgit.freedesktop.org/mesa/mesa/tree/src/util/bitset.h">BITSET APIs</a> with features needed for isaspec.
Here we are talking about bitwise AND, OR, and NOT, and left shifts.</p>
<p>The next step was to switch isaspec to use the BITSET API to support wider ISAs. This resulted in a lot of commits, as there was a need for some new APIs to support handling this new feature. After these 31 commits, we were able to start looking into isaspec support for etnaviv.</p>
<h1 id="decode-support">Decode Support</h1>
<p>Now it is time to start writing an isaspec XML for etnaviv, and the easiest opcode to start with is the <code>nop</code>. As the name suggests, it does nothing and has no src&rsquo;s, no dst, or any other modifier.</p>
<p>As I do not have this initial version anymore, I tried to recreate it - it might have looked something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;isa&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;bitset</span> <span class="na">name=</span><span class="s">&#34;#instruction&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;display&gt;</span>
</span></span><span class="line"><span class="cl">		{NAME} void, void, void, void
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;/display&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;6&#34;</span> <span class="na">high=</span><span class="s">&#34;10&#34;</span><span class="nt">&gt;</span>00000<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;11&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;12&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;13&#34;</span> <span class="na">high=</span><span class="s">&#34;26&#34;</span><span class="nt">&gt;</span>00000000000000<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;27&#34;</span> <span class="na">high=</span><span class="s">&#34;31&#34;</span><span class="nt">&gt;</span>00000<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;32&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;33&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;34&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;35&#34;</span> <span class="na">high=</span><span class="s">&#34;38&#34;</span><span class="nt">&gt;</span>0000<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;39&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;40&#34;</span> <span class="na">high=</span><span class="s">&#34;42&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c">&lt;!-- SRC0 --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;43&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_USE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;44&#34;</span> <span class="na">high=</span><span class="s">&#34;52&#34;</span><span class="nt">&gt;</span>000000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_REG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;53&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;54&#34;</span> <span class="na">high=</span><span class="s">&#34;61&#34;</span><span class="nt">&gt;</span>00000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_SWIZ --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;62&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_NEG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;63&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_ABS --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;64&#34;</span> <span class="na">high=</span><span class="s">&#34;66&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_AMODE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;67&#34;</span> <span class="na">high=</span><span class="s">&#34;69&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC0_RGROUP --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c">&lt;!-- SRC1 --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;70&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_USE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;71&#34;</span> <span class="na">high=</span><span class="s">&#34;79&#34;</span><span class="nt">&gt;</span>000000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_REG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;81&#34;</span> <span class="na">high=</span><span class="s">&#34;88&#34;</span><span class="nt">&gt;</span>00000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_SWIZ --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;89&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_NEG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;90&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_ABS --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;91&#34;</span> <span class="na">high=</span><span class="s">&#34;93&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_AMODE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;94&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;95&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;96&#34;</span> <span class="na">high=</span><span class="s">&#34;98&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC1_RGROUP --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c">&lt;!-- SRC2 --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;99&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_USE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;100&#34;</span> <span class="na">high=</span><span class="s">&#34;108&#34;</span><span class="nt">&gt;</span>000000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_REG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;110&#34;</span> <span class="na">high=</span><span class="s">&#34;117&#34;</span><span class="nt">&gt;</span>00000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_SWIZ --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;118&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_NEG --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;119&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_ABS --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;120&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;121&#34;</span> <span class="na">high=</span><span class="s">&#34;123&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_AMODE --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;124&#34;</span> <span class="na">high=</span><span class="s">&#34;126&#34;</span><span class="nt">&gt;</span>000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- SRC2_RGROUP --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;127&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/bitset&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- opcocdes sorted by opc number --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">&lt;bitset</span> <span class="na">name=</span><span class="s">&#34;nop&#34;</span> <span class="na">extends=</span><span class="s">&#34;#instruction&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">low=</span><span class="s">&#34;0&#34;</span> <span class="na">high=</span><span class="s">&#34;5&#34;</span><span class="nt">&gt;</span>000000<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- OPC --&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&lt;pattern</span> <span class="na">pos=</span><span class="s">&#34;80&#34;</span><span class="nt">&gt;</span>0<span class="nt">&lt;/pattern&gt;</span> <span class="c">&lt;!-- OPCODE_BIT6 --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/bitset&gt;&lt;/isa&gt;</span>
</span></span></code></pre></div><p>With the knowledge of the old ISA documentation, I went fishing for instructions. I <em>only</em> used instructions from the binary blob for this process. It is quite important for me to have as many unit tests as I can write to not break any decoding with some isaspec XML changes I do. And it was a huge lifesaver at that time.</p>
<p>After I reached almost feature parity with the old disassembler, I thought it was time to land etnaviv.xml and replace the current handwritten disassembler with a generated one - yeah, so I submitted <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20144">an MR</a> to make the switch.</p>
<p>As this is only a driver internal disassembler used by maybe 2-3 human beings, it would not be a problem if there were some regressions.</p>
<p>Today I would say the isaspec disassembler is superior to the handwritten one.</p>
<h1 id="encode-support">Encode Support</h1>
<p>The next item on my list was to add encoding support. As you can imagine, there was some work needed upfront to support ISAs that are bigger than 64 bits.  This time the <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16996">MR</a> only contains two commits 😄.</p>
<p>With everything ready it is time to add <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28183">isaspec based encoding support to etnaviv.</a></p>
<p>The goal is to drop our custom (and too simple) assembler and switch to one that is powered by isaspec.</p>
<p>This opens the door to:</p>
<ul>
<li>Modeling special cases for instructions like a branch with no src&rsquo;s to a new jump instruction.</li>
<li>Doing the NIR src -&gt; instruction src mapping in isaspec.</li>
<li>Supporting different instruction encodings.</li>
<li>Adding meta information to instructions.</li>
</ul>
<h1 id="supporting-special-instructions-that-are-used-in-compiler-unit-tests">Supporting special instructions that are used in compiler unit tests</h1>
<p>In the end, all the magic that is needed is shown in the following diff:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-patch" data-lang="patch"><span class="line"><span class="cl"><span class="gh">diff --git a/src/etnaviv/isa/etnaviv.xml b/src/etnaviv/isa/etnaviv.xml
</span></span></span><span class="line"><span class="cl"><span class="gh">index eca8241a2238a..c9a3ebe0a40c2 100644
</span></span></span><span class="line"><span class="cl"><span class="gd">--- a/src/etnaviv/isa/etnaviv.xml
</span></span></span><span class="line"><span class="cl"><span class="gi">+++ b/src/etnaviv/isa/etnaviv.xml
</span></span></span><span class="line"><span class="cl"><span class="gu">@@ -125,6 +125,13 @@ SPDX-License-Identifier: MIT
</span></span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;AMODE&#34; low=&#34;0&#34; high=&#34;2&#34; type=&#34;#reg_addressing_mode&#34;/&gt;
</span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;REG&#34; low=&#34;3&#34; high=&#34;9&#34; type=&#34;uint&#34;/&gt;
</span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;COMPS&#34; low=&#34;10&#34; high=&#34;13&#34; type=&#34;#wrmask&#34;/&gt;
</span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;encode type=&#34;struct etna_inst_dst *&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;DST_USE&#34;&gt;p-&gt;DST_USE&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;AMODE&#34;&gt;src-&gt;amode&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;REG&#34;&gt;src-&gt;reg&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;COMPS&#34;&gt;p-&gt;COMPS&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;/encode&gt;
</span></span></span><span class="line"><span class="cl"> &lt;/bitset&gt;
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> &lt;bitset name=&#34;#instruction&#34; size=&#34;128&#34;&gt;
</span></span><span class="line"><span class="cl"><span class="gu">@@ -137,6 +144,46 @@ SPDX-License-Identifier: MIT
</span></span></span><span class="line"><span class="cl"> 	&lt;derived name=&#34;TYPE&#34; type=&#34;#type&#34;&gt;
</span></span><span class="line"><span class="cl"> 		&lt;expr&gt;{TYPE_BIT2} &amp;lt;&amp;lt; 2 | {TYPE_BIT01}&lt;/expr&gt;
</span></span><span class="line"><span class="cl"> 	&lt;/derived&gt;
</span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;encode type=&#34;struct etna_inst *&#34; case-prefix=&#34;ISA_OPC_&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;TYPE_BIT01&#34;&gt;src-&gt;type &amp;amp; 0x3&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;TYPE_BIT2&#34;&gt;(src-&gt;type &amp;amp; 0x4) &amp;gt; 2&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;LOW_HALF&#34;&gt;src-&gt;sel_bit0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;HIGH_HALF&#34;&gt;src-&gt;sel_bit1&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;COND&#34;&gt;src-&gt;cond&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;RMODE&#34;&gt;src-&gt;rounding&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SAT&#34;&gt;src-&gt;sat&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;DST_USE&#34;&gt;src-&gt;dst.use&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;DST&#34;&gt;&amp;amp;src-&gt;dst&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;DST_FULL&#34;&gt;src-&gt;dst_full&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;COMPS&#34;&gt;src-&gt;dst.write_mask&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC0&#34;&gt;&amp;amp;src-&gt;src[0]&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC0_USE&#34;&gt;src-&gt;src[0].use&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC0_REG&#34;&gt;src-&gt;src[0].reg&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC0_RGROUP&#34;&gt;src-&gt;src[0].rgroup&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC0_AMODE&#34;&gt;src-&gt;src[0].amode&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC1&#34;&gt;&amp;amp;src-&gt;src[1]&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC1_USE&#34;&gt;src-&gt;src[1].use&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC1_REG&#34;&gt;src-&gt;src[1].reg&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC1_RGROUP&#34;&gt;src-&gt;src[1].rgroup&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC1_AMODE&#34;&gt;src-&gt;src[1].amode&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC2&#34;&gt;&amp;amp;src-&gt;src[2]&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC2_USE&#34;&gt;rc-&gt;src[2].use&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC2_REG&#34;&gt;src-&gt;src[2].reg&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC2_RGROUP&#34;&gt;src-&gt;src[2].rgroup&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC2_AMODE&#34;&gt;src-&gt;src[2].amode&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;TEX_ID&#34;&gt;src-&gt;tex.id&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;TEX_SWIZ&#34;&gt;src-&gt;tex.swiz&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;TARGET&#34;&gt;src-&gt;imm&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;!-- sane defaults --&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;PMODE&#34;&gt;1&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SKPHP&#34;&gt;0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;LOCAL&#34;&gt;0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;DENORM&#34;&gt;0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;LEFT_SHIFT&#34;&gt;0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;/encode&gt;
</span></span></span><span class="line"><span class="cl"> &lt;/bitset&gt;
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> &lt;bitset name=&#34;#src-swizzle&#34; size=&#34;8&#34;&gt;
</span></span><span class="line"><span class="cl"><span class="gu">@@ -148,6 +195,13 @@ SPDX-License-Identifier: MIT
</span></span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;SWIZ_Y&#34; low=&#34;2&#34; high=&#34;3&#34; type=&#34;#swiz&#34;/&gt;
</span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;SWIZ_Z&#34; low=&#34;4&#34; high=&#34;5&#34; type=&#34;#swiz&#34;/&gt;
</span></span><span class="line"><span class="cl"> 	&lt;field name=&#34;SWIZ_W&#34; low=&#34;6&#34; high=&#34;7&#34; type=&#34;#swiz&#34;/&gt;
</span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;encode type=&#34;uint8_t&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SWIZ_X&#34;&gt;(src &amp;amp; 0x03) &amp;gt;&amp;gt; 0&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SWIZ_Y&#34;&gt;(src &amp;amp; 0x0c) &amp;gt;&amp;gt; 2&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SWIZ_Z&#34;&gt;(src &amp;amp; 0x30) &amp;gt;&amp;gt; 4&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SWIZ_W&#34;&gt;(src &amp;amp; 0xc0) &amp;gt;&amp;gt; 6&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;/encode&gt;
</span></span></span><span class="line"><span class="cl"> &lt;/bitset&gt;
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> &lt;enum name=&#34;#thread&#34;&gt;
</span></span><span class="line"><span class="cl"><span class="gu">@@ -272,6 +326,13 @@ SPDX-License-Identifier: MIT
</span></span></span><span class="line"><span class="cl"> 			&lt;/expr&gt;
</span></span><span class="line"><span class="cl"> 		&lt;/derived&gt;
</span></span><span class="line"><span class="cl"> 	&lt;/override&gt;
</span></span><span class="line"><span class="cl"><span class="gi">+
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;encode type=&#34;struct etna_inst_src *&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC_SWIZ&#34;&gt;src-&gt;swiz&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC_NEG&#34;&gt;src-&gt;neg&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC_ABS&#34;&gt;src-&gt;abs&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+		&lt;map name=&#34;SRC_RGROUP&#34;&gt;p-&gt;SRC_RGROUP&lt;/map&gt;
</span></span></span><span class="line"><span class="cl"><span class="gi">+	&lt;/encode&gt;
</span></span></span><span class="line"><span class="cl"> &lt;/bitset&gt;
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> &lt;bitset name=&#34;#instruction-alu-no-src&#34; extends=&#34;#instruction-alu&#34;&gt;
</span></span></code></pre></div><p>One nice side effect of this work is the removal of <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=6b1456ccdbccedaa3342fd1a7a0a6fbba26df49b">isa.xml.h</a> file that has been part of etnaviv since day one. We are able to generate all the file contents with isaspec and some custom python3 scripts. The move <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28922">of instruction src swizzling</a> from the driver into etnaviv.xml was super easy - less code to maintain!</p>
<h1 id="summary">Summary</h1>
<p>I am really happy with the end result, even though it took quite some time from the initial idea to the point when everything was integrated into Mesa&rsquo;s main git branch.</p>
<p>There is so much more to share - I can&rsquo;t wait to publish parts II and III.</p>
]]></content:encoded>
    </item>
    <item>
      <title>hwdb - The only truth</title>
      <link>https://christian-gmeiner.info/2024-04-12-hwdb/</link>
      <pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2024-04-12-hwdb/</guid>
      <description>&lt;p&gt;Trusting hardware, particularly the registers that describe its functionality, is fundamentally risky.&lt;/p&gt;
&lt;h1 id=&#34;tldr&#34;&gt;tl;dr&lt;/h1&gt;
&lt;p&gt;The etnaviv GPU stack is continuously improving and becoming more robust. This time, a hardware database was incorporated into Mesa, utilizing header files provided by the SoC vendors.&lt;/p&gt;
&lt;p&gt;If you are interested in the implementation details, I recommend checking out this &lt;a href=&#34;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28574&#34;&gt;Mesa MR&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Are you employed at &lt;a href=&#34;https://www.verisilicon.com/&#34;&gt;Versilicon&lt;/a&gt; and want to help? You could greatly simplify our work by supplying the community with a comprehensive header that includes all the models you offer.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Trusting hardware, particularly the registers that describe its functionality, is fundamentally risky.</p>
<h1 id="tldr">tl;dr</h1>
<p>The etnaviv GPU stack is continuously improving and becoming more robust. This time, a hardware database was incorporated into Mesa, utilizing header files provided by the SoC vendors.</p>
<p>If you are interested in the implementation details, I recommend checking out this <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28574">Mesa MR</a>.</p>
<p>Are you employed at <a href="https://www.verisilicon.com/">Versilicon</a> and want to help? You could greatly simplify our work by supplying the community with a comprehensive header that includes all the models you offer.</p>
<p>Last but not least: I deeply appreciate <a href="https://www.igalia.com/">Igalia</a>&rsquo;s passion for open source GPU driver development, and I am grateful to be a part of the team. Their enthusiasm for open source work not only pushes the boundaries of technology but also builds a strong, collaborative community around it.</p>
<h1 id="the-good-old-days">The good old days</h1>
<p>Years ago, when I began dedicating time to hacking on etnaviv, the kernel driver in use would read a handful of registers and relay the gathered information to the user space blob. This blob driver was then capable of identifying the GPU (including model, revision, etc.), supported features (such as DXT texture compression, seamless cubemaps, etc.), and crucial limits (like the number of registers, number of varyings, and so on).</p>
<p>For reverse engineering purposes, this interface is super useful. Image if you could change one of these feature bits on a target running the binary blob.</p>
<p>With <a href="https://github.com/etnaviv/libvivhook">libvivhook</a> it is possible to do exactly this. From time to time, I am running such an old vendor driver stack on an i.MX 6QuadPlus SBC, which features a Vivante GC3000 as its GPU.</p>
<p>Somewhere, I have a collection of scripts that I utilized to acquire additional knowledge about unknown GPU states activated when a specific feature bit was set.</p>
<p>To explore a simple example, let&rsquo;s consider the case of misrepresenting a GPU&rsquo;s identity as a GC2000. This involves modifying the information provided by the kernel driver to the user space, making the user space driver believe it is interacting with a GC2000 GPU. This scenario could be used for testing, debugging, or understanding how specific features or optimizations are handled differently across GPU models.</p>
<pre tabindex="0"><code>export ETNAVIV_CHIP_MODEL=&#34;0x2000&#34;
export ETNAVIV_CHIP_REVISION=&#34;0x5108&#34;
export ETNAVIV_FEATURES0_CLEAR=&#34;0xFFFFFFFF&#34;
export ETNAVIV_FEATURES1_CLEAR=&#34;0xFFFFFFFF&#34;
export ETNAVIV_FEATURES2_CLEAR=&#34;0xFFFFFFFF&#34;
export ETNAVIV_FEATURES0_SET=&#34;0xe0296cad&#34;
export ETNAVIV_FEATURES1_SET=&#34;0xc9799eff&#34;
export ETNAVIV_FEATURES2_SET=&#34;0x2efbf2d9&#34;
LD_PRELOAD=&#34;/lib/viv_interpose.so&#34; ./test-case
</code></pre><p>If you capture the generated command stream and compare it with the one produced under the correct identity, you&rsquo;ll observe many differences. This is super useful - I love it.</p>
<h1 id="changing-tides-the-shift-in-ioctl-interface">Changing Tides: The Shift in ioctl() Interface</h1>
<p>At some point in time, Vivante changed their ioctl() interface and modified the <code>gcvHAL_QUERY_CHIP_IDENTITY</code> command. Instead of providing a very detailed chip identity, they reduced the data set to the following values:</p>
<ul>
<li>model</li>
<li>revision</li>
<li>product id</li>
<li>eco id</li>
<li>customer id</li>
</ul>
<p>This shift could indeed hinder reverse engineering efforts significantly. At a glance, it becomes impossible to alter any feature value, and understanding how the vendor driver processes these values is out of reach. Determining the function or impact of an unknown feature bit now seems unattainable.</p>
<p>However, the kernel driver also requires a mechanism to verify the existing features of the GPU, as it needs to accommodate a wide variety of GPUs. Therefore, there must be some sort of system or method in place to ensure the kernel driver can effectively manage and support the diverse functionalities and capabilities of different GPUs.</p>
<h1 id="a-new-approach-the-hardware-database-dilemma">A New Approach: The Hardware Database Dilemma</h1>
<p>Let&rsquo;s welcome: gc_feature_database.h, or hwdb for short.</p>
<p>Vivante transitioned to using a database that stores entries for limit values and feature bits. This database is accessed by querying with model, revision, product id, eco id and customer id.</p>
<p>There is some speculation why this move was done. My theory posits that they became frustrated with the recurring cycle of introducing feature bits to indicate the implementation of a feature, subsequently discovering problems with said feature, and then having to introduce additional feature bits to signal that the feature now truly operates as intended. It became far more straightforward to deactivate a malfunctioning feature by modifying information in the hardware database (hwdb). After they began utilizing the hwdb within the driver, updates to the feature registers in the hardware ceased.</p>
<p>Here is a concrete example of such a case that can be found in the <a href="https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/etnaviv/etnaviv_screen.c?h=24.0#n1029">etnaviv gallium driver</a>:</p>
<pre tabindex="0"><code>screen-&gt;specs.tex_astc = VIV_FEATURE(screen, chipMinorFeatures4, TEXTURE_ASTC) &amp;&amp;
                            !VIV_FEATURE(screen, chipMinorFeatures6, NO_ASTC);
</code></pre><p>Meanwhile, in the etnaviv world there was a hybrid in the making. We stuck with the detailed <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/drm/etnaviv_drm.h?h=v6.8#n51">feature words</a> and found a smart way to convert from Vivante&rsquo;s hwdb entries to our own <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c?h=v6.8">in-kernel database</a>. There is even a <a href="https://github.com/gizmo98/hwdb-converter">full blown</a> Vivante -&gt; etnaviv hwdb convert.</p>
<p>At that time, I did not fully understand all the consequences this approach would bring - more on that later. So, I dedicated my free time to reverse engineering and tweaking the user space driver, while letting the kernel developers do their thing.</p>
<p>About a year after the <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/gpu/drm/etnaviv?h=v6.8&amp;id=681c19c8bf34df58e6705ba4c1a1676474ef7799">initial hwdb</a> landed in the kernel, I thought it might be a good idea to <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=815e45bbd4d3b00ddb2af017fbdab25110ed13a4">read out the extra id values</a>, and <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=000806631d2a0bc914ffcf2a72aeb6dd59c7fc11">provide them via sysfs</a> to <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1ff79a4a49c239dedd67a12a16a8c3a8b53cf838">the user space</a>. At that time, I already had the idea of moving the hardware database to user space in mind. However, I was preoccupied with other priorities that were higher on my to-do list, and I ended up forgetting about it.</p>
<h1 id="challange-accepted">Challange accepted</h1>
<p><a href="https://blog.tomeuvizoso.net/">Tomeu Vizoso</a> began to work on <a href="https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/frontends/teflon">teflon</a> and a Neural Processing Unit (NPU) driver within Mesa, leveraging a significant amount of the existing codebase and concepts, including the same kernel driver for the GPU. During this process, he encountered a need for some NPU-specific limit values. To address this, he added an <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=49b5ff4c11305dec03e94490071931bf85981f65">in-kernel hwdb entry</a> and <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1dccdba084897443d116508a8ed71e0ac8a031a4">made the limit values accessible to user space</a>.</p>
<p>That&rsquo;s it — the kernel supplies all the values the NPU driver requires. We&rsquo;re finished, aren&rsquo;t we?</p>
<p>It turns out, that there are <a href="https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27513#note_2274394">many more NPU related</a> values that need to be exposed in the same manner, with seemingly no end in sight.</p>
<p>One of the major drawbacks when the hardware database (hwdb) resides in the kernel is the considerable amount of time it takes for hwdb patches to be written, reviewed, and eventually merged into Linus&rsquo;s git tree. This significantly slows down the development of user space drivers. For end users, this means they must either run a bleeding-edge kernel or backport the necessary changes on their own.</p>
<p>For me personally, the in-kernel hardware database should never have been implemented in its current form. If I could go back in time, I would have voiced my concerns.</p>
<p>As a result, moving the hardware database (hwdb) to user space quickly became a top priority on my to-do list, and I began working on it. However, during the testing phase of my proof of concept (PoC), I had to pause my work due to a kernel issue that made it unreliable for user space to trust the ID values provided by the kernel. Once <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b735ee173f84d5d0d0733c53946a83c12d770d05">my fix for this issue</a> began to be incorporated into stable kernel versions, it was time to finalize the user space hwdb.</p>
<p>There is only one little but important detail we have not talked about yet. There are vendor specific versions of gc_feature_database.h based on different versions of the binary blob. For instance, there is one from <a href="https://github.com/nxp-imx/linux-imx/blob/lf-6.6.y/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h">NXP</a>, <a href="https://github.com/STMicroelectronics/gcnano-binaries/blob/gcnano-6.4.13-binaries/gcnano-driver-stm32mp/hal/kernel/inc/gc_feature_database.h">ST</a>, <a href="https://github.com/khadas/android_vendor_amlogic_common_npu/blob/khadas-vim4-r-64bit/hal/kernel/inc/gc_feature_database.h">Amlogic</a> and some more.</p>
<p>Here is a brief look at the differences:</p>
<pre tabindex="0"><code>nxp/gc_feature_database.h (autogenerated at 2023-10-24 16:06:00, 861 struct members, 27 entries)
stm/gc_feature_database.h (autogenerated at 2022-12-29 11:13:00, 833 struct members, 4 entries)
amlogic/gc_feature_database.h (autogenerated at 2021-04-12 17:20:00, 733 struct members, 8 entries)
</code></pre><p>We understand that these header files are generated and adhere to a specific structure. Therefore, all we need to do is write an intelligent Python script capable of merging the struct members into a single consolidated struct. This script will also convert the old struct entries to the new format and generate a header file that we can use.</p>
<p>I&rsquo;m consistently amazed by how swiftly and effortlessly Python can be used for such tasks. Ninety-nine percent of the time, there&rsquo;s a ready-to-use Python module available, complete with examples and some documentation. To address the C header parsing challenge, I opted for <a href="https://github.com/eliben/pycparser">pycparser</a>.</p>
<p>The final outcome is a generated hwdb.h file that looks and feels similar to those generated from the binary blob.</p>
<h1 id="future-proof">Future proof</h1>
<p>This header merging approach offers several advantages:</p>
<ul>
<li>It simplifies the support for another SoC vendor.</li>
<li>There&rsquo;s no need to comprehend the significance of each feature bit.</li>
<li>The source header files are supplied by Versilicon or the SoC vendor, ensuring accuracy.</li>
<li>Updating the hwdb is straightforward — simply replace the files and rebuild Mesa.</li>
<li>It allows for much quicker deployment of new features and hwdb updates since no kernel update is required.</li>
<li>This method accelerates the development of user space drivers.</li>
</ul>
<p>While working on this topic I decided to do a bigger refactoring with the end goal to provide a <code>struct etna_core_info</code> that is located outside of the gallium driver.</p>
<p>This makes the code future proof and moves the filling of <code>struct etna_core_info</code> directly into the lowest layer - libetnaviv_drm (<a href="https://cgit.freedesktop.org/mesa/mesa/tree/src/etnaviv/drm">src/etnaviv/drm</a>).</p>
<p>We have not yet talked about one important detail.</p>
<blockquote>
<p>What happens if there is no entry in the user space hwdb?</p>
</blockquote>
<p>The solution is straightforward: we fallback to the previous method and request all feature words from the kernel driver. However, in an ideal scenario, our user space hardware database should supply all necessary entries. If you find that an entry for your GPU/NPU is missing, please get in touch with me.</p>
<h1 id="what-about-the-in-kernel-hwdb">What about the in-kernel hwdb?</h1>
<p>The existing system, despite its limitations, is set to remain indefinitely, with new entries being added to accommodate new GPUs. Although it will never contain as much information as the user space counterpart, this isn&rsquo;t necessarily a drawback. For the purposes at hand, only a handful of feature bits are required.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Year 2023 in Retrospect</title>
      <link>https://christian-gmeiner.info/2022-12-26-end-of-year/</link>
      <pubDate>Tue, 26 Dec 2023 09:03:20 -0800</pubDate>
      <guid>https://christian-gmeiner.info/2022-12-26-end-of-year/</guid>
      <description>&lt;p&gt;Holidays are here and I have time to look back at 2023. For six months I have been working for &lt;a href=&#34;https://www.igalia.com/&#34;&gt;Igalia&lt;/a&gt; and what should I say?&lt;/p&gt;
&lt;p&gt;I &amp;#x2764;&amp;#xfe0f; it!&lt;/p&gt;
&lt;p&gt;This was the best decision to leave my comfort zone of a normal 9-5 job. I am so proud to work on open source GPU drivers and I am able to spend much of my work time on etnaviv.&lt;/p&gt;
&lt;h2 id=&#34;driver-maintenance&#34;&gt;Driver maintenance&lt;/h2&gt;
&lt;p&gt;Before adding any new feature I thought it would be great idea to improve the current state of etnaviv&amp;rsquo;s gallium driver. Therefor I reworked some general driver &lt;a href=&#34;https://cgit.freedesktop.org/mesa/mesa/commit/?id=ae828a33a74c5b3fc6abee481eac7cb57bf815d0&#34;&gt;code&lt;/a&gt; to be more consistent and to have a more modern feeling, and made it possible to drop some &lt;a href=&#34;https://cgit.freedesktop.org/mesa/mesa/commit/?id=e13bdbbd5bfc1cef00cf504b0567238ae8f45524&#34;&gt;hand-rolled&lt;/a&gt; conversion helpers by switching to already existing solutions (&lt;code&gt;U_FIXED(..)&lt;/code&gt;, &lt;code&gt;S_FIXED(..)&lt;/code&gt;, &lt;code&gt;float_to_ubyte(..)&lt;/code&gt;).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Holidays are here and I have time to look back at 2023. For six months I have been working for <a href="https://www.igalia.com/">Igalia</a> and what should I say?</p>
<p>I &#x2764;&#xfe0f; it!</p>
<p>This was the best decision to leave my comfort zone of a normal 9-5 job. I am so proud to work on open source GPU drivers and I am able to spend much of my work time on etnaviv.</p>
<h2 id="driver-maintenance">Driver maintenance</h2>
<p>Before adding any new feature I thought it would be great idea to improve the current state of etnaviv&rsquo;s gallium driver. Therefor I reworked some general driver <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=ae828a33a74c5b3fc6abee481eac7cb57bf815d0">code</a> to be more consistent and to have a more modern feeling, and made it possible to drop some <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=e13bdbbd5bfc1cef00cf504b0567238ae8f45524">hand-rolled</a> conversion helpers by switching to already existing solutions (<code>U_FIXED(..)</code>, <code>S_FIXED(..)</code>, <code>float_to_ubyte(..)</code>).</p>
<p>I worked through the low hanging fruits of crashes seen in CI runs and <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=add14d6cfb6b2aa666c7dbe2bbe43a8926d62d34">fixed</a> <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=a11501e014c82a51e606df079cc0dec2538fd860">many</a> of <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=9342544ca5c9ec2d7c100fe80f3cb6ac41547231">them</a>.</p>
<p>Feature wise, I also looked at some easy to implement extensions like <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=62e0f6bf328e37f3c4704ca35427c3dde0744977">GL_NV_conditional_render</a> and <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=dadb7244bb3df10b1418146b5a5c1cffa8364973">GL_OES_texture_half_float_linear</a>.</p>
<p>Besides the gallium driver I also worked on <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=fb48d3d1da0ab493fbd22f62dd85a9ab0c0811a0">some</a> <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=f831883af6389097624d0f9d8b067eb59b2c4780">NIR</a> and <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=2c9a59dcfc1fc5674a590f6d157f76ce57bd9cac">isaspec</a> <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=b2e4972339711a9576ec309ecdd4f42eb664c2f9">features</a> that are <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=fa0ff0849c5d96534195d276658aa8211d115076">beneficial</a> for etnaviv.</p>
<h2 id="xdc2023">XDC2023</h2>
<p>A personal highlight was to give a talk about etnaviv at XDC2023 <strong>in person</strong>.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/ZRAltAOUiuM?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>You might wonder what happened since mid October in etnaviv land.</p>
<h2 id="gles3">GLES3</h2>
<p>I worked on some features that are needed to expose GLES3 and it turned out that an easy to maintain, extend and test compiler backend is needed. Sadly etnaviv&rsquo;s current backend compiler does not check any of these boxes. It is so fragile that I only added some needed <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=5a952807487255cb8e3be6bc2eb66041f7f7785b">lowerings</a> to pass some of the <code>dEQP-GLES3.functional.shaders.texture_functions.*</code> tests.</p>
<p>Some more fun work regarding some feature emulation is on the horizon and it&rsquo;s blocked again by the current compiler.</p>
<h2 id="backend-compiler">Backend Compiler</h2>
<p>etnaviv includes an <a href="https://docs.mesa3d.org/isaspec.html">isaspec</a> powered <a href="https://cgit.freedesktop.org/mesa/mesa/commit/?id=64caf906328dad0491a07898cf4b6382f4baab35">disassembler</a> now - a small step towards a new backend compiler. Next on the road to success is the etnaviv backend IR with an assembler.</p>
<p>The new backend compiler is able to run OpenCL kernels with the help of rusticl but I want to land the new backend compiler in smaller chunks that are easier to review.</p>
<h2 id="multiple-render-targets">Multiple Render Targets</h2>
<p>During my XDC presentation I talked about a feature I got working on GC7000L - Multiple Render Targets (MRT). At this point it was more or less a proof-of-concept regarding the gallium drivers. There were some missing bits and register for full support on more GPU models and therefore more reverse engineering work was needed. Also the gallium driver needed lots of work to add support for MRT.</p>
<p>Some weeks later I had MRT working on a wider range of Vivante GPUs that are supporting this feature. This includes GC2000, GC3000 and GC7000 models among others. As etnaviv makes heavy use of GPU features it should work on even more models.</p>
<h2 id="looking-forward-to-2024">Looking forward to 2024</h2>
<p>I am really confident that we will see GLES3 and OpenCL for etnaviv. As driver testing is quite important for my work I will expand my current board farm and will look into the new star in CI world - <a href="https://gfx-ci.pages.freedesktop.org/ci-tron/">ci-tron</a>.</p>
<p>With that, have a happy holiday season and we&rsquo;ll be back with more improvements in 2024!</p>
]]></content:encoded>
    </item>
    <item>
      <title>mesamatrix</title>
      <link>https://christian-gmeiner.info/2019-06-16-mesamatrix/</link>
      <pubDate>Sun, 16 Jun 2019 15:40:01 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2019-06-16-mesamatrix/</guid>
      <description>&lt;p&gt;You might be familiar with &lt;a href=&#34;https://mesamatrix.net/&#34;&gt;mesamatrix&lt;/a&gt; - a nice site to track the state of all GPU drivers provided by Mesa. Ohh.. did I say all? Let&amp;rsquo;s have a closer look:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This page is a graphical representation of the text file docs/features.txt from the Mesa repository.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So wouldn&amp;rsquo;t it be sick to get etnaviv mentioned in docs/features.txt and onto the matrix?&lt;/p&gt;
&lt;p&gt;First mesamatrix needs to know/support etnaviv. This seems to be quite simple as there is already a pull request to add a bunch of embedded GPU drivers: &lt;a href=&#34;https://github.com/MightyCreak/mesamatrix/pull/136&#34;&gt;Add VC4,VC5 and Vivante GPUs&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>You might be familiar with <a href="https://mesamatrix.net/">mesamatrix</a> - a nice site to track the state of all GPU drivers provided by Mesa. Ohh.. did I say all? Let&rsquo;s have a closer look:</p>
<blockquote>
<p>This page is a graphical representation of the text file docs/features.txt from the Mesa repository.</p>
</blockquote>
<p>So wouldn&rsquo;t it be sick to get etnaviv mentioned in docs/features.txt and onto the matrix?</p>
<p>First mesamatrix needs to know/support etnaviv. This seems to be quite simple as there is already a pull request to add a bunch of embedded GPU drivers: <a href="https://github.com/MightyCreak/mesamatrix/pull/136">Add VC4,VC5 and Vivante GPUs</a></p>
<p><img alt="Comment found at mesamatrix pull request" loading="lazy" src="/img/mesamatrix_pull_20190616.png"></p>
<p>Second we need is to add support for an easy to support extension. After skimming through the list I settled with <a href="https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_seamless_cubemap_per_texture.txt">ARB_seamless_cubemap_per_texture</a></p>
<p>To be fair I know that there are some UNK bits in the sampler registers and I hope one of them has something to do with seamless cubemaps. I went with a quick try-and-error approach to find the UNK bit which enables seamless cubemaps. And after 20 minutes of hacking the spec@amd_seamless_cubemap_per_texture@amd_seamless_cubemap_per_texture piglit works \o/.</p>
<p>The end result can be found in <a href="https://gitlab.freedesktop.org/mesa/mesa/merge_requests/997">in this merge request</a>. I hope to merge the changes soon and see something new in mesamatrix.</p>
]]></content:encoded>
    </item>
    <item>
      <title>etnaviv officially landed</title>
      <link>https://christian-gmeiner.info/2017-01-12-etnaviv-officially-landed-in-mesa/</link>
      <pubDate>Thu, 12 Jan 2017 19:48:36 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2017-01-12-etnaviv-officially-landed-in-mesa/</guid>
      <description>&lt;p&gt;After years of hard work the etnaviv team reached an other very important milestone. The gallium driver and the renderonly library got pushed into mesa&amp;rsquo;s git repository and will be released with mesa 17.0 - yeah!&lt;/p&gt;
&lt;p&gt;This does not mean we are done with development at all. There are many interesting topics to work on and some of them like better support for newer IP cores or a reworked GLSL compiler should see the light of day during the next months.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>After years of hard work the etnaviv team reached an other very important milestone. The gallium driver and the renderonly library got pushed into mesa&rsquo;s git repository and will be released with mesa 17.0 - yeah!</p>
<p>This does not mean we are done with development at all. There are many interesting topics to work on and some of them like better support for newer IP cores or a reworked GLSL compiler should see the light of day during the next months.</p>
<p>I think 2017 will be a quite interesting one for etnaviv and open source GPU drivers in general.</p>
<p>At this point I want to thank a lot of people who helped out in different areas. The whole <a href="http://www.mesa3d.org">mesa community</a> (esp. Rob, Ilia and Emil), <a href="https://www.solid-run.com/">SolidRun</a> for provided hardware, <a href="http://www.pengutronix.com">Pengutronix</a> - the &lsquo;imx6-company&rsquo; - for doing a wonderful job in the kernel space and all the other guys I meet in real life or via irc/mail.</p>
]]></content:encoded>
    </item>
    <item>
      <title>etnaviv: kmscube</title>
      <link>https://christian-gmeiner.info/2015-09-25-etnaviv-kmscube/</link>
      <pubDate>Fri, 25 Sep 2015 21:39:10 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2015-09-25-etnaviv-kmscube/</guid>
      <description>&lt;p&gt;Last Friday I got kmscube successfully running with mesa and the new etnaviv DRM kernel driver. At this time I got it not really pixel perfect and I spend some nights to get it fixed. It turns out that I need a small mesa hack to get the rendering correct.&lt;/p&gt;
&lt;iframe allowfullscreen=&#34;&#34; frameborder=&#34;0&#34; height=&#34;473&#34; src=&#34;https://www.youtube.com/embed/vjIBow3M-C4?feature=oembed&#34; width=&#34;840&#34;&gt;&lt;/iframe&gt;
&lt;p&gt;You may ask why did it so long to get it working? Let me explain it to you.&lt;/p&gt;
&lt;p&gt;The Vivnate GPU is a so called render-only GPU which does not have any kind of scanout logic in it. It can only render to physical memory and this only in a tiled memory layout. So we need to use the resolve engine found on the GPU to de-tile the rendered image and blit it to the dumb buffer. Currently mesa has  no software support for this kind of hardware, but I think that could change soon.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Last Friday I got kmscube successfully running with mesa and the new etnaviv DRM kernel driver. At this time I got it not really pixel perfect and I spend some nights to get it fixed. It turns out that I need a small mesa hack to get the rendering correct.</p>
<iframe allowfullscreen="" frameborder="0" height="473" src="https://www.youtube.com/embed/vjIBow3M-C4?feature=oembed" width="840"></iframe>
<p>You may ask why did it so long to get it working? Let me explain it to you.</p>
<p>The Vivnate GPU is a so called render-only GPU which does not have any kind of scanout logic in it. It can only render to physical memory and this only in a tiled memory layout. So we need to use the resolve engine found on the GPU to de-tile the rendered image and blit it to the dumb buffer. Currently mesa has  no software support for this kind of hardware, but I think that could change soon.</p>
<p>I think that this is a huge step into the right direction. All the needed sources can be found on <a href="https://github.com/austriancoder">my github account</a>. At the moment I am cleaning up the code and shortly I will send out RFC patch series for <strike>libdrm and</strike> mesa. Currently some hacks are needed to get it up an running so there is still a lot left to do.</p>
<p><strike>Yes I think libdrm is needed and should not be part of the gallium driver. I even think xf86-video-armada could be using libdrm-etnaviv sooner or later. This one of the topics on my huge TODO list.</strike></p>
<p>Russell does not want to maintain a 3rd GPU backend and with that fact I think I will merge the etnaviv libdrm part directly into the driver. Let’s see how the patch series gets accepted.</p>
<p>I think this the perfect time to say “thank you” to some guys. Wladimir thanks for the wonderful code basis you provided for the whole etnaviv project. Rob, thanks for your patience with me – at this point in time I was a complete newbie in the mesa source code and the whole GPU world. Thanks NVIDIA for their wonderful render-only patch. Emil thanks for helping me out with ideas to get render-only into a working state. Also quite important for spare-time open source development is a hardware sponsor. In may case I want to thank <a href="http://solid-run.com/">SolidRun</a> for sending me two devices for etnaviv development purposes.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vivante meets devicetree</title>
      <link>https://christian-gmeiner.info/2014-05-24-vivante-meets-devicetree/</link>
      <pubDate>Sat, 24 May 2014 23:41:14 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2014-05-24-vivante-meets-devicetree/</guid>
      <description>&lt;p&gt;It took me some time to rework the device tree bindings but it looks like it starts to work!&lt;/p&gt;
&lt;div class=&#34;oembed-gist&#34;&gt;&lt;script src=&#34;https://gist.github.com/austriancoder/6196fa33011a120a01dd54dbd077a60d.js&#34;&gt;&lt;/script&gt;&lt;noscript&gt;View the code on [Gist](https://gist.github.com/austriancoder/6196fa33011a120a01dd54dbd077a60d).&lt;/noscript&gt;&lt;/div&gt;Gets loaded into :
&lt;p&gt;[ 3.358155] vivante: module is from the staging directory, the quality is unknown, you have been warned.
[ 3.373087] imx-sgtl5000 sound.15: sgtl5000 2028000.ssi mapping ok
[ 3.379150] [drm] add child gpu2d
[ 3.379154] [drm] add child gpu3d
[ 3.380395] vivante-gpu 134000.gpu2d: pre gpu[idx]: 0x00000000
[ 3.380401] vivante-gpu 134000.gpu2d: adding core @idx 1
[ 3.380408] vivante-gpu 134000.gpu2d: post gpu[idx]: 0xecb56c10
[ 3.380460] vivante gpu-subsystem.11: bound 134000.gpu2d (ops gpu_ops [vivante])
[ 3.380467] vivante-gpu 130000.gpu3d: pre gpu[idx]: 0x00000000
[ 3.380473] vivante-gpu 130000.gpu3d: adding core @idx 0
[ 3.380479] vivante-gpu 130000.gpu3d: post gpu[idx]: 0xecb57210
[ 3.380502] vivante gpu-subsystem.11: bound 130000.gpu3d (ops gpu_ops [vivante])
[ 3.380533] IO:R f0200018 14010000
[ 3.380537] IO:R f0200020 00002000
[ 3.380540] IO:R f0200024 00005108
[ 3.380546] vivante gpu-subsystem.11: model: 2000
[ 3.380551] vivante gpu-subsystem.11: revision: 5108
[ 3.380554] IO:R f020001c e0296cad
[ 3.380558] IO:R f0200034 c9799eff
[ 3.380561] IO:R f0200074 2efbf2d9
[ 3.380564] IO:R f0200084 00000000
[ 3.380567] IO:R f0200088 00000000
[ 3.380572] vivante gpu-subsystem.11: minor_features: c9799eff
[ 3.380578] vivante gpu-subsystem.11: minor_features1: 2efbf2d9
[ 3.380583] vivante gpu-subsystem.11: minor_features2: 0
[ 3.380588] vivante gpu-subsystem.11: minor_features3: 0
[ 3.380592] IO:R f0200000 00070100
[ 3.408629] IO:R f0200004 7fffffff
[ 3.408632] IO:R f0200000 00070100
[ 3.412940] vivante gpu-subsystem.11: 130000.gpu3d: using IOMMU
[ 3.413080] IO:R f01f8018 14010000
[ 3.413083] IO:R f01f8020 00000320
[ 3.413087] IO:R f01f8024 00005007
[ 3.413093] vivante gpu-subsystem.11: model: 320
[ 3.413098] vivante gpu-subsystem.11: revision: 5007
[ 3.413101] IO:R f01f801c e02c7eca
[ 3.413105] IO:R f01f8034 c1399eff
[ 3.413108] IO:R f01f8074 020fb2db
[ 3.413111] IO:R f01f8084 00000000
[ 3.413114] IO:R f01f8088 00000000
[ 3.413120] vivante gpu-subsystem.11: minor_features: c1399eff
[ 3.413126] vivante gpu-subsystem.11: minor_features1: 20fb2db
[ 3.413131] vivante gpu-subsystem.11: minor_features2: 0
[ 3.413136] vivante gpu-subsystem.11: minor_features3: 0
[ 3.413139] IO:R f01f8000 00070100
[ 3.438615] IO:R f01f8004 7fffffff
[ 3.438619] IO:R f01f8000 00070100
[ 3.442583] vivante gpu-subsystem.11: 134000.gpu2d: using IOMMU
[ 3.442681] [drm] Initialized vivante 1.0.0 20130625 on minor 1&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>It took me some time to rework the device tree bindings but it looks like it starts to work!</p>
<div class="oembed-gist"><script src="https://gist.github.com/austriancoder/6196fa33011a120a01dd54dbd077a60d.js"></script><noscript>View the code on [Gist](https://gist.github.com/austriancoder/6196fa33011a120a01dd54dbd077a60d).</noscript></div>Gets loaded into :
<p>[ 3.358155] vivante: module is from the staging directory, the quality is unknown, you have been warned.
[ 3.373087] imx-sgtl5000 sound.15: sgtl5000 2028000.ssi mapping ok
[ 3.379150] [drm] add child gpu2d
[ 3.379154] [drm] add child gpu3d
[ 3.380395] vivante-gpu 134000.gpu2d: pre gpu[idx]: 0x00000000
[ 3.380401] vivante-gpu 134000.gpu2d: adding core @idx 1
[ 3.380408] vivante-gpu 134000.gpu2d: post gpu[idx]: 0xecb56c10
[ 3.380460] vivante gpu-subsystem.11: bound 134000.gpu2d (ops gpu_ops [vivante])
[ 3.380467] vivante-gpu 130000.gpu3d: pre gpu[idx]: 0x00000000
[ 3.380473] vivante-gpu 130000.gpu3d: adding core @idx 0
[ 3.380479] vivante-gpu 130000.gpu3d: post gpu[idx]: 0xecb57210
[ 3.380502] vivante gpu-subsystem.11: bound 130000.gpu3d (ops gpu_ops [vivante])
[ 3.380533] IO:R f0200018 14010000
[ 3.380537] IO:R f0200020 00002000
[ 3.380540] IO:R f0200024 00005108
[ 3.380546] vivante gpu-subsystem.11: model: 2000
[ 3.380551] vivante gpu-subsystem.11: revision: 5108
[ 3.380554] IO:R f020001c e0296cad
[ 3.380558] IO:R f0200034 c9799eff
[ 3.380561] IO:R f0200074 2efbf2d9
[ 3.380564] IO:R f0200084 00000000
[ 3.380567] IO:R f0200088 00000000
[ 3.380572] vivante gpu-subsystem.11: minor_features: c9799eff
[ 3.380578] vivante gpu-subsystem.11: minor_features1: 2efbf2d9
[ 3.380583] vivante gpu-subsystem.11: minor_features2: 0
[ 3.380588] vivante gpu-subsystem.11: minor_features3: 0
[ 3.380592] IO:R f0200000 00070100
[ 3.408629] IO:R f0200004 7fffffff
[ 3.408632] IO:R f0200000 00070100
[ 3.412940] vivante gpu-subsystem.11: 130000.gpu3d: using IOMMU
[ 3.413080] IO:R f01f8018 14010000
[ 3.413083] IO:R f01f8020 00000320
[ 3.413087] IO:R f01f8024 00005007
[ 3.413093] vivante gpu-subsystem.11: model: 320
[ 3.413098] vivante gpu-subsystem.11: revision: 5007
[ 3.413101] IO:R f01f801c e02c7eca
[ 3.413105] IO:R f01f8034 c1399eff
[ 3.413108] IO:R f01f8074 020fb2db
[ 3.413111] IO:R f01f8084 00000000
[ 3.413114] IO:R f01f8088 00000000
[ 3.413120] vivante gpu-subsystem.11: minor_features: c1399eff
[ 3.413126] vivante gpu-subsystem.11: minor_features1: 20fb2db
[ 3.413131] vivante gpu-subsystem.11: minor_features2: 0
[ 3.413136] vivante gpu-subsystem.11: minor_features3: 0
[ 3.413139] IO:R f01f8000 00070100
[ 3.438615] IO:R f01f8004 7fffffff
[ 3.438619] IO:R f01f8000 00070100
[ 3.442583] vivante gpu-subsystem.11: 134000.gpu2d: using IOMMU
[ 3.442681] [drm] Initialized vivante 1.0.0 20130625 on minor 1</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vivante MMU v1</title>
      <link>https://christian-gmeiner.info/2014-05-03-vivante-mmu-v1/</link>
      <pubDate>Sat, 03 May 2014 20:25:35 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2014-05-03-vivante-mmu-v1/</guid>
      <description>&lt;p&gt;I did spend quite some time the last days to figure out how the MMU v1 could work and what all the code in the v4 Kernel sources does. It took quite some time and a little hint from Russel to finally understand it. So lets start with the technical details.&lt;/p&gt;
&lt;p&gt;The MMU uses a page table with a maximum size of 256KB. Where each Page Table Entry (PTE) is 4 byte long. The used page size is 4K and can not be changed via some registers etc.
Lets have a look at the bit layout of a PTE.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I did spend quite some time the last days to figure out how the MMU v1 could work and what all the code in the v4 Kernel sources does. It took quite some time and a little hint from Russel to finally understand it. So lets start with the technical details.</p>
<p>The MMU uses a page table with a maximum size of 256KB. Where each Page Table Entry (PTE) is 4 byte long. The used page size is 4K and can not be changed via some registers etc.
Lets have a look at the bit layout of a PTE.</p>
<p><a href="/wp-content/uploads/2014/05/vivante_mmuv1.png"><img alt="vivante_mmuv1" loading="lazy" src="/wp-content/uploads/2014/05/vivante_mmuv1-1024x86.png"></a>
What does all that code in the v4 driver? In the end it turned out to be a ‘simple’ memory manager. All the code is needed to keep track of which pages are mapped into the GPU address area. Index 0 of the big page table array maps directly to GPU address 0x80000000 and index 1 maps directly to 0x80001000. We can quite easily map Linux kernel pages into the address range of the GPU.</p>
<p>The solution I am working on will use drm_mm as memory manager and the iommu framework to keep the page table in sync.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The next steps for etnaviv</title>
      <link>https://christian-gmeiner.info/2014-02-22-the-next-steps-for-etnaviv/</link>
      <pubDate>Sat, 22 Feb 2014 17:54:17 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2014-02-22-the-next-steps-for-etnaviv/</guid>
      <description>&lt;p&gt;I did spend some time to find the cause for the rendering issues during running some egls2 demos. The fix is a simple one-liner and I would say that GC8xx and GC2000 are ‘equal’ now. That means general work on etnaviv can start now. Currently I am looking in different problem zones and where to start.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update mesa fork&lt;/li&gt;
&lt;li&gt;Start working on an improved compiler&lt;/li&gt;
&lt;li&gt;Start working on an kernel interface&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think that Rob will start soon on the kernel interface and the mesa update should be doable during some hours. So I think the next big and important step is to improve the compiler. What should I say… I have basic compiler understanding, did wrote a compiler and VM during my study… thats it. I have never written a single line of glsl and I do not completely understand the Vivante GPU. So a perfect starting point for doing some hacking 🙂 The success rate will be quite low and I hope to not lose my motivation too soon.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I did spend some time to find the cause for the rendering issues during running some egls2 demos. The fix is a simple one-liner and I would say that GC8xx and GC2000 are ‘equal’ now. That means general work on etnaviv can start now. Currently I am looking in different problem zones and where to start.</p>
<ol>
<li>Update mesa fork</li>
<li>Start working on an improved compiler</li>
<li>Start working on an kernel interface</li>
</ol>
<p>I think that Rob will start soon on the kernel interface and the mesa update should be doable during some hours. So I think the next big and important step is to improve the compiler. What should I say… I have basic compiler understanding, did wrote a compiler and VM during my study… thats it. I have never written a single line of glsl and I do not completely understand the Vivante GPU. So a perfect starting point for doing some hacking 🙂 The success rate will be quite low and I hope to not lose my motivation too soon.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Mesa meets GC2000</title>
      <link>https://christian-gmeiner.info/2014-02-15-mesa-meets-gc2000/</link>
      <pubDate>Sat, 15 Feb 2014 20:18:25 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2014-02-15-mesa-meets-gc2000/</guid>
      <description>&lt;p&gt;Here is the first result of running &lt;a href=&#34;https://github.com/laanwj/mesatest_gles&#34;&gt;mesatest_gles &lt;/a&gt;on &lt;a href=&#34;https://github.com/austriancoder/mesa&#34;&gt;mesa&amp;amp;etna&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Following tests are showing good visual results compared to swrast:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hello_Triangle/CH02_HelloTriangle&lt;/li&gt;
&lt;li&gt;Simple_VertexShader/CH08_SimpleVertexShader&lt;/li&gt;
&lt;li&gt;CubeVBO/cube_vbo&lt;/li&gt;
&lt;li&gt;ParticleSystem/CH13_ParticleSystem&lt;/li&gt;
&lt;li&gt;Viewports/viewports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All other are visual corrupted or segfault. So there is still some work done to get all demos
up and running.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Here is the first result of running <a href="https://github.com/laanwj/mesatest_gles">mesatest_gles </a>on <a href="https://github.com/austriancoder/mesa">mesa&amp;etna</a>:</p>
<p>Following tests are showing good visual results compared to swrast:</p>
<ul>
<li>Hello_Triangle/CH02_HelloTriangle</li>
<li>Simple_VertexShader/CH08_SimpleVertexShader</li>
<li>CubeVBO/cube_vbo</li>
<li>ParticleSystem/CH13_ParticleSystem</li>
<li>Viewports/viewports</li>
</ul>
<p>All other are visual corrupted or segfault. So there is still some work done to get all demos
up and running.</p>
]]></content:encoded>
    </item>
    <item>
      <title>GC2000 support for etnaviv</title>
      <link>https://christian-gmeiner.info/2014-02-09-gc2000-support-for-etnaviv/</link>
      <pubDate>Sun, 09 Feb 2014 17:22:56 +0000</pubDate>
      <guid>https://christian-gmeiner.info/2014-02-09-gc2000-support-for-etnaviv/</guid>
      <description>&lt;p&gt;Today I hit an important milestone for etnaviv – an open source user-space driver for the Vivante GCxxx series of embedded GPUs.
I finally got GC2000 support to a level that it seems to work. It took me some months to get there.
At the beginning it sounds easy to rebuild a ‘driver’ if you get readable command buffer dumps. I did start with working on a simple replay program to render a cube in the same was as the binary blob does it.
But what should I say… it is quite boring to do everything by hand and not taking advantage of libetnaviv
and the ‘driver’ at all. So I decided to go the hard way and try to fix/add all missing bits until it renders something.
The good thing is that I have now some knowledge about the structure of libetnaviv, the
dirver and mesa in general. It helps a lot if you know why stuff is done that way.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I hit an important milestone for etnaviv – an open source user-space driver for the Vivante GCxxx series of embedded GPUs.
I finally got GC2000 support to a level that it seems to work. It took me some months to get there.
At the beginning it sounds easy to rebuild a ‘driver’ if you get readable command buffer dumps. I did start with working on a simple replay program to render a cube in the same was as the binary blob does it.
But what should I say… it is quite boring to do everything by hand and not taking advantage of libetnaviv
and the ‘driver’ at all. So I decided to go the hard way and try to fix/add all missing bits until it renders something.
The good thing is that I have now some knowledge about the structure of libetnaviv, the
dirver and mesa in general. It helps a lot if you know why stuff is done that way.</p>
<p>Also this is my first reverse engineering project I contributed to and even I have never done any graphics related stuff – okay I did
some OpenGL stuff during my studies.</p>
<p>I try to find some more time to help to create a fully open source graphics stack for Vivante GPUs.</p>
<p>If have not seen it yet: Here is a short video showing the current state of etnaviv on a iMX6q (Sabre Lite).
<a href="https://plus.google.com/102045773664179486664/posts/aiBDNmMQRTU">Video in Google+ post</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
