Annonce de ComputeSharp 2.0 — exécutez facilement C# sur le GPU via DirectX 12 et D2D1 !

Nov 30 2022
Après plus de 2 ans de travail, je suis heureux de vous annoncer que ComputeSharp 2.0 est enfin disponible ! Il s'agit d'une réécriture complète de la bibliothèque, avec prise en charge à la fois des fichiers .

Après plus de 2 ans de travail, je suis heureux de vous annoncer que ComputeSharp 2.0 est enfin disponible ! Il s'agit d'une réécriture complète de la bibliothèque, avec prise en charge de .NET Standard 2.0 et .NET 6, de nouveaux générateurs de source pour remplacer entièrement la génération de code d'exécution, de nombreuses nouvelles API, une toute nouvelle prise en charge des shaders de pixels D2D1 également, des contrôles XAML pour UWP et WinUI 3, et bien plus encore !

Beaucoup d'efforts ont été consacrés à cette version, et la portée de l'ensemble du projet a tellement augmenté au fil du temps, bien plus que ce que j'avais initialement prévu. Dans cet article de blog, je souhaite présenter la bibliothèque à ceux qui ne la connaissent pas, mettre en évidence certaines des nouvelles fonctionnalités et montrer quelques exemples de ce qui peut être fait avec.

Pour ceux qui préfèrent un formulaire vidéo, voici un lien vers mon discours sur ComputeSharp à .NET Conf 2022 , et pour ceux qui veulent juste sauter directement dans le code, voici également un lien vers le référentiel GitHub . Passons à ComputeSharp 2.0 !

Commençons par un pitch élévateur pour la bibliothèque : ComputeSharp est une bibliothèque .NET permettant d'exécuter du code C# en parallèle sur le GPU via DX12, D2D1 et des shaders de calcul HLSL générés dynamiquement, dans le but de rendre l'informatique GPU facile à utiliser pour tous. Développeurs NET ! Il vous permet d'écrire des shaders (c'est-à-dire du code pouvant s'exécuter sur le GPU) à l'aide de C #, puis il fait tout le gros du travail pour transformer ce code et l'envoyer sur le GPU utilisé sur votre machine. Cela peut être utilisé pour accélérer matériellement toutes sortes de charges de travail - traitement d'image, calculs parallèles, génération d'animations fantaisistes, etc. Et tout cela sans que vous ayez besoin de plonger dans les API spécifiques à la plate-forme nécessaires pour faire fonctionner tout cela, ni d'apprendre à écrire réellement HLSL, qui est le langage de programmation que DirectX utilise pour les shaders.

Pour un exemple pratique, voici l'exemple d'application ComputeSharp en action :

Ici, vous pouvez voir l'un des contrôles XAML proposés par ComputeSharp pour UWP et WinUI 3 utilisé pour rendre plusieurs shaders de calcul animés, dans ce cas exécuté dans une application WinUI 3. L'intégralité du code source est disponible sur GitHub , et tous les shaders que vous voyez ont été portés à partir de shaders GLSL de shadertoy vers C# uniquement, et sont tous alimentés par ComputeSharp et exécutés à l'aide de shaders de calcul DirectX 12.

Et voici un autre exemple de ComputeSharp en action :

Paint.NET 5.0 présentant un effet de flou bokeh alimenté par ComputeSharp

J'ai également passé les derniers mois à ajouter la prise en charge de Direct2D à ComputeSharp, qui est désormais un composant fondamental de la prochaine version de Paint.NET 5.0 . ComputeSharp.D2D1 (la version de la bibliothèque pour les shaders de pixels D2D1) est utilisée pour implémenter des dizaines d'effets d'image dans l'application, qui sont entièrement écrits en C# et accélérés par GPU grâce à la puissance de D2D. Cela a permis à Rick Brewster , le développeur de Paint.NET, d'augmenter considérablement le nombre d'effets qu'il pouvait exécuter sur le GPU, tout en réduisant considérablement la complexité de l'application en ce qui concerne les effets GPU D2D, car il n'y avait plus la nécessité d'écrire manuellement des effets dans HLSL et de les compiler avec une étape de construction personnalisée - ComputeSharp fait tout ce travail en coulisse !

