Denis Salem | Blog

CATEGORIES

ARCHIVES

Nuit de 2016 ou 2017

Je travaillais sur une technique de projection astral basé sur le rêve lucide.

J'arrive dans une sorte de jardin à l’arrière d’une vielle maison. Sidoine est déjà là. Il y a une très grande machine, une sorte de vaisseau spatial. Je pénètre à l’intérieur. Sidoine est en train d’examiner le vaisseau, il a l’air plus expérimenté et a l’air de connaitre la machine, sans forcément la maîtriser.

À l’intérieur se trouvent des rangés de sièges permettant de contrôler collectivement ou individuellement la machine. J’essai de comprendre les mécanismes, mais tout ça ressemble à de la technologie extra-terrestre. Sidoine ne me parle pas trop. Il est à l’autre bout du vaisseau et continue d’examiner attentivement l’intérieur du véhicule.

Nous ne parvenons pas à démarrer.

Nuit du 2 novembre 2017

テレパシー愛好家

Je me regarde dans le miroir. Je suis en train de me préparer. Je suis une jeune est très belle transgenre noire. J’observe minutieusement le grain de ma peau dont je redécouvre les formes et la texture. Je suis beau et belle à la fois. Il me semble que c’est la première fois que je me travestis, sur un coup de tête, ou du moins, je n’ai pas le souvenir d’avoir déjà fait ça avant. J’ai de beaux et longs cheveux platine, rasé sur le côté. J’applique un rouge à lèvre blanc sur mes lèvres et à l’aide d’un aérographe un voile rectangulaire, blanc également, sur le regard.

J'enfile des collants et une paire de chaussure noires à talons et semelles compensées, très féminine et élégante. Je porte à mes oreilles de belles boucles argentées triangulaire. J’hésite à mettre une jupe ou un mini short satin. Mon choix se porte sur le mini short. La question se pose maintenant de savoir quel volume donner à ma fausse poitrine. En ai-je besoin? Pourquoi pas. Je me mets un soutien gorge noir, que je rambour avec ce que je trouve comme tissu. Je n’en mets pas trop. Il me faut quelque chose d’harmonieusement proportionné. Je m’habille avec un débardeur à col roulé noir et enfile par dessus un blouson en cuir à manches courtes. Au risque d’en faire trop je ponctue l’ensemble avec des gants long et noir. L’ensemble me donne une curieuse allure, comme si je venais du futur. Je prends mon petit sac à mains et sort dans la rue.

L'angoisse et le malaise monte en moi, en même temps que l’excitation. Et si on me reconnait? Et si on m’agresse? Si je rencontre un homme ou une femme et que nous voulons faire l’amour, comment me comporter? Je croise des collègues de l’école, certains ne me remarquent pas, d’autre si. Je vois qu’ils me désirent alors qu’ils ne me reconnaissent pas. Je croise une collègue, elle me sourit et me demande si on se connait. Au coin d’une rue, mon prof d’anglais me reconnaît et me fait un signe de la main. Il est amusé de me voir ainsi, mais il n’est pas malveillant. Cela ne le surprend pas de ma part me dit-il. Des passants me sifflent.

Je songe à ce que je suis. Je suis exactement ce que je désire et que je ne parviens pas à avoir. Mais je suis aussi moi. Une part de moi en sommeil depuis très longtemps. Nous sommes deux à présent en moi-même. L’homme et la femme. Peut-être sommes nous d’avantage. Je me sens infiniment fort et fragile à la fois. Ce sentiment de complétude que je cherchais depuis si longtemps existait en moi-même. Je n’ai pas besoin de désirer les femmes. Je peux m’aimer moi-même, et ainsi aimer les autres. Leur corps et leur âme.

Je songe à en parler à mon père. J’entreprend de l’appeler. Je le visualise clairement à l’autre bout du fil. Il me reproche de ne pas me montrer raisonnable. Je lui fais honte et ma véritable nature, binaire, le déçois. Sans surprise l’image qu’il se fait de moi est tout autre de ce que je suis vraiment.

La beauté ou la laideur ne sont pas universels, mais dans l’œil de l’observateur.

Nuit du 3 novembre 2017

On regarde un film d’horreur cyberpunk intitulé Nevnov datant de 2009. Je finis par plonger dans le film, c’est très confus. Je retrouve des éléments visuels présent dans BioShock. L’action se déroule dans un bunker tentaculaire dont il est impossible de s’échapper, plongé dans l’obscurité et partiellement inondé. Des créatures rôdes et d’innommable secrets nous attendent. On comprend vite qu’il n’y a rien à sauver. L’eau est infestée de méduses cubozoaires mortellement dangereuses dont les piqûres sont atrocement douloureuses. L’horreur qui nous assiège n’est pas une chose avec laquelle nous devons ou pouvons lutter, mais plutôt quelque chose qu’il nous faut accepter. Comme un nouveau paradigme. Les ténèbres qui nous dévorent sont comme autant de lumières noires révélant nos pires souffrances psychologiques et traumatismes.

On pourrait penser que c’était un cauchemar, mais en fait non. C’était plus comme un cheminement à l’intérieur de ce qu’il y a de plus sombre dans la conscience.

Nuit du 4 novembre 2017

Nous sommes une unité d’élite. Un groupe d’individus dont l’âge varie grandement, sélectionné me semble-t-il pour nos aptitudes. Réflexes, maniement de l’arme à feu, condition physique. Nous sommes, en quelque sorte, des supers héros sous contrat. Nous sommes une petite dizaine et certains d’entre nous rentrent seulement dans l’adolescence alors que d’autres, comme moi sommes déjà de jeune adultes. Difficile de relater les circonstances de notre rencontre, l’action effrénée m’empêche de me souvenir, seul compte notre objectif. Nous devons amener à destination, saint et sauf, une personnalité importante. Cette destination, c’est la cathédrale au cœur de la ville.

Nos véhicules, bijoux de technologie, filent à toute allure, assistés par des tirs depuis l’espace dégageant la routes de nos assaillants. Ce matériel, ainsi que les satellites nous prêtant mains forte sont de mon invention et ne sont pas de trop, l’ennemi est en sur-nombre et nous sommes forcés par moment de nous disperser dans de vastes décors urbains mêlé à des environnements naturels sauvages présentants de gros risques. Nous rentrons dans des zones où se trouvent des civils, une nouvelle contrainte s’impose à nous, et nous oblige à cesser de faire feu.

