• Aucun résultat trouvé

Primitive de calcul avec le pipeline graphique

4.5 Modèle formel du traitement en pipeline graphique

4.5.2 Primitive de calcul avec le pipeline graphique

Pour formaliser le fonctionnement du pipeline graphique, nous allons définir quelques fonctions qui utiliseront les types définis préalablement et vont donner les correspondants formels aux blocs opéra- tionnels du pipeline graphiques et à la façon de leur fonctionnement. Le tableau 4.2 présente une liste complète de ces fonctions.

Nom de la Nom Désignation Signature de type

fonction du type

— Sampler Échantillonage des textures (TX → TXP → C)

vprocessor — Processeur des vertex (Env → VProg → [V] → [V])

— VProg Vertex programme (Env → V → V)

fprocessor — Processeur des fragments (Env → FProg → [F] → [F])

— FProg Fragment programme (Env → F → F)

rprocessor — Opérations du framebuffer (Env → RProg → FB → [F] → FB)

— RProg Raster programme (Env → FB → F → FB)

TAB. 4.2 : Signatures de type des primitives du calcul du pipeline graphique et les GPU

4.5.2.1 Échantillonnage des textures

L’échantillonnage des textures est une des opérations utilisées dans deux unités - l’unité de traitement des vertex et l’unité de traitement des fragments. Elle se présente à l’utilisateur par les samplers, les blocs configurables d’accès à la mémoires des textures. Dans cette thèse, nous définissons les samplers comme des fonctions du type Sampler qui, pour une texture TX et une position TXP données, extraient une information à partir de cette texture. Le résultat d’échantillonnage se présente par le vecteur de couleurs de sortie C.

type Sampler = ( TX → TXP → C )

Le fonctionnement exact des fonctions d’échantillonnage est dépendant des capacités matérielles des processeurs graphiques et est configurable selon nos besoins. Ces capacités sont largement suffisantes pour notre travail et nous n’en allons utiliser que certaines configurations.

La première des fonctions d’échantillonnage que nous allons utiliser en la morphologie mathéma- tique est la fonction smpBorder qui nous retourne les points de la texture tx correspondant à la coor- donnée tp si cette coordonnée est présente dans l’étendue d’indexation de la texture, sinon, elle nous retourne la valeur de bord associée à la texture.

smpBorder :: Sampler

smpBorder tx tp | inbounds2D(bounds$ar) tp = ar ! tp

| otherwise = getTXBFromTX$tx

where ar = getArFromTX$tx

4.5.2.2 Traitement des vertex

Les vertex sont traités dans une unité de traitement que nous appelons le processeur des vertex et qui est définie dans notre formalisme fonctionnel par la fonction vprocessor. Son fonctionnement exact est

décrit par un programme VProg qui est exécuté sur chaque vertex du stream d’entrée. Ce programme peut obtenir certains paramètres globaux à partir de l’environnement de travail Env ou il peut obtenir des données à partir des textures (stockées dans l’environement Env).

vprocessor :: Env → VProg → [ V ] → [ V ] vprocessor e vp vs = map (vp $ e) vs

Le vertex programme lui-même est défini comme une fonction du type VProg qui est connectée à l’environnement Env et qui effectue une opération sur un vertex V. Le type V du vertex constitue également le type de sa valeur de sortie. Nous ne donnons ici que la signature de type VProg du vertex programmecar c’est ce programme qui exprime la capacité de programmation des GPU et nous allons le définir spécifiquement pour chacun de nos algorithmes.

typeVProg = ( Env → V → V )

Comme un exemple trivial d’un vertex programme, nous présentons la fonction vpid d’identité qui ne modifie pas le vertex d’entrée et le retourne aussitôt :

vpid :: Env → V → V vpid e v = v

4.5.2.3 Rastérisation des primitives géométriques

