<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: org dotnet</title>
    <description>The latest articles on DEV Community by org dotnet (@org_dotnet_2dc36e3aac2ce1).</description>
    <link>https://dev.to/org_dotnet_2dc36e3aac2ce1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4245318%2F795a5bd7-b6c8-41f5-a822-dbf66202bac2.webp</url>
      <title>DEV Community: org dotnet</title>
      <link>https://dev.to/org_dotnet_2dc36e3aac2ce1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/org_dotnet_2dc36e3aac2ce1"/>
    <language>en</language>
    <item>
      <title>Can C# Replace Native Skia? Building SimdSkia for Avalonia and NativeAOT</title>
      <dc:creator>org dotnet</dc:creator>
      <pubDate>Sun, 15 Nov 2026 03:28:03 +0000</pubDate>
      <link>https://dev.to/org_dotnet_2dc36e3aac2ce1/can-c-replace-native-skia-building-simdskia-for-avalonia-and-nativeaot-3k12</link>
      <guid>https://dev.to/org_dotnet_2dc36e3aac2ce1/can-c-replace-native-skia-building-simdskia-for-avalonia-and-nativeaot-3k12</guid>
      <description>&lt;p&gt;I’m building &lt;strong&gt;SimdSkia&lt;/strong&gt;, an open-source 2D rendering engine for .NET, with a C# CPU rasterizer, SIMD acceleration, SkiaSharp-style APIs, and an Avalonia rendering backend.&lt;/p&gt;

&lt;p&gt;The motivation is straightforward. I wanted to explore how much of a desktop graphics stack could move into managed C#, while reducing the native Skia payload and preserving familiar drawing APIs.&lt;/p&gt;

&lt;p&gt;The project targets .NET 10 and uses the MIT license. &lt;a href="https://github.com/donet-org-cn/SimdSkia" rel="noopener noreferrer"&gt;Source code and examples&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it provides
&lt;/h2&gt;

&lt;p&gt;The current implementation includes paths, clipping, gradients, image sampling, blending, static TrueType fonts, basic English and Chinese text layout, and image codecs through Sdcb.SimdCodecs.&lt;/p&gt;

&lt;p&gt;For Avalonia desktop applications, backend selection currently works as follows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Default rendering&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;Direct2D, with CPU fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux under X11/XWayland&lt;/td&gt;
&lt;td&gt;Hardware Vulkan, with CPU fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;CPU rendering through Avalonia’s native window host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;td&gt;CPU/SIMD rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CPU drawing implementation runs independently of Google Skia. GPU backends call system graphics APIs, window integration uses platform hosts, and image compression uses .NET’s compression facilities. &lt;a href="https://github.com/donet-org-cn/SimdSkia/blob/main/docs/DEPENDENCIES.md" rel="noopener noreferrer"&gt;Architecture and dependencies&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing your first image
&lt;/h2&gt;

&lt;p&gt;Install the standalone drawing package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package SimdSkia --version 0.1.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compatibility layer exposes the &lt;code&gt;SkiaSharp&lt;/code&gt; namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nc"&gt;SkiaSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SKBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SKCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SKColors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;White&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SKPaint&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SKColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;IsAntialias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DrawRoundRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;SKRect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;272&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;132&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;png&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SKEncodedImageFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Png&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PNG encoding failed."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hello-simdskia.png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;png&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SaveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using it with Avalonia
&lt;/h2&gt;

&lt;p&gt;Install the desktop integration package in your startup project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package SimdSkia.Avalonia.Desktop --version 0.1.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the migration guide to adjust package references, then configure the application builder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nc"&gt;SimdSkia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Avalonia&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;AppBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Configure&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UseSimdSkiaDesktop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StartWithClassicDesktopLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Desktop integration has been tested against Avalonia versions &lt;strong&gt;12.1.0 through 12.1.5&lt;/strong&gt;. Applications with third-party controls should check their dependencies on Skia-specific features. &lt;a href="https://github.com/donet-org-cn/SimdSkia/blob/main/README.en.md" rel="noopener noreferrer"&gt;Full migration guide&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened to NativeAOT deployment size?
&lt;/h2&gt;