Je donne alors le signal pour nous mettre en position. Les satellites vont générer depuis l’espace des leurres et des obstacles. Mon équipe est alors voilée par des formes géométriques régulières rendant impossible notre identification, et donc la localisation exacte de notre colis dans notre unité. Pour fonctionner ces voiles semi-virtuelles ne doivent pas être trop éloignés entre eux. Alors que nous filons à toute vitesse, le plus jeune d’entre nous, qui est également le plus virtuose au commande de son bolide, est obligé de se séparer et d’emprunter une route singulièrement sinueuse et dangereuse. Grâce à la vision par satellite, je suis capable, au commande de mon propre véhicule, de suivre exactement l’action de chacun d’entre nous. J'indique à mon jeune ami qui s'éloigne comment nous retrouver au plus vite pour reprendre notre position et sauver notre couverture. Notre colis est au moins aussi habile que nous autres en matière de pilotage et de défense, mais du fait de son importance, il était totalement exclu de laisser cette personnalité effectuer le trajet seule puisque, de toute évidence, le contre-espionnage était parfaitement au courant de nos plans.

La course poursuite est effrénée, et contrairement à nous, l’ennemie n’hésite pas à ouvrir le feu sur notre équipe quitte à blesser des civils. C’est notre dernière mission et sans aucun doute la plus difficile, celle où tout se joue maintenant. Nous parvenons finalement à rentrer dans la zone de la ville dont le niveau de sécurité est naturellement suffisant pour repousser et dissuader nos assaillants de poursuivre leur manœuvre. La cathédrale commence à être visible et n’est plus dissimulée par les grands immeubles de la ville. Je profite de cette accalmie pour faire le point sur notre carrière et la situation. ???? est parvenu à nous retrouver en empruntant un chemin extrêmement étroit et mortel. Ses réflexes sont hors du commun, je me demande s’il a conscience du danger. ???? et ???? comprennent que nous avons gagné, j’entend dans mes écouteurs qu’ils s’échangent quelques mots coquins. Nous avons gagné. Une sorte d’euphorie et de soulagement nous envahie. Seul notre colis se montre parfaitement stoïque et reste maitre d’elle-même. Très alerte et professionnelle. Nous la déposons au pied de la cathédrale où sa sécurité viens la chercher.

C’est finit. Mes camarades sont soulagés et fier. J’éprouve moi-même un grand sentiment de satisfaction et de puissance. Nous avons vraiment assuré. Nous avons mis en déroute la plus grande menace qui pesait sur le colis. Je rappelle à mes collègues que nous passerons dans quelques heures un entretien individuel pour présenter notre rapport détaillé. Mais ça ira, nous sommes les plus forts. Oui. Je réalise alors, comme pour la première fois, que nous sommes vraiment les plus forts.

Je m’éloigne un peu de mon groupe, songeurs. La fête bat son plein en ville, au pied de la cathédrale, où un événement est attendu. Un discours de notre colis? Où peut-être une avant première? Des stars de cinéma semble être attendu. À mesure que je marche un sentiment d’inquiétude m’envahit. Nous sommes les seules à connaitre le système de sécurité du colis aussi bien, et étant sous contrat, théoriquement rien ne nous empêcherait de changer de camps, si ce n’est notre loyauté. Nous somme la dernière menace potentiel pesant sur la personne que nous protégions quelques instants au par avant. Je reviens alors voir mes camarades, toujours très joyeux et enivré par l’action dont ils ne cessent de se vanter, amusé et fier.

« Écoutez, c’était notre dernière mission avec ces gens là, au moment de faire notre rapport individuel, il se peut qu’ils tentent d’en finir avec nous. Soyez tous extrêmement prudent. »

La joie s’efface de leurs visage, je retrouve le sérieux et la concentration auquel ils m’habituent tous en mission. Un voile de tristesse et de fatigue obscurcisse légèrement leur visage.

À l'occasion du Weekly challenge Good Bye Old Friend j'ai mit à jour un de mes pixelarts les plus fameux: L'Homme du Desert

Voilà le making of qui s'additionne à celui de la version antérieur ici L'Homme du Desert v6.1 (Making of)

Le résultat final:

L'Homme du Désert

Voilà mon petit derniers :)

http://pixeljoint.com/pixelart/114337.htm

Le Long Chemin Vers Les Réponses (Making Of)

Le résultat final:

Le Long Chemin Vers Les Réponses

They Are Anonymous

Journal onirique 0x00

J'ai terminé une grosse toile de peinture que j'avais commencé il y a un moment déjà...

Journal onirique 0x00

C'est peint d'après un rêve que j'avais fait il y a longtemps.

C'était une sorte de film où l'on suivait plusieurs protagonistes, dont la personne sur la toile. Ils étaient tous marginaux et dégageaient une sorte de lumiére, comme une aura, que personne ne pouvait voir à part eux (et le spectateur du film bien sûr). Ils ne se croisaient jamais, et ne se connaissaient pas mais leurs actions contribuaient à rendre le monde meilleur par effet papillon bien qu'ils soient de petites gens, anonymes et noyés dans la masse et la misére. Il y avait un vieux réparateur d'appareils électroniques, une fille qui faisait de la récup' dans les décharges (elle était un peu junky aussi), et d'autres personnages dont je ne me rappelle plus trop. À la fin du film, après moulte épreuves de la vie, dépressions et difficultées dû à leurs conditions, ils finissent tous par se trouver pour la première fois sur une plage lors d'une fête populaire. Il y a alors une sorte de mouvement de foule circulaire, et ça les faits converger vers le centre, et ils se rencontre alors tous enfin découvrant leur aura respective et l'influence positive qu'ils ont sur le monde. Cette dernière scène avait une forte charge symbolique.

Souvenir d'INRIA

L'Oiseau Pendule (Making of)

Le résultat final:

L'Oiseau Pendule

Aout 2015

Je cherchais quelque chose de plus visuel et de beaucoup moins mental dirons nous. Une troisième tentative avec les champignons l'été derniers, au dernier festival de la Hadra dans le Vercors, semble avoir confirmé que ça ne correspond pas à ce que je cherche, mais ce pourrait être aussi une question de dosage et d'état d'esprit. Toujours est-il que j'ai pu mettre la mains sur de la Salvia Divinorium, de la bonne du terroir, si l'on peut dire. Je m'efforçais à ce moment de me défaire des aprioris que j'avais développé sur les effets en lisant les trip reports d'autres psychonauts, retenant que ce que j'avais vécu avec les champignons était finalement assez différent de ce que j'avais lu. Encore une fois le dosage et l'état d'esprit y sont sans dans doute pour quelque chose.

La Salvia se chique ou se fume. Je n'aime pas fumer et il paraitrait que chiquer la Salvia augmenterait substantiellement ses effets. Mon amie et moi même choisîmes donc de mâcher la plante jusqu'à ce que les effets apparaissent. Nous avions préparé un grand bol de feuilles fraiches. Pendant ce temps, et bien que je n'étais guère inquiet d'un éventuelle accident ou bad trip, je m'assurais que son appartement, qui donc serait le lieu de notre trip, ne présenterait aucun danger potentiel.

Le goût est infâme. Il est peu probable que vous ayez déjà gouttez quelque chose d'aussi infecte. C'est d'autant plus difficile qu'il faut garder la mixture ainsi malaxée en bouche. La substance active pénètre par les muqueuse, en cas d'ingestion, celle-ci est détruite et ne pénètre pas dans le sang. Nous poursuivons péniblement la chique assis sur le canapé de mon amie. Malheureusement pour elle, le goût est tellement ignoble qu'elle finit par tout recracher et vomir par la même occasion.