Fait amusant - le flou bokeh présenté dans la capture d'écran Paint.NET ci-dessus est le port de Rick de mon échantillon de flou bokeh ComputeSharp.D2D1 , qui est lui-même un port que j'ai fait de mon échantillon de flou bokeh ComputeSharp , qui est un port de la version C# que j'ai écrite pour ImageSharp , qui est un portage de la version Python que le professeur Mike Pound a écrite pour sa vidéo Computerphile sur les effets de flou bokeh . Allez vérifier !

Et cela est également disponible pour les auteurs de plugins, ce qui signifie que n'importe qui peut désormais utiliser ComputeSharp.D2D1 pour écrire des effets entièrement personnalisés et accélérés par GPU à intégrer dans Paint.NET. Ce qui nécessitait auparavant une connaissance des composants internes HLSL et D2D est désormais facilement accessible à tous les développeurs C #, avec seulement quelques lignes de code et des API conviviales de haut niveau.

Si vous êtes curieux de voir à quoi ressemble un shader ComputeSharp, en voici un très simple : le shader hello world, qui affiche juste un dégradé de couleurs animé qui change avec le temps. Voici le code C# pour cela :

Un shader de calcul DirectX 12 écrit en C# avec ComputeSharp

Vous pouvez voir comment le shader est simplement un type de structure C #, qui capture certaines valeurs (dans ce cas, un flottant pour indiquer le temps écoulé), puis effectue des calculs pour calculer la couleur à afficher dans la sortie. Il s'agit de l'intégralité du shader, que ComputeSharp se chargera ensuite de traiter au moment de la construction via un générateur de source, pour le convertir en HLSL et également générer du code supplémentaire pour prendre en charge son exécution.

Voici à quoi ressemble le code HLSL résultant pour ce shader :

Le shader HLSL transpilé pour le type C#

Il est facile de voir certaines des transformations que ComputeSharp a effectuées dans les coulisses : le shader a maintenant un tampon constant, qui est utilisé pour marshaler les valeurs capturées vers le GPU, il a des annotations de taille de thread pour contrôler la répartition du shader, les vérifications automatiques des limites ont été ajouté, et le shader capture également implicitement la texture de sortie et lui attribue le pixel résultant. En tant que développeur C# utilisant ComputeSharp, vous n'aurez jamais à vous soucier de tout cela : le générateur de source fourni avec ComputeSharp se chargera de tout ce gros travail tandis que vous pourrez écrire en C# et bénéficier d'IntelliSense et de tous les excellents outils qu'offre C#.

Je souhaite également montrer quelques exemples complets de bout en bout de ce à quoi ressemble le code en cours d'exécution sur le GPU à l'aide de ComputeSharp. Nous avons vu comment vous pouvez écrire un shader, mais vous pourriez vous demander s'il est réellement difficile ou non de le répartir. Ce n'est pas le cas ! Et il y a aussi plusieurs façons de le faire, vous pouvez donc choisir celle qui correspond le mieux à vos besoins.

ComputeSharp offre un mode d'exécution rapide et un mode graphique de calcul. Le premier est particulièrement utile si vous débutez avec la bibliothèque, si vous voulez essayer des choses ou si vous avez juste besoin d'exécuter un script simple et que vous ne voulez pas avoir à vous soucier de la configuration d'un pipeline d'exécution plus complexe. Voici comment exécuter un shader de test très simple :

Mode d'exécution rapide dans ComputeSharp

C'est tout ce que vous avez à faire pour exécuter du code C# sur le GPU ! Vous pouvez voir comment nous avons un shader très simple, qui multiplie simplement toutes les valeurs d'une texture par 2, puis nous le répartissons sur un tampon inscriptible que nous avons alloué sur le GPU avec des valeurs aléatoires. Après avoir envoyé le shader, nous pouvons également recopier ce tampon GPU sur le CPU afin de pouvoir lire son contenu. ComputeSharp expose des dizaines d'API très faciles à utiliser pour effectuer des opérations courantes comme celles-ci, qui peuvent s'adapter à tous les scénarios, des simples scripts minimaux aux architectures plus complexes.

Examinons également un exemple utilisant le mode graphique de calcul :

Mode graphique de calcul dans ComputeSharp