&lt;p&gt;For the same Windows x64 example and bundled font, the measured deployment sizes were as follows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measurement&lt;/th&gt;
&lt;th&gt;Original renderer&lt;/th&gt;
&lt;th&gt;SimdSkia&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Executable&lt;/td&gt;
&lt;td&gt;18.70 MiB&lt;/td&gt;
&lt;td&gt;24.47 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native DLLs&lt;/td&gt;
&lt;td&gt;12.82 MiB&lt;/td&gt;
&lt;td&gt;0.00 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required runtime files, including font&lt;/td&gt;
&lt;td&gt;41.16 MiB&lt;/td&gt;
&lt;td&gt;30.66 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compressed ZIP&lt;/td&gt;
&lt;td&gt;16.35 MiB&lt;/td&gt;
&lt;td&gt;13.03 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The SimdSkia executable grew, while total deployment size fell by approximately &lt;strong&gt;25.5%&lt;/strong&gt; in this example. These measurements apply to this specific application and publishing configuration. &lt;a href="https://github.com/donet-org-cn/SimdSkia/blob/main/docs/PERFORMANCE-2026-11-10-ROUND2.md" rel="noopener noreferrer"&gt;Size measurements and methodology&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance is workload-dependent
&lt;/h2&gt;

&lt;p&gt;The November 10 source revision was tested on Windows x64 with an Intel i7-8700K, GTX 1050 Ti, and .NET 10.0.14. The comparison baseline used SkiaSharp 3.119.4.&lt;/p&gt;

&lt;p&gt;Several CPU workloads still need substantial optimization.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CPU workload&lt;/th&gt;
&lt;th&gt;SkiaSharp&lt;/th&gt;
&lt;th&gt;SimdSkia&lt;/th&gt;
&lt;th&gt;SimdSkia / original&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mesh&lt;/td&gt;
&lt;td&gt;0.330 ms&lt;/td&gt;
&lt;td&gt;1.409 ms&lt;/td&gt;
&lt;td&gt;4.26×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patch&lt;/td&gt;
&lt;td&gt;0.784 ms&lt;/td&gt;
&lt;td&gt;2.029 ms&lt;/td&gt;
&lt;td&gt;2.59×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atlas&lt;/td&gt;
&lt;td&gt;0.040 ms&lt;/td&gt;
&lt;td&gt;0.243 ms&lt;/td&gt;
&lt;td&gt;6.13×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime effect&lt;/td&gt;
&lt;td&gt;0.280 ms&lt;/td&gt;
&lt;td&gt;0.736 ms&lt;/td&gt;
&lt;td&gt;2.63×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perlin noise&lt;/td&gt;
&lt;td&gt;13.362 ms&lt;/td&gt;
&lt;td&gt;4.585 ms&lt;/td&gt;
&lt;td&gt;0.34×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All five workloads passed their existing original-renderer image-comparison thresholds. The runtime-effect optimization reduced SimdSkia’s own previous time from &lt;strong&gt;5.435 ms to 0.736 ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpgt1al54qleqq59kzf8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpgt1al54qleqq59kzf8j.png" alt="CPU rendering comparison" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The report also covers actual NativeAOT windows, CPU time, allocations, working set, private memory, and Vulkan/Direct2D completion times including synchronization and readback. Full-page CPU and GPU comparisons still fail the current strict pixel-error thresholds, so their timing results remain diagnostic. The measured source changes extend beyond the published 0.1.4 package. &lt;a href="https://github.com/donet-org-cn/SimdSkia/blob/main/docs/PERFORMANCE-2026-11-10-ROUND2.md" rel="noopener noreferrer"&gt;Full benchmark report&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory improvements have specific conditions
&lt;/h2&gt;

&lt;p&gt;In one fixed-font NativeAOT controls example, private memory fell from &lt;strong&gt;53.5 MiB to 37.9 MiB&lt;/strong&gt; after eliminating duplicate font-loading buffers. The original renderer used &lt;strong&gt;32.4 MiB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A separate system-font test showed &lt;strong&gt;49.8 MiB&lt;/strong&gt; for SimdSkia versus &lt;strong&gt;41.4 MiB&lt;/strong&gt; for the original default renderer. The benefit depends on the application’s font-loading path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw6la6p4jk7wzmzlscpnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw6la6p4jk7wzmzlscpnn.png" alt="NativeAOT private memory comparison" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility and remaining work
&lt;/h2&gt;

&lt;p&gt;The public-signature audit matched &lt;strong&gt;3,230 of 3,235 entries&lt;/strong&gt; against SkiaSharp 3.119.4. Migration requires recompiling code against the compatibility layer and validating application behavior.&lt;/p&gt;

&lt;p&gt;Remaining work includes native Skia interoperation gaps, text and curve rendering differences, some JPEG comparisons, and slower mesh, atlas, and runtime-effect workloads. Complete pages also require further visual validation. &lt;a href="https://github.com/donet-org-cn/SimdSkia/blob/main/docs/COMPATIBILITY.md" rel="noopener noreferrer"&gt;Compatibility report&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d especially welcome small reproductions from developers using Avalonia, NativeAOT, or SkiaSharp. Real application workloads will help identify which compatibility and performance improvements matter most.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/donet-org-cn/SimdSkia" rel="noopener noreferrer"&gt;GitHub repository, examples, and issue tracker&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>opensource</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