Elle reviens à mes côtés. Des effets très léger se font déjà sentir, nous ressentons vite une pesanteur dans notre corps et notre esprit. Ne pouvant pas parler, parce que la bouche pleine, je lui propose avec la main de nous coucher dans le lit. J'aurais voulu (et j'aurais sans doute du) garder en bouche plus longtemps le produit que je recrache finalement peu de temps après elle. Je l'embrasse du bout des lèvres. Je la sens un peu déçu de ne pas avoir pu garder en bouche la Salvia, découragée aussi peut-être.

Allongé l'un contre l'autre je l'enlace dans mes bras, mais je ne suis pas bien installé. Ce n'est pas exactement de la fatigue, mais je ressens le besoins d'immobilité et de confort. Je lui explique et je m'excuse, je sais qu'elle veut être contre moi. Je reste collé à elle, mais détendu de tout mon long, emmitouflé avec elle sous sa couette patchwork. Bien qu'elle ne dise rien je ressens qu'elle perçoit quelque chose. Au bout d'un moment elle me dit qu'elle contemple les légères déformations de l’environnement. Comme moi, elle est assommée par la substance. De mon côté, c'est plus que des déformations. Je n'ai pas spécialement d'états d'âmes, c'est très visuel et ça me plait ainsi. Je me rend tout de même compte que comme pour elle, la dose est faible. C'est comme si le trip était lointain. Je suis à mit chemin entre le vrai monde et « là-bas ».

Je ne suis pas sûr qu'elle le perçoit comme moi, pour elle l'environnement ne fait qu'onduler, ce qui est déjà pas mal quand on a pas l'habitude, j'imagine. C'est comme si notre être était multidimensionnel. Il faut entendre par là que celui-ci s'étend au-delà des trois dimensions physiques. C'est comme si cet être, dont le prolongement est l'esprit, changeait de perspective ; de dimension. Par décalage ou translation successive sur l'un des axes d'une dimension inconnue du commun des mortels. Je repense alors à une expérience de pensée que j'avais imaginé. Lorsque vous faites de l'infographie 3D ou des mathématiques vous représentez le mouvement d'un corps ou d'un objet en fonction du temps qui correspond à une dimension à part entière. Je me demandais alors ce qu'il se passerait visuellement si l'on inversait l'axe x,y ou z avec t. Comment cela affecterait-il les formes et le mouvement?

À mesure de cette lente progression vers « l'autre côté », effectivement, l'environnement ondule et se transforme en un autre monde. Il devient évident que le temps est une dimension spatial. Ce n'est pas le temps qui s'écoule, c'est la conscience qui glisse dans un univers statique. Les objets les plus insignifiants semblent habités par un esprit qui les animes, littéralement.

De l'autre côté de la chambre en bazar, des vêtements sont jetés pêle mêle sur les meubles, et notamment une chaise solitaire et encombrante que mon amie aime d'autant plus qu'elle est orange. Mon regards semble figé sur ces vêtements. Ils semblent voler majestueusement. Les plis du tissu s'anime gracieusement, comme des méduses à la dérive ou un voile sous la brise. J'ignore si c'est l'univers qui bouge ou si c'est le vêtement qui se déplace. Il ressemble à une créature étrange et inoffensive, le genre sans système nerveux complexe et qui se nourrirait de micro organisme invisible à l’œil nu.

Malgré les visions je sens qu'il me faut un effort de concentration pour les maintenir. Je ressens mon corps vibrer comme si j'allais sortir de celui-ci à tout moment. Non, ça n'arrivera pas me dis-je. J'y suis encore bien encré. Je n'en ai pas assez pris. Le lit semble immense, comme un océan, les plis de la couette ondulent, c'est comme si j'étais sur un océans de tissu multicolore. C'est vraiment magnifique. Par instant on croirait à un décors de théâtre de papier et de carton animé en coulisse, derrière la scène. Je suis minuscule dans cet espace si grand.

Je suis frustré de ne pas avoir gardé la Salvia plus longtemps en bouche ça aurait pus aller plus loin, je le sens, c'est certains. Je m'endors finalement avec mon amis qui ne m'as pas attendu pour perdre connaissance.

Au réveil, elle me confirmera n'avoir finalement rien vu d'extra ordinaire si ce n'est des distorsions de l'espace, très légère, comme tout le reste de notre trip.

Peut-être la plante s'introduit elle à nous doucement. Peut-être est-ce une invitation à quelque chose de plus profond.

Le 10 février 2014

C. a répondu. Pas de la manière la plus élégante. Je ne suis pas non plus toujours élégant. Le trou noir s'étant évaporé il emporte avec lui une part de mes illusions. Bien d'autres persistent.

Peu de temps après ma première expérience, comme je l'avait dit dans mon précédent TR, j'avais manifesté de la déception quand au produit, mais son esprit semblait m'habiter encore discrètement. Comme une présence ou une inspiration. J'ai cette idée curieuse que la réalité est une chose vivante en soit, et qu'il est possible de communiquer avec. Jung parlait de synchronicité pour un phénomène à mon sens similaire. Après mon premier trip il restait moins d'un gramme et demi de champignons. J'ai tout gobé un dimanche matin de la même façon. Avec un vers d'eau. Mon trip à été successivement perturbé par plusieurs petit événement anodin qu'il n'est pas intéressant de mentionner. L'expérience aura duré deux à trois heures. Nous retiendrons notamment ce moment tristement comique où, confus, je tâtais à l'aveugle dans le boitier électrique -propriété d'EDF- de chez moi pour attraper mon portable que j'avais fait tomber dedans. Il n'y avait que des files de phases, neutre, et de terre qui ont manqué de me faire gagner les darwins awards 2014.

Les effets se sont fait sentir 40 minutes après ingestions. Tranquillement en train de refaire le papier peint de mon bureau -assurément psychédélique-. Quand soudain il me semble que je me déconnecte. Tout me semble étrange. Tout semble m'appeler. Une lourde fatigue m'arrasse. Pour une obscure raison mon oscilloscope est allumé. Le signal bruité qui s'y affiche est vaguement périodique et semble traduire un état de confusion mental croissant. Je l’éteins. J'ai besoin de m'assoir. La lumière semble irréel. C'est un peu le malaise à vrai dire, je comprend évidement tout de suite ce qu'il m'arrive. Je suis amusé de physiquement ressentir un truc et me laisse surprendre. Je suis étonné que les effets se manifestent de cette façon avec une si petite dose.