Un autre bloc fonctionnel dans le pipeline graphique est le rastériseur. Il s’agit de l’unité qui crée les fragments à partir des données décrivant une forme géométrique. Nous le définissons formellement comme fonction du type Rasterizer qui est connectée à l’environnement Env et qui prend comme argu- ment un tuple composé du flux des valeurs de la forme géométrique et du flux de vertex, ([Shape], [V]). Les fonctions de ce type extraient, selon les valeurs concrètes décrivant la forme, un nombre défini de vertex [V]. La sortie de ce bloc est, bien sûr, le flux des fragments [F] dérivés de cette forme.

typeRasterizer = ( Env → ( [ Shape ] , [ V ] ) → [ F ] )

Nous ne donnons à cette place que la signature de type Rasterizer d’un rastériseur. C’est dû au fait que le rastériseur est également une unité configurable. Par conséquent, les fonctions de ce type seront définies dans nos algorithmes et elles vont correspondre à la configuration particulière de cette unité.

4.5.2.4 Traitement des fragments

L’unité de traitement des fragments, appelée processeur des fragments, est définie d’une façon si- milaire au processeur des vertex (dans 4.5.2.2, page 81). Le processeur des fragments est modelé par la fonction fprocessor qui exécute un fragment programme FProg sur un flux d’entrée des fragments [F]. Ce processeur peut obtenir des données supplémentaires à partir de l’environnement de travail Env ce qui se présente comme la capacité d’échantillonner les textures. Le processeur de traitement des fragments a pour résultat également un flux des fragments [F].

fprocessor :: Env → FProg → [ F ] → [ F ] fprocessor e fp fs = map ( fp $ e) fs

Le fragment programme est une fonction du type FProg :

typeFProg = ( Env → F → F )

Nous ne présentons que la signature de type pour les fragment programmes. Les fonctions seront définies spécifiquement pour chaque algorithmes en assurant la fonctionnalité convenable à notre cas d’utilisa- tion. Le programme trivial d’un fragment programme est le programme d’identité fpid qui ne modifie rien sur le fragment d’entrée et le retourne inchangé aussitôt.

fpid :: Env → F → F fpid e f = f

4.5.2.5 Opération du framebuffer

Les opérations du pipeline graphique qui sont regroupées dans notre diagramme de blocs, fig. 3.18, page 52, sous le nom Raster opérations constitue, en effet, un bloc fonctionnel tout entier qui traite les fragments, les convertit en pixels et se charge de leur fusion avec le contenu déjà présent dans le framebuffer.

La manière dont l’information d’un fragment est fusionnée avec les données du framebuffer peut être configurée par l’utilisateur et nous pouvons, si notre matériel dispose de telles capacités, avoir également les fonctionnalités de post-traitement des pixels plus ou moins complexes.

Nous avons regroupé toutes ces opérations dans un bloc que nous avons nommé raster processor mais qui ne correspond pas sur les GPU à un vrai processeur mais plutôt à un certain nombre des blocs fonctionnels qui sont enchaînés dans un pipeline et dont la fonction peut être activée par l’utilisateur.

Pour suivre la même logique que pour le vertex processeur et le fragment processeur, nous définis- sons le raster processeur par la fonction rprocessor. Elle prend un programme RProg comme paramètre et englobe tous les blocs de post-traitement travaillant avec les informations du framebuffer dans une seule fonction du Haskell :

rprocessor :: Env → RProg→ FB → [ F ] → FB rprocessor e rp fb fs = foldl (rp$e) fb fs

Ce processeur peut obtenir des paramètres de configuration de l’environnement Env et applique le pro- gramme RProg sur tous les fragments du stream d’entrée [F] en utilisant les données du framebuffer FB. Le raster programme se charge également de l’écriture d’un nouveau pixel issu de ces opérations dans le framebuffer. La fonction du Haskell foldl qui est utilisée ici est parfaitement convenable pour notre travail. Elle correspond à la réduction du stream par une fonction dont les arguments sont de deux types différents et qui est parfaitement convenable pour notre travail.

Nous présentons ici la signature de type RProg du raster programme, la définition précise sera spé- cifiée ultérieurement selon les besoins particuliers de nos algorithmes.

typeRProg :: ( Env → FB → F → FB)