Ce mode est parfait si vous souhaitez créer un pipeline d'exécution entièrement personnalisé qui peut également tirer le meilleur parti des performances du GPU. Dans ce mode, nous créons d'abord un ComputeContext , qui est un objet qui nous permet de mettre en file d'attente les opérations sur le GPU. Ensuite, nous créons notre pipeline (y compris des opérations telles que la répartition des shaders, le contrôle des transitions pour synchroniser les accès aux ressources partagées, etc.), et enfin nous le répartissons sur le GPU lorsque nous sortons du cadre du contexte. Vous pouvez également voir comment ici nous tirons parti de la syntaxe await using pour exécuter tout ce travail de manière asynchrone sur le GPU, de sorte que nous ne bloquons pas le thread actuel tant que le GPU n'a pas fini de traiter notre demande.

Qu'en est-il de la prise en charge de XAML ? ComputeSharp propose deux contrôles ( ComputeShaderPanel et AnimatedComputeShaderPanel ), qui facilitent l'intégration d'un effet alimenté par ComputeSharp dans une application UWP ou WinUI 3 : placez simplement le contrôle XAML dans votre vue, attribuez-lui un objet shader runner et vous c'est bon d'y aller !

ComputeShaderPanel utilisé dans une vue XAML

Voici comment un ComputeShaderPanel peut facilement être déclaré dans une vue. Ensuite, il a juste besoin d'une instance IShaderRunner pour savoir comment rendre chaque image. Pour les cas simples, par exemple lorsque nous voulons simplement afficher une animation de shader, le type intégré ShaderRunner<T> est plus que suffisant :

ShaderRunner étant assigné à un ComputeShaderPanel

Et c'est tout! Le panneau utilisera le shader runner pour dessiner chaque image et prendra en charge toute la configuration nécessaire pour afficher chaque image générée. Pour des scénarios plus avancés, vous pouvez également implémenter vous-même le shader runner, ce qui vous donne un contrôle total sur la synchronisation des images, le graphe de calcul utilisé pour produire chaque image à afficher, et plus encore !

Enfin, je souhaite également montrer un exemple de pixel shader D2D1. Ce sont les shaders que Paint.NET utilise, et ils font également partie de l'infrastructure sur laquelle je travaille actuellement pour permettre leur utilisation dans les applications UWP et WinUI 3 via la bibliothèque Win2D (vous pouvez voir ma proposition pour cela ici aussi ). Ils sont très différents des shaders de calcul DirectX 12, mais grâce à l'infrastructure de ComputeSharp, ils sont tout aussi faciles à mettre en œuvre et peuvent également être exécutés sans trop d'effort en tirant parti de l'effet de shader de pixels intégré inclus dans ComputeSharp.D2D1.

Voici un exemple d'effet pixellisé de Paint.NET :

Un pixel shader D2D1 pixélisé, de Paint.NET

Vous remarquerez qu'il y a quelques différences entre ce shader et le shader DX12 montré ci-dessus, mais l'expérience du développeur est essentiellement la même : il vous suffit de créer un type C#, d'utiliser les projections HLSL et les API disponibles incluses dans ComputeSharp, laissez IntelliSense vous guider. vous, puis laissez ComputeSharp faire tout le reste du travail pour vous au moment de la compilation.

Regardons également le code transpilé pour ce shader :

L'effet pixelisé transpilé en HLSL

Encore une fois, le type C # a été transformé selon les besoins pour suivre les conventions HLSL nécessaires, dans ce cas spécifiquement pour les pixel shaders D2D1. Nous avons déclaré des champs à mapper aux différentes valeurs capturées en C#, tous les intrinsèques ont été transmis à leurs équivalents HLSL, la syntaxe du shader a été mise à jour, et bien plus encore. Et tous ces shaders, tout comme ceux de DX12, peuvent également être précompilés au moment de la construction, ce qui signifie que vos applications peuvent avoir des performances de démarrage extrêmement rapides et qu'il n'est pas nécessaire d'invoquer ou de regrouper le compilateur de shader une fois déployé !

Il y a beaucoup plus qui est disponible dans ComputeSharp, et ce n'est que la toute première version stable après la réécriture - il y a beaucoup de nouvelles fonctionnalités et améliorations sur lesquelles je travaille déjà et que je prévois d'inclure dans les futures versions ! Vous êtes invités à consulter le référentiel sur GitHub , à essayer la bibliothèque ( vous pouvez la trouver sur NuGet ! ) et à laisser des commentaires et des idées !

Et si vous l'utilisez et construisez quelque chose, partagez-le ! J'adore voir toutes les choses sympas que les gens peuvent créer avec ComputeSharp !

Bon codage !