Il ne fait pas beau dehors. Une lumière blafarde jaunâtre traverse les nuages et s'efforce de réchauffer l'air et les couleurs de l'extérieur. Par instant la lumière se reflète de tel sorte que, sur le goudron mouillé, si l'on plisse les yeux, éblouit, on pourrait penser que c'est la mer. Des bourdonnements et des sifflements sourds me traversent le corps. Je connais cette sensation. C'est comme quand je m’apprête à sortir de mon corps sans le vouloir. Je suis incapable de me concentrer, et je me sens sensiblement oppressé. J'appréhende un coup de fil ou une interaction humaine requérant des phrases construites. Je m'allonge à même le sol, sur la moquette. Je reste là un moment bouche bée. Mon corps semble paralysée. Seule mes yeux semblent encore relativement dynamique. Je m'amuse à flouter ma vision comme lorsque, tout petit, incapable de dormir, je me prêtais à ces jeux optique, en fermant plus ou moins mes paupières.

Je suis étendu dans la lumière. Le ciel est gris, mais la pièce est très clair. À un moment, une camionnette se gare devant chez moi. Le ronronnement du moteurs m'apaise et me berce. Bien que je ne la vois pas, j’entends la portière s'ouvrir. J’entends les pas et les clapotis. J’entends le moteur. Je reste ainsi un moment. La pièce semble vivante, et chaque motif, chaque forme semble chargé d'une histoire confuse. Des formes se précisent, d'autres disparaissent. Je rêve. Je ressens de lourdes vagues à mesure que le moteur bourdonne. Je suis dans cet état si particulier ou mon esprit semble pouvoir se détacher de mon corps à tout instant. Il me semble être véritablement entre deux réalités.

Entre la réalité et le rêve, il n'y a rien. Dans cet endroit la mémoire est un fardeaux pesant. C'est peut-être plus vide encore que l'image que l'on se fait de la mort. L'horizon de cet espace intermédiaire est tapissé d'entités et de concepts volatiles. De loin, le monde semble déstructuré. Sans cohérence, à l'image d'un rêve confus dont persisterait pourtant l'impression que l'on serait impliqué dans une conjecture grave, des enjeux important. Ce qui est angoissant, c'est de ne pas pouvoir comprendre la quantité d'information qui me submerge. Pourtant à ce moment là, la réalité lointaine semble plus loquace. Et nous semblons entreprendre de communiquer, ou du moins poser les fondements d'une interaction intelligible. Ce n'est pas exactement Dieu, la réalité serait plus comme un langage, une interface dont on ne saisit absolument le sens la plupart du temps. Je me souviens que lorsque je parle de philosophie au chat, lui n'entend que du bruit. Pour lui, la réalité, c'est avant tout sa sieste, le radiateur, le bol de merde aseptisé que je lui sert et qui me coûte la peau du cul et, bien sûr, ses éternelles querelle avec le chat du voisin. Intelligence fractal convergente me dis-je. En ce moment, un Inconnue me parle, il me parle depuis toujours, mais c'est à peine si je l'écoute ou même tente de vraiment le comprendre sans que ma condition d'humain faible et peu concentré prennent le dessus. Sans que mes habitudes, mes désirs, la médiocrité d'un quotidien morbide s'empare de moi.

De ce chaos quelque chose de clair apparaît. Un énième avertissement, un appelle à ne pas s'égarer du chemin. Je suis un rescapé, un fortuné. Pour combien de temps? J'ai chuté de nombreuses fois et Il m'a relevé alors que d'autres sont resté à terre.

Je me redresse brusquement, le son du moteur à quelque chose d'étrange. D'inconsistant. Je l'entend dans ma tête, mais la camionnette est partie. Plus d'une heure s'est écoulée. Les objet jaune dans la pièce ressortent particulièrement plus que tout le reste, et cela me frappe. Je prête l'oreille. J'entends mon téléphone portable sonner. Je me relève, déséquilibré. Et tente de me rappeler où j'ai bien pu le poser. Sur le boitier EDF. Le vibreur le fait se déplacer, et je n'ai pas le temps de le saisir qu'il tombe dans le SEUL PUTAIN de trou de ce PUTAIN de boitier électrique.

Après cet incident, je redescend doucement. Troublé, naturellement. Bien que satisfait, je réalise comme je suis bloqué. J'étais tellement persuadé d'être maître de ma conscience à force de rêve lucide. Je réapprend à rêver, et à vivre. Je réapprend à être humble et à craindre que mon esprit défaille, de perdre ce que j'ai acquis spirituellement. Un héritage qui tout compte fait constitue quelque chose de bien fragile.

J'en veux encore.

À C., le 1er Décembre 2013

Prise de 2.2g de Cubensis Equador, avec de l'eau, Chez moi, Pas mangé depuis 4 ou 5 heure. Bonne lumière et bonne ambiance. Aucune montée, 2h après ingestions, aucun effet visuel notoire mais un fort état introspectif.

L'heure est grave. Les champignons magique, que j'ai avalé ne me font aucun effet. Leur chair bleutée était pourtant, semblait-t-il, saturée en psilocybine. La déception est immense. Il s'agit de cet instant, à la frontière du nihilisme et de la misanthropie, où tu te dis qu'il n'y a rien pour s’échapper de l'aliénante réalité. J'étais déjà bien allumé au collège. On peut même dire que j'ai connue, en quelque sorte, l'illumination. Je sais ce que c'est que de faire l'expérience de réalités alternées, peut-être que c'est pour ça que ces champignons se refusent à moi. Pas de couleurs, pas de rêves éveillés, pas de révélation que je n'ai déjà eu. Je n'apprendrais rien de nouveau. Il me semble connaître tout du monde et du cœur des hommes. Mon ami qui lui aussi écrit à son acte manqué me confessait tout à l'heure qu'il se sent seul. Une amie me confessait tout à l'heure, en pleure, au téléphone qu'elle se sentait seul. Ils se sentent tous seul. En couple ou célibataire, en famille ou entre ami. La solitude est la chose la mieux partagé du monde. Je me sens seul, immensément seul. Trahi au dernier degré par mes espoirs, par mon corps et par mon esprit.

C., tu es vraiment une fille magnifique. Mais la cigarette te fais vieillir prématurément. Je regrette vraiment de ne pas avoir pu être ton ami, je regrette de ne pas avoir pu te dire quand j'aurais pu que je t'aimais. Mon esprit perpétuellement confus ne fait pas la distinction entre passé, présent et futur. La vie est un rêve comme un autre, et le temps est une dimension spatial. Tout est affaire de perspective. Carl Gustave Jung, père de la psychanalyse, s'extasierait devant cette explosion de spontanéité et de sincérité. C., tu le savais ? On à tendance à être sexuellement attiré par des personnes ressemblant à nos parents. Enfin je dis sexuellement, mais en réalité, je parle du mécanisme primitif à l'origine du sentiment amoureux. Il y a quelque temps, en rangeant des cartons, je tombais sur des photos de ma mère. Tu lui ressemble beaucoup, au même âge. Vous avez le même caractère. La même tendresse apparente et la même frustration latente et insidieuse. La même féminité. À moi qui tombe dans un trou noir, au delà de l'horizon des évènements, sur la ligne de ma vie. Je ne m'attend plus à rien. Si jeune et déjà si fatigué de vivre.

