Archives par étiquette : Idées

Encore une idée que je ne ferais pas : Linq To HLSL

C’est en lisant ce tweet de
Robert Pickering que j’ai eu l’idée d’écrire des posts sur les différentes idées (bizarre,
originales ou farfelues) qu’il m’arrive d’avoir. En effet, comme l’indique Robert,
et comme beaucoup d’entre vous je suppose, il m’arrive parfois d’avoir des idées qui
m’intéressent et qui me motivent mais par soucis de temps ou de compétences, je ne
les réalise que rarement. Je me propose donc de partager dorénavant certaines de ces
idées avec vous. Le but étant bien entendu d’avoir vos réactions, commentaires et
remarques. Commençons donc dès à présent avec la dernière idée en date que j’ai eu
(début de cette semaine).

Les GPU ont actuellement une puissance de calcul supérieure aux CPU et malheureusement
il n’est pas simple d’en profiter. Microsoft a étudié cette faisabilité via
le projet Accelerator
initié par Microsoft Research. DirectX 11 poursuit dans
cette voie grâce à l’apparition des Compute Shaders. Ces shaders particuliers n’ont
pas pour objectif de modifier un rendu graphique (d’effectuer des traitements sur
des pixels) mais d’effectuer différents types de calculs.

L’idée d’exploiter ces shaders m’est venu en rentrant un peu plus en détail dans le Windows
API Code Pack for .net
. Ce projet disponible sur Code Gallery permet principalement
d’exploiter les nouvelles APIs apparues avec Windows 7 directement depuis du code
managé. Mais l’API Code Pack for .net propose d’autres fonctionnalités tels que des
wrappers managés de DirectX 10.x et DirectX 11. Et en consultant la documentation
de ces wrappers je me suis rendu compte qu’il était possible d’appeler et d’exécuter
des Compute Shaders directement depuis du code managé. Ce fut une surprise puisque
depuis DirectX 9 qui disposait d’une version managée (un wrapper intelligent nommé
Managed DirectX), Microsoft avait fait un retour en arrière en ne proposant de développer
des applications DirectX qu’en code natif. Fonçant tête la première et pompant allègrement
un code natif trouvé sur le net je me retrouve rapidement avec ces quelques lignes
de code :

SwapChain swapChain;
SwapChainDescription swapChainDescription = new SwapChainDescription();
swapChainDescription.BufferCount = 1;
swapChainDescription.BufferDescription.Width = 1024;
swapChainDescription.BufferDescription.Height = 768;
swapChainDescription.BufferDescription.Format = Format.R8G8B8A8_UNORM;
swapChainDescription.BufferDescription.RefreshRate.Numerator = 60;
swapChainDescription.BufferDescription.RefreshRate.Denominator = 1;
swapChainDescription.BufferUsage = UsageOption.RenderTargetOutput;
swapChainDescription.OutputWindowHandle = m_windowHandle;
swapChainDescription.SampleDescription.Count = 1;
swapChainDescription.SampleDescription.Quality = 0;
swapChainDescription.Windowed = true;
var levels = new FeatureLevel[]
                            {
                                FeatureLevel.FeatureLevel_11_0,
                                FeatureLevel.FeatureLevel_10_1,
                                FeatureLevel.FeatureLevel_10_0
                            };
var driverTypes = new DriverType[]
                      {
                          DriverType.Hardware,
                          DriverType.Reference
                      };
D3DDevice device = null;

foreach(var driverType in driverTypes)
{
     device = D3DDevice.CreateDeviceAndSwapChain(null, driverType, null,CreateDeviceFlag.Default , levels,
                                                          swapChainDescription, out swapChain);
}

//Check Support for Compute Shader
FeatureDataD3D10XHardwareOptions options;
device.CheckFeatureDataD3D10XHardwareOptions(out options);
if(!options.ComputeShadersPlusRawAndStructuredBuffersViaShader4x)
    return;

device.CreateComputeShader();

Comme vous le devinez, la méthode CreateComputeShader attend un paramètre afin de
pouvoir être exécutée. Il faut en effet lui passer un pointeur vers le code d’un Compute
Shader compilé. Le problème suivant auquel j’ai donc été confronté fut donc de développer
un compute shader. Comme les shaders traditionnels, ceux-ci se développent dans un
langage spécialisé : le HLSL. Et après avoir jeté un oeil dans la documentation de
ce langage, je me suis vite rendu compte qu’il n’allait pas être simple d’implémenter
un traitement utile avec ce langage basé sur une syntaxe proche du C. Le langage propose
en effet un ensemble de types assez restreint et ne permet pas au pauvre développeur
managé que je suis de faire ce que je souhaite de manière simple. Partant de ce constat,
et pensant qu’il serait utile de simplifier l’accès au GPU via ces compute shader,
j’ai donc songé à l’idée de créer un provider Linq To HLSL. L’objectif de ce provider
est “simple” : Générer du code HLSL à partir d’un arbre d’expression, le compiler
en mémoire (ah mince D3DCompile ne semble pas implementé dans l’API Code Pack for
.net), l’exécuter et récupérer les informations en mémoire. Bien sûr en pratique,
il existe plusieurs difficultés de taille, notamment celle concernant le nombre de
types restreints supportés par HLSL contrairement aux langages managés. Il faudrait
lors de la génération de code convertir les types non supportés (quand cela est possible)
vers des types HLSL. Une chaine de caractères devrait être ainsi par exemple converti
en tableau d’entiers avant de pouvoir être manipulé.

Pourquoi je ne le ferais pas :

  • Il n’existe pas encore de cartes graphiques compatible DirectX
    11. La première qui sera disponible sera une carte AMD et devrait être mise en vente
    le 10 septembre. Il n’est donc pas encore possible de tester les réelles performances
    du projet.
  • Cela m’obligerait à apprendre un nouveau langage HLSL, langage
    très spécifique qu’il peu probable que j’utilise dans le futur.
  • Je n’ai absolument aucune idée du temps nécessaire pour développer
    ce type de provider (je sais que ça se rapproche de beaucoup mais je ne suis pas capable
    d’être plus précis que cela).
  • Et enfin, il semblerait que le langage Axum supporte à la fois
    le multi-core (plusieurs coeurs/processeurs) et many-core (différents types de coeurs
    (CPU/GPU)). Etudier ce projet devrait donc être plus pertinent que de développer ce
    provider.