Je ne suis pas capable de dire si, à l'issu de ce tripe improbablement introspectif, je sortirais de cette convergence entropique ou si, au contraire, je serais capable de transcender ma condition. Dans un univers parallèle, une réalité subjective, un rêve sans doute, nous nous aimons. Dans cette réalité ta sœur se moque de moi. Se serait comme dans un manga où les protagonistes se parle pour ne rien dire. Où les personnages se chamaille bêtement, et c'est mignon. Tendre. Innocent. Dans cette réalité, je ne connais pas encore le sexe, et je te désire sans comprendre comment ça fonctionne. J'aimerais te toucher. Comme ton regard m'a toujours fasciné, c'est ton visage que j'embrasse en premier, et tu me rend ce baisé, avec ton si beau sourire. Mais nous n'allons pas plus loin parce que nous n'osons pas. Nous n'oserons jamais. Nous nous aimons d'un amour impossible, parce que cette réalité alternative, comme toute les autres prendra fin. C., la réalité n'est pas absolu. Je regrette que tout le monde ne rêve pas comme moi je rêve pour s'en rendre compte.

Tout le monde ne peut saisir cette notion pourtant concrète de réalité alternée.

Tes yeux, ça c'est quelque chose. La topologie de ton visage va bien au delà de tout ce que j'ai pu voir. Une géométrie parfaite qui semble ne parler qu'a moi. Et pourtant tu es si loin. La vie est trop courte pour perdre son temps. Dans la réalité objective, dans le passé, en cours de biologie, nous somme exceptionnellement assis l'un à côté de l'autre. Comme on passait le peu de temps ensemble à être désagréable l'un envers l'autre, il me semble qu'a ce moment là nous étions mal à l'aise. Il fallait pourtant être courtois, ou se montrer qu'on était capable « de ». Difficile de t'observer sans que tu t'en rende compte. Nous nous parlons, nous échangeons. J'aimerais que ça dure, j'aimerais que ça devienne naturel. Tu sens bon. Dans la réalité objective, dans le passé, en cours de français. Tu es assise, et tu regarde droit devant toi. Tu es entourée de je ne sais trop qui. A un moment, quelqu'un sous entend, pour t’embarrasser que tu es amoureuse de moi. Faux souvenir ? Pourtant, c'est à ce moment que j'ai commencé à te considérer. Si cet instant n'a jamais eu lieu, tout une réalité s'est pourtant déroulé, conséquence de cet événement fictif. C'est peut-être ça le big-bang. Une hallucination. Avant, je n'avais pas suffisamment confiance en moi pour pouvoir espérer être aimé par quelqu'un d'aussi belle et doué. À ce moment ambiguë pourtant, il me semble que tu es amoureuse de moi, dans cette réalité objective. Nous ne nous l'avouerons jamais. Pour Erwin Schrödinger, physicien quantique de son époque, l'univers est double.

Tant que je n'ai pas les moyens de vérifier tes sentiments. Tu es simultanément amoureuse et indifférente. Se soir, dans les ténèbres, je rompt la symétrie. J'avais peint un tableau de toi, et je t'en avais envoyé une copie numérique. Sans réponse. En même temps, c'était pas brillant, mais ça rend mieux en vrai. Saisir tes traits, c'est comme te faire mienne. Qu'aurais tu pu répondre ? Plus de sept ans se sont écoulé, plus que le temps nécessaire pour que toutes les cellules de nos deux corps se soient entièrement régénéré. Autrement dit, tu n'es plus du tout la même personne. Ni moi non plus. Je cours après un fantôme, un souvenir. Merci Facebook de conserver pour moi ton image.

C.

Merci internet d'abolir la notion d'espace temps. J'ai franchi l'event horizon. Je me sens chuter. Je redescend. L'univers, au delà du trou noir s'accélère. Le décalage temporel est tel que toute la lumière de l'univers se concentre en un seul point et me brûle. Compressé, il ne reste que la peur. Broyé, dans un maelström de souvenirs et de matière en fusion, dans un vide glacial, dans la lumière. Dans l'obscurité. Au delà du trou noir, l'univers poursuit son expension. Moi qui suit figé dans un abysse dont la science peine à saisir la nature, je ne peu vivre avec mon temps. Dimanche. Dans un univers qui n'est pas encore présent, tu te réveille d'une cuite. Tu te réveille tout court. Tu ne te réveille pas. Mais tu reçoit ce message confus. Indifférente, ou troublée. Surtout très mal à l'aise devant mes embarrassantes obsessions. Peut-être touchée. Peut-être... Mais il fallait bien que j'en finisse, d'une manière ou d'une autre. Je n'ai jamais cessé d'aimer les personnes que j'ai aimé, et qui ne sont plus dans ma vie. Ça n'a plus aucun sens mais je continue d'étendre cet affection torturé dans le vide. J'espère secrètement un écho à ma mesure. J'espère ne pas être seul ; j'espère un signal. Un écho. Juste un écho. Un écho lointain. Tous les trous noirs sont destinés à s'évaporer. En son sein, je ne puis plus communiquer avec l'univers. C'est mon dernier message, qui s'étire et s'étend, longuement, puis le silence. Enfin.

Introduction

Avant de se lancer dans ce tutoriel il convient d'être à l’aise avec la notion de shaders et les opérations basiques d'OpenGL. Si vous ne connaissez pas OpenGL, il est sans doute trop tôt pour se lancer dans les compute shaders. Il existe une pléthore de très bons tutoriels sur l'OpenGL moderne qui vous permettront de vous familiariser avec l'API. J'en retiens notamment trois:

Pour comprendre cette introduction aux compute shaders vous n'avez pas besoin d'aller trop loin dans les tutoriels OpenGL ci-dessus. Le minimum étant de savoir rendre à l'écran un simple triangle, auquel on applique une texture, en OpenGL moderne, avec les vertex/fragment shaders minimaux qu'il convient d'avoir.

Ceci étant dit, nous allons voir ici une fonctionnalité introduite depuis la version 4.3 de notre API favorite qui va nous permettre d'étendre nos possibilités.

Rappels

OpenGL définit un processus de rendu bien précis dont certaines étapes (stages) sont programmables en GLSL (OpenGL Shading Language) ; Ces étapes programmables sont appelées shaders et s'exécutent dans un ordre bien précis à l'intérieur de ce qu'on appel la Render Pipeline. Un schéma très simplifié de cette render pipeline est présenté ci-dessous, à gauche.

Fixed Shader Pipeline VS Compute Shader

On connaissait déjà les vertex shaders qui permettent de manipuler les vertices et les fragments shaders qui permettent de réaliser et d’appliquer des effets graphiques à notre image de sortie. Ces deux types de shaders sont obligatoires en OpenGL moderne. Les trois autres sont optionnels et nous n'en parlerons pas ici car ce n'est pas du tout le propos de ce tutoriel.

Lorsque l’on manipule les vertex shaders ou les fragment shaders, on se rend compte que chaque appel est indépendant et ignorent les autres. Ces shaders, s’inscrivant dans une pipeline de rendu bien définit, leurs entrées/sorties sont elles aussi bien définies, tout comme leur fréquence d’exécution (par exemple un vertex shader donné s’exécutera pour chaque vertex qu'on lui donne).

À quoi servent les computer shaders?

Avec les compute shaders il est maintenant possible de manipuler arbitrairement des données de la façon dont on le souhaite sans passer par la pipeline de rendu. En effet, avant les compute shaders, les développeurs utilisaient des hacks et des astuces plus ou moins efficaces pour faire des choses qui ressemblent à du GPU computing.

Car oui, ce que nous voulons faire avec les compute shaders, c'est du GPU computing avec l'API OpenGL.

Le GPU computing consiste en fait à faire du calcul dit parallèle sur la carte graphique. Certains algorithmes sont plus commodes et plus efficaces quand ils sont effectués sur ce type de support. En effet le CPU est très rapide mais a entre autre l’inconvénient majeur de ne pouvoir faire qu'une seule chose à la fois dans la majorité des situations. La carte graphique, elle, est beaucoup moins rapide mais peut effectuer un nombre astronomique de tâches simultanément. C'est cette aptitude qui confère à la carte graphique toute sa puissance.

Il faut cependant insister sur un point très important. L'architecture de la carte graphique étant conçue pour exécuter parallèlement des instructions, cela impose nécessairement au programmeur de prendre en considération cet état de fait lors de l'implémentation d'un algorithme sur ce type de support.

La programmation multi-threadé/parallèle est quelque chose de très différent et de substantiellement plus difficile que l'approche traditionnel; celle qui consiste donc à penser un programme séquentiellement.

La conception d'un algorithme est très différent de son implémentation. Tous les algorithmes ne sont donc pas adapté à des implémentations sur GPU ou de façon générale à des architectures parallèles.

Les compute shaders permettent donc maintenant de faire tout ça proprement. Ce gain en flexibilité représente un grand intérêt puisque l’on peut maintenant tirer parti de la puissance de la GPU plus librement pour par exemple:

  • créer à la volée des textures de synthèses
  • générer procéduralement des objets
  • effectuer des calculs parallèles qui ne sont pas forcément en rapport avec de l’imagerie 3D sans dépendre des APIs comme CUDA ou OpenCL.

CUDA ou OpenCL servent à ne faire que du calcul parallèle. En effet, embrayer dans un même programme d'OpenGL vers l'une des APIs mentionnées à l'instant (ou vis versa) est très chronophage, les compute shaders constituent une solution commode à ce problème.

Comme on l'a déjà dit les compute shaders sont indépendant de la pipeline de rendu. Lorsque ceux là sont invoqués les entrées/sorties sont définies par le programmeur et non plus par la pipeline. C’est également le programmeur qui détermine la charge de travail à effectuer en définissant des groupes de travail (workgroups) que nous verrons plus bas.

Aperçu de l'example

Pour illustrer le fonctionnement des compute shaders on se donne le programme exemple suivant :

damnSimpleComputeShader

Ce code source sert de support à ce tutoriel mais relire le code d'un autre peut être laborieux et/ou peut-être n'utilisez vous pas les mêmes librairies que moi. En réalité, il est très simple d'intégrer le compute shader rudimentaire que je présente ici dans un petit programme OpenGL tout aussi rudimentaire. N'ayez donc pas peur d'écrire votre propre programme et d'intégrer au fur et à mesure les éléments manquants qui nous intéressent.

Pour se représenter un peu le tableau de loin, on se propose donc à l’aide d’un compute shader de générer le contenu d’une texture vide pour réaliser un damier, et l’afficher.

En fait, c’est assez simple ; dans notre exemple, tout se passe comme si on allait créer une texture vierge et qu’on l’affichait normalement sur un quad (deux triangles formant un carré ou un rectangle) aux dimensions du viewport (la surface du rendu).

La différence étant qu’avant d’entrer dans la boucle de rendu, on génère le damier en appelant notre compute shader et en s’assurant que cette boucle n’interfère pas avec la génération des données.

En effet, sans explicitement bloquer le fil d’exécution OpenGL va écrire dans la texture et simultanément essayer de l’afficher, parallélisme oblige, ce qui n'est évidemment pas très commode.

Création de la texture

Maintenant que l’on a un aperçu de la façon dont se déroule notre programme, allons un peu plus dans le détail. La première chose à faire est de créer la texture qui nous servira de support.

1 glGenTextures(1, &quadTextureID)

On configure ensuite la texture

1 glBindTexture(GL_TEXTURE_2D, quadTextureID);
2     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
6     glGenerateMipmap(GL_TEXTURE_2D);  
7     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 640, 480, 0, GL_RGBA, GL_FLOAT, NULL);
8   glBindTexture(GL_TEXTURE_2D, 0);

Je ne vais pas m'attarder sur la configuration de la texture, mais à titre de rappel, on peut tout de même rapidement parler de ce qu'il se passe ici:

  • glTexParameteri sert à configurer la texture courante, c'est à dire celle que l'on a bindé avec glBindTexture. Ici la configuration choisi est très généraliste. Inutile pour ce turoriel d'aller plus dans le détail.
  • glTexImage2D permet de définir le type de texture que l'on utilise (GL_TEXTURE_2D) ainsi que le format interne des données de la texture côté GPU et côté CPU. C'est également avec cette commande qu'on envoie les données brutes de la texture à la carte graphique.

Remarquons qu'en général on passe à glTexImage2D un pointeur vers un tableau de données pour initialiser la texture avec celui-ci. Comme on alloue la mémoire côté GPU et qu'on génère ces données toujours sur la GPU ce pointeur peut-être NULL.

Création du compute shader

Un peu plus bas dans le programme, on arrive au bloc d’instructions où l’on crée notre compute shader.

 1 PrintWorkGroupsCapabilities();
 2 
 3   GLuint computeShaderID;
 4   GLuint csProgramID;
 5   char * computeShader = 0;
 6 
 7   GLint Result = GL_FALSE;
 8   int InfoLogLength = 1024;
 9   char ProgramErrorMessage[1024] = {0};
10   
11   computeShaderID = glCreateShader(GL_COMPUTE_SHADER);
12   
13   loadShader(&computeShader, "compute.shader");
14   compileShader(computeShaderID, computeShader);
15   
16   csProgramID = glCreateProgram();
17 
18   glAttachShader(csProgramID, computeShaderID);
19   glLinkProgram(csProgramID);
20   glDeleteShader(computeShaderID);

Ici, rien de nouveau. On voit que le compute shader se construit de la même façon qu'un vertex/fragment shader. La seule différence réside au moment de l'invocation de la commande glCreateShader. En effet le type de shader est maintenant GL_COMPUTE_SHADER

La première chose à faire, bien que ce ne soit pas obligatoire ici, c’est de connaître la capacité des groupes de travail offerte par la GPU. Ça ne mange pas de pain et ça va être l’occasion de détailler comment les groupes de travail sont organisés.

Les groupes de travail contiennent un certain nombre d’invocations du compute shader, définit à l’intérieur du shader lui même comme nous le verrons plus bas. Ce nombre est appelé taille locale du groupe de travail. On définit également au moment de l’exécution du compute shader le nombre de groupes de travail à lancer.

On peut schématiser ce qui vient d’être dit ainsi :

Groupes de travail

Où chaque petit carré représente une invocation de shader contenu dans un groupe de travail.

Ceci étant dit on devine que la carte graphique a une capacité limitée de groupes de travail et de nombre d’invocations locales. OpenGL permet de déterminer la capacité de la carte graphique en la matière. En effet dans la fonction printWorkGroupsCapabilities on récupère ces informations et on les affiches dans la sortie standard :

 1 void printWorkGroupsCapabilities() {
 2   int workgroup_count[3];
 3   int workgroup_size[3];
 4   int workgroup_invocations;
 5 
 6   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &workgroup_count[0]);
 7   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &workgroup_count[1]);
 8   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &workgroup_count[2]);
 9 
10   printf ("Taille maximale des workgroups:\n\tx:%u\n\ty:%u\n\tz:%u\n",
11   workgroup_size[0], workgroup_size[1], workgroup_size[2]);
12 
13   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &workgroup_size[0]);
14   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &workgroup_size[1]);
15   glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &workgroup_size[2]);
16 
17   printf ("Nombre maximal d'invocation locale:\n\tx:%u\n\ty:%u\n\tz:%u\n",
18   workgroup_size[0], workgroup_size[1], workgroup_size[2]);
19 
20   glGetIntegerv (GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &workgroup_invocations);
21   printf ("Nombre maximum d'invocation de workgroups:\n\t%u\n", workgroup_invocations);
22 }

Ce qu’on peut remarquer, et c’est très important, c’est que la taille locale d’un groupe de travail ainsi que le nombre de groupes de travail est définit en trois dimensions. Autrement dit les compute shaders travaillent dans l’espace. C’est très pratique, évidement, pour faire du traitement d’image, ou travailler en volume. Nous verrons plus bas comment organiser notre shader en fonction de ces informations.

Précisons également que ces groupes de travail sont lancés en parallèles selon la capacité et la disponibilité de la carte graphique. Il n’est pas possible de connaître l’ordre d’exécution des invocations et dans certains cas il est absolument vital de composer avec cet état de fait sous peine d’obtenir des résultats pour le moins inattendus ou pire, de planter le système.

Heureusement, dans notre cas:

  • La question de la synchronisation n’est pas le sujet ici, et le programme que l’on étudie ne nécessite pas que l’on soit attentif à l’ordre d’exécution des groupes de travail et des invocations du compute shader.
  • Notre exemple n’étant pas non plus gourmand en ressource il ne nécessite pas que l’on implémente une vérification particulière de la capacité des groupes de travail.

La fonction printWorkGroupsCapabilities est donc ici purement informative.

Rappelons tout de même que l’on crée un programme spécifiquement POUR le compute shader. Un programme qui n’est donc PAS celui où sera lié le vertex shader et le fragment shader qui servent au rendu. On le voit bien, plus bas dans le code ; la création du programme de rendu est indépendante et ne fait intervenir à aucun moment le compute shader.

Exécution du shader

Une fois que tout est prêt on peut enfin lancer notre compute shader.

1 glUseProgram(csProgramID);
2     glBindTexture(GL_TEXTURE_2D, quadTextureID);
3       glBindImageTexture (0, quadTextureID, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
4         glDispatchCompute(40,30,1);
5         glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
6       glBindImageTexture (0, 0, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
7     glBindTexture(GL_TEXTURE_2D, 0);
8   glUseProgram(0);

OpenGL étant une machine à état on bind la texture qui est associée au shader, exactement comme on l’a fait au moment de la création de la texture. On oublie pas également de binder notre shader program.

Par ailleurs, pour écrire dans la texture on utilise ce qu'on appelle une image unit. Ce qui signifie dans la pratique que l’on va pouvoir travailler dans un tableau avec des indices entiers, et non plus dans un sampler2D où les coordonnées sont normalisées. En utilisant la commande glBindImageTexture le shader peut accéder directement au contenu de la texture.

L’image unit associée à la texture est en WRITE_ONLY. En effet pour ce que l’on se propose de faire on a pas besoin de lire l’image depuis le compute shader, mais seulement d’y écrire.

C’est finalement avec glDispatchCompute que l’on lance l’exécution du compute shader et plus exactement que l’on lance l’exécution d’un certain nombre de groupes de travail. En effet glDispatchCompute prend trois paramètres x, y et z spécifiant chacun les dimensions de l’espace des workgroups à lancer.

Dans notre example, on travaille sur une image, donc dans un espace en deux dimensions, le troisième paramètre est naturellement fixé à 1.

Dans le programme on voit que j’ai choisi pour l’espace des groupes de travail une largeur de 40 et une hauteur de 30 (j’expliquerai le choix de ces valeurs plus bas), ce qui signifie qu’OpenGL va exécuter 40 x 30 = 1200 groupes de travail. Cela peut paraître beaucoup mais c’est en fait relativement peu.

Après l’appel de glDispatchCompute, OpenGL se met au travail et le fil d’exécution continue côté CPU ?

Non ! Programmeur vigilant que l'on est, on s’assure que le fil d’exécution de notre programme s’interrompe le temps qu’OpenGL termine le traitement de tous les groupes de travail à l’aide de la commande glMemoryBarrier qui permet comme on le devine de bloquer l’exécution des commandes OpenGL suivantes tant que la carte graphique n’a pas terminé ses transactions mémoires en cours.

Bloquer l’exécution des commandes OpenGL suivantes ?

Oui, en fait, le CPU et la GPU travaillent tous les deux de façon asynchrones la plupart du temps. En réalité, lorsque l'on appelle une commande OpenGL, celle-ci est mise en attente et est réellement exécutée côté GPU quand arrive son tour. Ce qui signifie que du côté du CPU, le programme peut continuer d'avancer tout seul. glMemorieBarrier s'assure donc que lorsqu'une commande OpenGL est lancé, toutes les transactions mémoires définies sont bien terminé.

En particulier, cela permet de bloquer l’exécution en fonction du type de mémoire que l’on veut. Ici, comme nous travaillons sur une image on utilise la valeur prédéfinie GL_SHADER_IMAGE_ACCESS_BARRIER_BIT.

On pourrait également, si cela était nécessaire, combiner plusieurs valeurs prédéfinies par OpenGL pour bloquer l’exécution du programme en fonction de plusieurs zones mémoire.

Si GL_ALL_BARRIER_BITS est utilisé alors le fil d'exécution des tâches à venir côté GPU se met en pause en fonction de toutes les zones mémoire précédemment sollicitées.

Pour bloquer réellement le fil d'exécution côté CPU, il faudrait utiliser la commande glFinish(). On a ainsi la garantie absolue qu'OpenGL à bien finit tout son travail après cette commande.

C'est bien pratiquer pour débuguer...

Ceci étant fait, les workgroups étant tous exécutés, on peut reprendre le fil d’exécution du programme et unbind nos états OpenGL.

Après quoi, on rentre tout simplement dans la boucle de rendu qui ne fait absolument rien de nouveau.

Doit on réappeler la commande glBindImageTexture dans la boucle de rendu ?

Bonne question. Non, ce n'est pas nécessaire. En effet, le fragment shader n'a besoin à aucun moment d'une image unit puisque ce qu'on fait c'est sampler la texture. On n'y accède donc pas directement.

Détail du compute shader

C’est donc le moment de voir à quoi ressemble le compute shader que l’on a exécuté.

 1 ##version 430
 2 
 3 layout (local_size_x = 16, local_size_y = 16) in;
 4 
 5 layout (rgba32f, binding = 0) uniform image2D img_output;
 6 
 7 void main() {
 8   // Aucun tableau de donnée n'étant passé au moment de la création de la texture,
 9   // c'est le compute shader qui va dessiner à l'intérieur de l'image associé
10   // à la texture.
11   
12   // gl_LocalInvocationID.xy * gl_WorkGroupID.xy == gl_GlobalInvocationID
13   ivec2 coords = ivec2(gl_GlobalInvocationID);
14 
15   // Pour mettre en evidence. Les groupes de travail locaux on dessine un damier.
16   vec4 pixel;
17   if ( ((gl_WorkGroupID.x & 1u) != 1u) != ((gl_WorkGroupID.y & 1u) == 1u)) {
18     pixel = vec4(1.0,.5,.0,1.0);
19   }
20   else {
21     pixel = vec4(.0,.5,1.0,1.0);
22   }
23 
24   imageStore(img_output, coords, pixel);
25 }

Un compute shader se présente en fait de façon très similaire aux shaders classiques. La nouveauté c’est que l’on définit à l’intérieur du shader lui même la taille des groupes de travail. Comme on le voit, la taille locale d’un groupe de travail est de 16 par 16. Rappelons que les dimensions de l’espace de travail des workgroups étaient de 40 par 30. On aura donc 16² x 1200 invocations du compute shader. On peut également remarquer que 16 * 40 = 640 et 16 * 30 = 480. Et ça tombe bien parce que c’est justement les dimensions de notre image et de notre viewport.

Quelques explications s’imposent. Nous pourrions effectivement générer un damier dans une image de façon itérative dans un seul thread. Mais ça ne serait pas vraiment optimal si on tient compte du fait que l’on peut faire la même chose en tirant parti de l’aptitude du GPU à faire du calcul parallèle.

Comme on l'a dit plus haut, la raison pour laquelle le nombre de groupes de travail et la taille de ceux là sont formulés en terme d’espace est que les compute shaders travaillent dans l'espace. Pour se repérer dans l’espace de la structure de donnée dans laquelle on travaille on utilise des variables introduites avec les compute shaders qui nous renseignent sur l’identifiant de l’invocation courante du compute shader. Cet identifiant étant tridimensionnel, on sait donc où l’on se trouve au moment d’une invocation donnée. Comme les invocations sont parallèles (mais également dans un ordre arbitraire décidé par OpenGL) on peut donc ici travailler simultanément à différents endroits de notre image, ce qui fait substantiellement gagner du temps.

Du coup, la seule façon de savoir où l’on se trouve est d’interroger ces variables spéciales qui identifient l’invocation courante.

Ces variables sont des vec3. À titre de rappel, OpenGL travail le plus souvent avec des vecteurs de deux, trois ou quatre composantes; respectivement vec2, vec3 et vec4. Les vecteurs peuvent contenir des entiers signés ou non signés ou, comme c'est le cas la plupart du temps, des nombres à virgules flottantes. Pour en savoir plus rendez vous sur le wiki d'OpenGL.

  • gl_LocalInvocationID est un vec3 qui nous dit où l’on se trouve relativement au groupe de travail courant. Les coordonnées xyz ainsi retournées ne peuvent donc pas être en dehors du volume décrit par la taille du groupe locale, à savoir ici : 16 par 16 par 1.
  • gl_WorkGroupID est un vec3 qui nous renseigne sur le groupe de travail courant, à ne pas confondre avec l’invocation courante donc. Les coordonnées xyz ainsi retournées ne peuvent pas être en dehors du volume décrit par la taille de l’espace des groupes de travail, à savoir ici : 40 par 30 par 1.
  • gl_GlobalInvocationID est un vec3 qui est en fait le produit des deux variables vues précédemment. Il repère l’invocation courante non plus relativement au groupe de travail courant mais dans l’espace global des invocations. Autrement dit, dans notre programme, cette variable nous dit où l’on se trouve dans l’image.

Finalement pour dessiner notre damier, on détermine la couleur de sortie en fonction de gl_WorkGroupID ; si sa composante x est paire et que sa composante y ne l’est pas alors la couleur de sortie est orange, sinon, elle est bleue. Toutes les invocations à l’intérieurs d’un groupe de travail seront donc soit oranges, soit bleues.

Pour terminer, on utilise la fonction GLSL imageStore pour écrire dans notre image. Remarquez qu’en fait on n’enregistre qu’un seul et unique pixel pour une invocation donnée du compute shader.

Résultat

En compilant et en exécutant le programme exemple (en vous assurant préalablement de satisfaire les dépendances) on obtient l’image ci-dessous.

Damier de 40x30 secteurs de 16 pixels²

Comme on pouvait s’y attendre notre damier comporte des secteurs de 16 pixels² au nombre de 40 en largeur et 30 en hauteur. On illustre ainsi sans ambiguïté l’utilisation d’un compute shader et des groupes de travail.

Pour terminer ce cours introductif vous pouvez jouer avec le compute shader présenté ici et modifier la taille du groupe de travail locale et adapter l'espace des groupes en conséquence pour changer la taille des cases du damier ou pour rendre à l'écran des formes géométriques et les positionner comme bon vous semble.

Conclusion

Pour terminer voici les ressources qui m'ont permis de réaliser ce tutoriel

Ce tutoriel a été rédigé dans le cadre d’un stage à l’INRIA, un grand merci à Sylvain Lefebvre et son équipe pour leur aide et leur disponibilité.

Un très grand merci également à Ge0 et Shenzyn, ainsi qu’Arius et Anto59290 pour leurs conseils et leurs relectures.

Merci enfin à Glordim pour la relecture finale!