<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>C++, Qt et GPU &#187; OpenGL</title>
	<atom:link href="https://blog.developpez.com/gpu/?cat=6&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/gpu</link>
	<description></description>
	<lastBuildDate>Fri, 24 May 2013 17:02:21 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Compléments sur l&#8217;article &#171;&#160;implémenter un Voxel Cone Tracing&#160;&#187;</title>
		<link>https://blog.developpez.com/gpu/?p=214</link>
		<comments>https://blog.developpez.com/gpu/?p=214#comments</comments>
		<pubDate>Sun, 12 May 2013 20:45:59 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Intermédiaire]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Techniques]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=214</guid>
		<description><![CDATA[J&#8217;ai récement traduit l&#8217;article Implémenter un Voxel Cone Tracing, qui présente quelques difficultés techniques pour ceux qui ne sont pas habitués avec les concepts présentés dans cet article. Ce billet de blog à pour objectif de présenter ces concepts. Quelques &#8230; <a href="https://blog.developpez.com/gpu/?p=214">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>J&rsquo;ai récement traduit l&rsquo;article <a href="http://simonstechblog.blogspot.fr/2013/01/implementing-voxel-cone-tracing.html">Implémenter un Voxel Cone Tracing</a>, qui présente quelques difficultés techniques pour ceux qui ne sont pas habitués avec les concepts présentés dans cet article. Ce billet de blog à pour objectif de présenter ces concepts.<br />
<span id="more-214"></span></p>
<h1>Quelques définitions</h1>
<h2>Illumination globale</h2>
<p>Les techniques d&rsquo;illuminations globales (GI) visent à améliorer le rendu d&rsquo;une scène 3D, en prenant en compte aussi bien la lumière directe (les sources de lumières qui éclairent les objets) que la lumière indirecte (réflexion de la lumière sur les objets, qui éclaire d&rsquo;autres objets). Ces techniques permettent d&rsquo;obtenir des rendus réalistes, au prix d&rsquo;un temps de calcul relativement long (parfois trop pour être compatible avec du rendu en temps réel). Un domaine de la recherche actuelle vise à développer de nouveaux algorithmes d&rsquo;illumination globale compatible avec le temps réel (jeux 3D).</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/commons/0/0d/Global_illumination.JPG" alt="Exemple d'une scène rendu avec l'illumination globale" /></p>
<p style="text-align: center">(source : <a href="http://fr.wikipedia.org/wiki/Illumination_globale">Wikipédia &#8211; Illumination globale</a>)</p>
<h3>Illumination indirecte</h3>
<p>Dans l&rsquo;illumination directe (à gauche sur l&rsquo;illustration suivante), la lumière provenant d&rsquo;une source est directement réfléchie sur une surface, puis renvoyé vers la caméra. C&rsquo;est le modèle classique de calcul de la lumière en 3D, que l&rsquo;on retrouve par exemple dans le <a href="http://cpp.developpez.com/redaction/data/pages/users/gbdivers/qtopengl/?page=opengl#L5-A">modèle de Phong</a>. La lumière est alors décomposée en plusieurs composantes : la lumière ambiante (qui représente une illumination globale constante), la lumière diffuse (qui représente une diffusion de la lumière sur la surface) et la lumière spéculaire (qui représente une réflexion sur la surface).</p>
<p style="text-align: center"><img src="http://www.cgg-journal.com/2010-1/02/files/VPLs.png" alt="Principe de l'illumination indirecte" /></p>
<p style="text-align: center">(Source : <a href="http://www.cgg-journal.com/2010-1/02/index.html">Real-Time Global Illumination for Point Cloud Scenes</a>)</p>
<p>Dans l&rsquo;illumination indirecte, on considère que chaque surface qui reçoit de la lumière va à son tour en renvoyer. Il n&rsquo;y a donc plus qu&rsquo;une seule source de lumière, mais une infinité, correspondant à chaque surface qui renvoie de la lumière. Pour réaliser le rendu d&rsquo;une scène, il faut donc procéder de la façon suivante :</p>
<ol>
<li>pour chaque surface S1 visible par la caméra ;</li>
<li>pour chaque surface S2 visible depuis la surface S1 ;</li>
<li>calculer la lumière reçue par la surface S2 provenant de la source ;</li>
<li>calculer la lumière renvoyée par la surface S2 vers la surface S1 ;</li>
<li>calculer la lumière reçue par la surface S1 provenant de la surface S2 ;</li>
<li>calculer la lumière totale renvoyée par la surface S1 vers la caméra.</li>
</ol>
<p>Chaque étape doit prendre en compte plusieurs paramètres. Pour (3), il faut par exemple prendre en compte la distance entre la source et la surface S2 et l&rsquo;atténuation de la lumière en fonction de la distance. Pour (4), il faut prendre en compte les caractéristiques de la surface et sa capacité à réfléchir la lumière. Pour (5), il faut prendre en compte la distance entre les surfaces S1 et S2 et l&rsquo;angle d&rsquo;incidence. Pour (6), les capacités de réflexion de la surface S1 et la distance entre la surface S1 et la caméra.</p>
<p>Cette première approche simple peut largement être améliorée (et complexifiée), en prenant en compte par exemple que la lumière peut se réfléchir plusieurs fois sur des surfaces avant d&rsquo;atteindre la caméra (particulièrement important lorsque les surfaces sont très réfléchissantes, comme du verre ou du métal poli), de la diffusion de la lumière dans le brouillard ou la poussière (<a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html">lumière volumétrique</a>, <a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html">éclat lumineux</a>), la présence de plusieurs sources lumineuses (voir des milliers de sources lumineuses dans le cas de particules incandescentes).</p>
<h3>Lancé de rayons</h3>
<p>Il existe plusieurs techniques de &laquo;&nbsp;lancés&nbsp;&raquo;. Elles reposent sur l&rsquo;idée que la lumière est constituée de rayons qui vont partir de des sources lumineuses, se réfléchir, diffuser et réfracter sur les différentes surfaces (chaque surface pouvant renvoyer plusieurs rayons), puis atteindre la caméra. Dans les techniques de photon mapping, on part des sources lumineuses, on émet des rayons et on les suit jusqu&rsquo;à la caméra (cette technique est décrite dans un autre <a href="http://simonstechblog.blogspot.fr/2012/06/photon-mapping-part-1.html">article du blog de Simon</a> et fera l&rsquo;objet d&rsquo;une traduction). Dans les techniques de lancé de rayons, on part de la caméra, on lance un rayon pour chaque pixel de l&rsquo;image finale et l&rsquo;on remonte jusqu&rsquo;aux sources de lumière (illustration suivante).</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Ray_trace_diagram.svg/300px-Ray_trace_diagram.svg.png" alt="Principe du lancé de rayons" /></p>
<p style="text-align: center">(Source : <a href="http://en.wikipedia.org/wiki/Ray_tracing_(graphics)">Wikipédia &#8211; Raytracing</a>)</p>
<p>Dans la technique du lancé de cônes (Cone Tracing), présentée dans l&rsquo;article traduit, on remplace simplement les rayons par des cônes pour le calcul de l&rsquo;illumination.</p>
<h3>Occlusion ambiante</h3>
<p>Cette technique fera également l&rsquo;objet de <a href="http://simonstechblog.blogspot.fr/2011/06/ssao-using-line-integrals.html">plusieurs</a> <a href="http://simonstechblog.blogspot.fr/2012/10/angle-based-ssao.html">traductions</a> du blog de Simon, je la détaillerai à ce moment là.</p>
<p>Simplement pour comprendre l&rsquo;idée générale : lorsque deux surfaces sont proches (dans une fissure, un trou), la lumière indirecte diminue fortement et l&rsquo;on observe des ombres douces. Plus les surfaces sont proches et fermées, plus l&rsquo;ombrage sera important. L&rsquo;illustration suivante représente la même scène sans (en haut) et avec l&rsquo;occlusion ambiante (en bas). Remarquez en particulier l&rsquo;ombre dans l&rsquo;angle du mur et du sol et entre la sphère dans l&rsquo;image du bas.</p>
<p style="text-align: center"><img src="http://blog.developpez.com/gpu/files/2013/02/ambient-occlusion-2.png" /></p>
<p>Cette technique améliore fortement la qualité du rendu et commence à être très utilisée dans les jeux. Un de ses points forts est que pour un objet statique (ou peu dynamique), l&rsquo;occlusion ambiante ne varie pas (ou peu) et il est possible de la pré-calculer, le résultat étant mis dans une texture. Il suffit ensuite d&rsquo;appliquer la texture sur l&rsquo;objet lors du rendu, comme n&rsquo;importe quelle autre texture.</p>
<p>Il existe plusieurs algorithmes de calcul de l&rsquo;occlusion ambiante, mais pour comprendre le principe, voyons un exemple simple représenté dans l&rsquo;illustration suivante. Pour chaque point d&rsquo;une surface, on va lancer un nombre fixé de rayons qui vont parcourir une distance fixée aussi dans toutes les directions. On compte ensuite le nombre de rayons qui ne rencontrent pas une autre surface et on calcul le rapport entre le nombre de rayons ayant rencontrés une surface et le nombre de rayons lancés. Ainsi, dans l&rsquo;illustration suivante, pour le point A, sur les six rayons lancés, aucun ne rencontre de surfaces, le rapport est de 0/6 = 0 %. Pour le point B, seul quatre rayons ne rencontrent pas de surfaces sur les six lancés, le rapport est de 4/6 = 66 %. Pour le point C, deux rayons ne rencontrent pas de surfaces, le rapport est de 2/6 = 33 %.</p>
<p style="text-align: center"><img src="http://blog.developpez.com/gpu/files/2013/02/ambient-occlusion.png" /></p>
<p>Il suffit ensuite d&rsquo;atténuer la lumière pour chaque point en fonction du rapport calculé. Plus le rapport est proche de 0 %, plus la surface sera sombre et plus le rapport est proche de 100 %, plus la surface est claire.</p>
<p>Pour obtenir un bon rendu, on pourra augmenter le nombre de point et le nombre de rayons lancés, mais l&rsquo;impact sur les performances sera important.</p>
<h2>Partitionnement de l&rsquo;espace</h2>
<h3>Voxel</h3>
<p>Le principe des voxels est relativement simple : ils sont l&rsquo;équivalent en 3D des pixels pour la 2D. Un exemple bien connu d&rsquo;utilisation des voxels est le jeu Minecraft, dans lequel chaque élément (terrain, objets) sont représentés par des cubes.</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/en/7/74/Minecraft_city_hall.png" alt="Un exemple d'utilisation des voxels bien connu : Minecraft" /></p>
<p style="text-align: center">(Source : <a href="http://en.wikipedia.org/wiki/Minecraft">Wikiépdia &#8211; Minecraft</a>)</p>
<p>Les voxels sont particulièrement gourmand en termes de performances et sont encore peu utilisés pour les jeux vidéos. Ils sont particulièrement adaptés pour le rendu de volumes transparents (verre, liquide, fumée, nuage) ou de géométries très complexes (pour le rendu d&rsquo;un mesh complexe, une approche utilisant une version <a href="http://en.wikipedia.org/wiki/Low_poly">low poly</a> du mesh et une texture des <a href="http://fr.wikipedia.org/wiki/Displacement_mapping">Displacement</a>/<a href="http://fr.wikipedia.org/wiki/Normal_mapping">Normal</a>/<a href="http://fr.wikipedia.org/wiki/Bump_mapping">Bump</a> mapping).</p>
<h3>Octree</h3>
<p>Un octree est une structure permettant de partitionner l&rsquo;espace dans un arbre, permettant par exemple de faciliter la recherche d&rsquo;un élément par rapport à sa position 3D. La construction d&rsquo;un tel arbre est simple : à chaque itération, le cube représentant une partie de l&rsquo;espace est divisé en 8 cubes.</p>
<p style="text-align: center"><img src="http://http.developer.nvidia.com/GPUGems2/elementLinks/37_octree_03.jpg" alt="Division de l'espace avec un octree" /></p>
<p style="text-align: center">(Source : <a href="http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter37.html">GPU Gems 2 &#8211; Octree Textures on the GPU</a>)</p>
<p>L&rsquo;intérêt des octrees avec les voxels est que l&rsquo;on va pouvoir utiliser une structure &laquo;&nbsp;creuse&nbsp;&raquo; : les zones qui sont vides ne seront pas divisées en cubes plus petits, simplifiant ainsi les algorithmes de recherche et la mémoire.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ColorPicker avec Qt – Benchmark et optimisations</title>
		<link>https://blog.developpez.com/gpu/?p=390</link>
		<comments>https://blog.developpez.com/gpu/?p=390#comments</comments>
		<pubDate>Fri, 15 Feb 2013 18:52:59 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Intermédiaire]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=390</guid>
		<description><![CDATA[Le sujet du premier exercice proposé par la rubrique Qt de Developpez.com consistait à créer un widget permettant de sélectionner les différentes nuances de gris à partir d&#8217;une teinte définie. Deux méthodes ont été proposer pour générer ces nuances de &#8230; <a href="https://blog.developpez.com/gpu/?p=390">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Le sujet du premier exercice proposé par la rubrique Qt de Developpez.com consistait à créer un widget permettant de sélectionner les différentes nuances de gris à partir d&rsquo;une teinte définie.<br />
<span id="more-390"></span><br />
Deux méthodes ont été proposer pour générer ces nuances de gris :</p>
<ul>
<li>utiliser deux boucles for imbriquées pour parcourir chaque pixel du widget et calculer la couleur correspondante, en faisant varier les paramètres S et V dans l&rsquo;espace colorimétrique HSV ;</li>
<li>utiliser deux gradient (à l&rsquo;aide de la classe QLinearGradient), le premier, horizontal, allant du blanc à gauche à la teinte choisie à droite, et le second, vertical, allant du transparent en haut au noir en bas.</li>
</ul>
<p>Je vais présenter ici comment implémenter un benchmark avec Qt pour tester la rapidité de ces différentes méthodes et présenter deux autres méthodes pour accélérer le rendu : l&rsquo;accès direct au tampon mémoire contenant l&rsquo;image finale et l&rsquo;accélération matériel sur carte graphique.</p>
<h1>Création du programme Benchmark</h1>
<p>Qt offre différents outils facilitant la création de tests unitaires et de benchmarks, rassemblés dans le module <a href="http://qt.developpez.com/doc/4.6/QtTest/">QtTest</a>. Différents tutoriels permettent de se familiariser progressivement avec ce module.</p>
<h2>Benchmark.pro</h2>
<p>Pour créer notre programme Benchmark, commençons par créer un fichier de projet Benchmark.pro. Ce fichier de projet contient les déclarations de base suivantes : la liste des modules utilisés (core, gui puisse que l&rsquo;on teste les fonctions de dessin et testlib) et le nom et le type de binaire généré (une application Benchmark dans notre cas) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QT <span style="color: #000040;">+</span><span style="color: #000080;">=</span> core gui testlib<br />
TARGET <span style="color: #000080;">=</span> Benchmark<br />
TEMPLATE <span style="color: #000080;">=</span> app</div></td></tr></tbody></table></div>
<p>On ajoute ensuite la liste des fichiers à inclure dans notre projet. On va simplement créer une classe Benchmark : on ajoute donc les fichiers d&rsquo;en-tête et d&rsquo;implémentation :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SOURCES <span style="color: #000040;">+</span><span style="color: #000080;">=</span> benchmark.<span style="color: #007788;">cpp</span><br />
HEADERS &nbsp;<span style="color: #000040;">+</span><span style="color: #000080;">=</span> benchmark.<span style="color: #007788;">h</span></div></td></tr></tbody></table></div>
<h2>benchmark.h</h2>
<p>La classe Benchmark hérite de QObject (pour pourvoir utiliser le système de signaux et slots) et contient deux slots privés, un pour chaque méthode que l&rsquo;on souhaite tester. Ces slots seront automatiquement appelés à l&rsquo;exécution du programme. A part cela, le contenu de la classe est minimaliste :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#ifndef BENCHMARK_H</span><br />
<span style="color: #339900;">#define BENCHMARK_H</span><br />
<span style="color: #339900;">#include &lt;QtTest/QtTest&gt;</span><br />
<span style="color: #0000ff;">class</span> Benchmark <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> QObject<br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; Q_OBJECT<br />
<span style="color: #0000ff;">private</span> slots<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> hsvGradient<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> doubleLinearGradient<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<span style="color: #339900;">#endif // BENCHMARK_H</span></div></td></tr></tbody></table></div>
<h2>benchmark.cpp</h2>
<p>Dans le fichier d&rsquo;implémentation, on ajoute chaque méthode dans les slots correspondants :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &quot;benchmark.h&quot;</span><br />
<br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Il faut également ajouter la macro QTEST_MAIN, qui crée une fonction main, qui aura pour fonction de créer une instance de la classe Benchmark et d&rsquo;exécuter les slots privés :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QTEST_MAIN<span style="color: #008000;">&#40;</span>Benchmark<span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h2>Méthode des deux boucles for</h2>
<p>Pour mesurer le temps d&rsquo;exécution d&rsquo;une méthode, on utilise la macro BENCHMARK. Le temps du reste du code contenu dans le slot mais en dehors du bloc précédent la macro n&rsquo;est pas évalué. Pour vérifier que le code généré correctement les nuances de gris, on enregistre les images produites :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;QtGui/QPainter&gt;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> width <span style="color: #000080;">=</span> <span style="color: #0000dd;">500</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> height <span style="color: #000080;">=</span> <span style="color: #0000dd;">500</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> QColor m_main_color <span style="color: #000080;">=</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">red</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; QImage image <span style="color: #000080;">=</span> QImage<span style="color: #008000;">&#40;</span>QSize<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span>, QImage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> h <span style="color: #000080;">=</span> m_main_color.<span style="color: #007788;">hsvHueF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> s<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> s<span style="color: #000080;">&lt;</span>width<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>s<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> v<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> v<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>v<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; QColor color <span style="color: #000080;">=</span> QColor<span style="color: #008080;">::</span><span style="color: #007788;">fromHsvF</span><span style="color: #008000;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; h,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> s <span style="color: #000040;">/</span> <span style="color: #008000;">&#40;</span>width<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> v <span style="color: #000040;">/</span> <span style="color: #008000;">&#40;</span>height<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image.<span style="color: #007788;">setPixel</span><span style="color: #008000;">&#40;</span>s, v, color.<span style="color: #007788;">rgb</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;hsvGradient.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Méthode des deux gradients linéaires</h2>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; QImage image<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPixmap pixmap<span style="color: #008000;">&#40;</span>QSize<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPainter painter<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>pixmap<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">setPen</span><span style="color: #008000;">&#40;</span>QPen<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">NoPen</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QLinearGradient h_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span>width, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">white</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, m_main_color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>h_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>QRect<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QLinearGradient v_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">0.0</span>, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">transparent</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">black</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>v_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>QRect<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; image <span style="color: #000080;">=</span> pixmap.<span style="color: #007788;">toImage</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;doubleLinearGradient.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Le code étant expliqué dans la solution de l&rsquo;exercice, je n&rsquo;entre pas dans le détail ici.</p>
<h2>Résultat du benchmark</h2>
<p>Lorsque le programme est exécuté, des messages sont générés automatiquement à chaque étape du processus. L&rsquo;en-tête décrit simplement le nom du programme et les versions de QtTest et de Qt utilisées :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000040;">*********</span> Start testing of Benchmark <span style="color: #000040;">*********</span><br />
Config<span style="color: #008080;">:</span> Using QTest library 4.7.0, Qt 4.7.0</div></td></tr></tbody></table></div>
<p>Le premier slot que lance le programme est un slot spécifique, initTestCase, généré par défaut et ne faisant rien. Ce slot permet, si on le souhaite, d&rsquo;initialiser des objets pour l&rsquo;ensemble du programme :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">initTestCase</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Vient ensuite les différents slots que l&rsquo;on a créé. Le premier est hsvGradient. Lorsque le temps d&rsquo;exécution du slots est trop petit, la mesure risque de ne pas être précise. Pour palier à cet inconvénient, le code contenu dans le bloc de code suivant la macro BENCHMARK peut être exécuté plusieurs fois, le temps indiqué correspondant au temps moyen mesuré. Ici, le slot hsvGradient a été exécuté deux fois et le temps moyen est de 47 millisecondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">47</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">94</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Pour le slot doubleLinearGradient, le code a été exécuté une seule fois et le temps mesuré est de 57 millisecondes. On voit donc ici que cette méthode est plus lente que la première version (sur le système testé ! C&rsquo;est à dire Linux dans mon cas. Sous Windows ou Max OS X, il est possible que les résultats soient différents). Cette différence peut s&rsquo;expliquer par le fait que la génération de deux gradients et la gestion de la transparence est plus lente que l&rsquo;accès directe aux pixels, sur le système de rendu par défaut (le système Raster) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">57</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">57</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Le programme exécute ensuite un slot pour libérer les ressources initialisées dans la fonction initTestCase :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">cleanupTestCase</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Pour terminer, le programme indique le nombre de slot exécutés sans incident (passed), ceux qui ont échoué (failed) et ceux qui n&rsquo;ont pas été exécutés (skipped) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Totals<span style="color: #008080;">:</span> <span style="color: #0000dd;">4</span> passed, <span style="color: #0000dd;">0</span> failed, <span style="color: #0000dd;">0</span> skipped<br />
<span style="color: #000040;">*********</span> Finished testing of Benchmark <span style="color: #000040;">*********</span></div></td></tr></tbody></table></div>
<h1>Rendu dans un tampon mémoire</h1>
<p>Dans la première méthode, on utilise la fonction Qimage::setPixel pour modifier chaque pixel un par un. Cette méthode permet d&rsquo;utiliser une interface sécurisée et simple. Malheureusement, les calculs (calcul de l&rsquo;adresse mémoire correspondant au pixel, conversion de l&rsquo;espace colorimétrique HSV en RGB) et tests effectués en interne (la position du pixel est bien dans l&rsquo;image ? Les valeurs de la couleurs sont-elles correctes ?) peuvent ralentir fortement l&rsquo;exécution.<br />
Il est alors possible d&rsquo;optimiser le rendu en accédant directement à la mémoire à l&rsquo;aide de pointeurs : on créer un bloc mémoire de taille suffisante que l&rsquo;on alloue à une image puis on accède à chaque octet un par un.</p>
<p>ATTENTION : ce type d&rsquo;approche peut comporter certains risques : en cas d&rsquo;erreur dans le code, il est possible que l&rsquo;on écrive dans une zone mémoire qui ne correspond pas à l&rsquo;image. Aucun test n&rsquo;est effectué pour vérifier que le pointeur pointe vers une zone valide. L&rsquo;application peut devenir instable. De plus, il est possible que le code ne soit pas portable et donne des résultats différents en fonction des systèmes d&rsquo;exploitation utilisés (je l&rsquo;ai testé uniquement sur Linux, pensez à bien enregistrer tous vos documents avant de lancer le programme sur un autre système:) ).</p>
<p>La première chose a faire est de créer une zone mémoire de taille suffisante : un pixel étant codé sur 32 bits (un octet par composante de la couleur et quatre composantes : rouge, vert, bleu et alpha), il faudra donc réserver un bloc mémoire de width * height * 4 pour contenir toute l&rsquo;image :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; uchar buffer<span style="color: #008000;">&#91;</span>width <span style="color: #000040;">*</span> height <span style="color: #000040;">*</span> <span style="color: #0000dd;">4</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QImage image<span style="color: #008000;">&#40;</span>buffer, width, height, QImage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Il n&rsquo;est pas nécessaire d&rsquo;initialiser chaque octet du bloc mémoire (avec memset par exemple) puisque l&rsquo;algorithme utilisé garanti que chaque octet sera initialisé durant l&rsquo;exécution de celui-ci.</p>
<p>Pour commencer, on crée un pointeur pointant vers le premier octet du bloc mémoire :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; uchar<span style="color: #000040;">*</span> pbuffer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>buffer<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On utilise deux boucle for, comme dans la première méthode, pour parcourir chaque pixel (en fait, on parcourt le bloc mémoire linéairement, en « déplaçant » le pointeur octet par octet et non en accédant aux coordonnées (x, y) comme dans le cas d&rsquo;une image) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>width<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">//uchar green_blue = red;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> j<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> j<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>j<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span></div></td></tr></tbody></table></div>
<p>Les valeurs de composantes RGB sont calculés par la méthode présentée dans la version QML de la solution de l&#039;exercice :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> a <span style="color: #000080;">=</span> <span style="color:#800080;">255.0</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> i <span style="color: #000040;">/</span> width<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> b <span style="color: #000080;">=</span> a <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> j <span style="color: #000040;">/</span> height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Ensuite, pour chaque composante, on affecte la valeur calculée (sous forme de uchar pour être sur qu&#039;elle occupe bien à un octet en mémoire) à l&#039;octet pointé par le pointeur (en dé-référençant celui-ci) puis on « avance » le pointeur d&rsquo;un octet :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> b<span style="color: #008080;">;</span> <span style="color: #666666;">// blue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On fait de même pour les autres composantes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> b<span style="color: #008080;">;</span> <span style="color: #666666;">// green</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> a<span style="color: #008080;">;</span> <span style="color: #666666;">// red</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">255</span><span style="color: #008080;">;</span> <span style="color: #666666;">// alpha</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour terminer, on enregistre l&rsquo;image générée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;buffured.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Résultat du benchmark</h2>
<p>Les messages de sortie d&rsquo;application générés par le slot drawInBuffer indique que cette méthode est plus rapide d&rsquo;un facteur 10 que les deux autres méthodes, avec un temps d&rsquo;exécution moyen de 3,9 millisecondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color:#800080;">3.9</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">63</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">16</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h1>Optimisation de l&rsquo;algorithme</h1>
<p>Jusqu&rsquo;à présent, nous avons simplement travailler sur l&rsquo;implémentation pour optimiser le rendu des nuances de gris. Une autre approche consiste à travailler sur l&rsquo;algorithme utilisé et d&rsquo;essayer de diminuer les calculs effectués.<br />
Quelque soit l&rsquo;approche utilisée, il sera nécessaire de parcourir l&rsquo;ensemble des pixels du widget, soit explicitement, comme dans le cas de la première méthode présentée, soit implicitement, comme dans le cas des deux QLinearGradient. On ne pourra donc pas optimiser cette partie (on peut au mieux éviter de parcourir plusieurs fois chaque pixel, comme on fait avec la méthode avec les deux QLinearGradient).<br />
On peut remarquer que, dans chaque méthode présentée jusqu&rsquo;ici, on travaille avec des nombres réels, ce qui n&rsquo;est pas optimal. L&rsquo;idéal serait de travailler qu&rsquo;avec des nombres entiers, mieux gérés par les processeurs, et d&rsquo;effectuer que des opérations élémentaires : addition, soustraction et multiplication.</p>
<p>Regardons en détail ce que l&rsquo;on souhaite faire lorsque l&rsquo;on parcourt un ligne pour une composante en particulier. La composante est une valeur entière allant de 0 à 255 (ou de 255 à 0) pour les pixels allant de 0 à N (avec N &gt; 256 pour être sur d&rsquo;afficher toutes les nuances). Il faut donc parcourir chaque pixel et incrémenter, quand c&rsquo;est nécessaire, la composante. Si on représente cela avec un graphique 2D, on obtient :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/droite.png" class="aligncenter" /></p>
<p>avec x, l&rsquo;index des pixels, et y, la composante de la couleur (source : <a href="http://commons.wikimedia.org/wiki/File:Bresenham_run-based.svg">Wikipédia</a>).</p>
<p>Le lecteur averti aura compris l&rsquo;idée sous-jacente : calculer la composante de la couleur revient à dessiner une ligne dans un espace (x, y) discret. Or, il existe un algorithme très performant pour réaliser cela : <a href="http://fr.wikipedia.org/wiki/Algorithme_de_trac.%C3%A9_de_segment_de_Bresenham">l&rsquo;algorithme de Bresenham</a>. Il suffit juste de remplacer y par la composante de la couleur. Le lecteur se reportera à l&rsquo;article de Wikipédia pour l&rsquo;explication du principe de cet algorithme.</p>
<p>L&rsquo;implémentation de l&rsquo;algorithme est assez triviale à partir du pseudo-code. On fera attention aux notations utilisées, qui correspondent au pseudo-code, c&rsquo;est à dire que y1 correspondent à la composante de la couleur et non à la position verticale du pixel. La variable i est utilisée pour parcourir verticalement l&rsquo;image dans une boucle for :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QImage image<span style="color: #008000;">&#40;</span>width, height, Qimage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">int</span> x1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #666666;">// premier pixel</span><br />
<span style="color: #0000ff;">int</span> y1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #666666;">// composante dans le premier pixel</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> x2 <span style="color: #000080;">=</span> width <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> <span style="color: #666666;">// dernier pixel</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> y2 <span style="color: #000080;">=</span> <span style="color: #0000dd;">255</span><span style="color: #008080;">;</span> <span style="color: #666666;">// composante dans le dernier pixel</span><br />
<span style="color: #0000ff;">int</span> e <span style="color: #000080;">=</span> x2 <span style="color: #000040;">-</span> x1<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> dx <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <span style="color: #000040;">*</span> e<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> dy <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span>y2 <span style="color: #000040;">-</span> y1<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>x1 <span style="color: #000080;">&lt;=</span> x2<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; image.<span style="color: #007788;">setPixel</span><span style="color: #008000;">&#40;</span>QPoint<span style="color: #008000;">&#40;</span>x1, i<span style="color: #008000;">&#41;</span>, qRgb<span style="color: #008000;">&#40;</span>y1, y1, y1<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #000040;">++</span>x1<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; e <span style="color: #000040;">-</span><span style="color: #000080;">=</span> dy<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>e <span style="color: #000080;">&lt;=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>y1<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; e <span style="color: #000040;">+</span><span style="color: #000080;">=</span> dx<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;bresenham.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>L&#039;image générée est un gradient allant du noir au blanc :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/gradient.png" class="aligncenter" /></p>
<p>Pour générer toutes les nuances, il va falloir imbriquer deux fois algorithme, le premier allant du blanc à la teinte choisie (première ligne de pixels) et le second allant de la teinte (pixel de  la première ligne) au noir (pixel de la dernière ligne). Il faut également gérer chaque composante indépendamment.</p>
<p>Pour terminer, il est possible de combiner cette méthode avec la méthode utilisant un tampon mémoire. Le code est très proche du précédent.</p>
<h2>Résultat du benchmark</h2>
<p>La méthode utilisant l&rsquo;algorithme amélioré permet de gagner un facteur 3 à 4 par rapport aux premières méthodes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenham</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">14</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">58</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenham</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>La version combinant les deux approches permet un gain de performance d&rsquo;un facteur 4 par rapport à la méthode utilisant un tampon mémoire et un facteur 50 par rapport au premières méthodes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenhamInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color:#800080;">1.1</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">72</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">64</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenhamInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h1>Accélération matériel sur carte graphique</h1>
<p>Pour réaliser le rendu des nuances de gris sur carte graphique, on utilise une classe dérivée de QGLWidget. Il suffit de dessiner un rectangle s&rsquo;adaptant à la taille du widget, le reste du travail de rendu est réalisé dans le fragment shader : on calcule le rapport entre la position du pixel et la largeur du widget (passé en paramètre) pour calculer la nuance de gris correspondante :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #FF0000;">&quot;uniform vec4 main_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;uniform vec2 size;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;vec4 pixel_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;void main(void)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;{<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.r = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.r - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.g = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.g - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.b = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.b - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.a = main_color.a;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;gl_FragColor = pixel_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;}<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour que le fragment shader soit appliqué sur chaque pixel du widget, il suffit de dessiner un quadrilatère sur la totalité de la surface :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glClear<span style="color: #008000;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
glBegin<span style="color: #008000;">&#40;</span>GL_QUADS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color: #000040;">-</span><span style="color:#800080;">1.0</span>, <span style="color: #000040;">-</span><span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color: #000040;">-</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color: #000040;">-</span><span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
glEnd<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les différents paramètres utilisés dans le fragment shader sont définis à l&rsquo;aide des fonctions uniformLocation et setUniformValue. Par exemple, pour mettre à jour la taille du widget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">position_location <span style="color: #000080;">=</span> program<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>uniformLocation<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;position&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
QVector2D s <span style="color: #000080;">=</span> QVector2D<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
program<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setUniformValue<span style="color: #008000;">&#40;</span>size_location, s<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Par contre, je n&rsquo;ai pas réussit à utiliser les fonctions de benchmarks de Qt Test pour tester la rapidité du rendu par cette méthode. Pour pouvoir mesurer le temps, j&rsquo;ai ajouté un calcul du nombre de FPS (frame par seconde) avec un simple compteur, incrémenté à chaque cycle et remis à zéro toutes les secondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> delay <span style="color: #000080;">=</span> m_time.<span style="color: #007788;">msecsTo</span><span style="color: #008000;">&#40;</span>QTime<span style="color: #008080;">::</span><span style="color: #007788;">currentTime</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> delay <span style="color: #000080;">&gt;=</span> <span style="color: #0000dd;">1000</span> <span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>m_fps <span style="color: #000080;">&gt;</span> m_fps_max<span style="color: #008000;">&#41;</span> m_fps_max <span style="color: #000080;">=</span> m_fps<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; setWindowTitle<span style="color: #008000;">&#40;</span>QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;fps:%1 - max:%2 - w:%3 - h:%4&quot;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>m_fps<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>m_fps_max<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>width<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>height<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; m_fps <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; m_time <span style="color: #000080;">=</span> QTime<span style="color: #008080;">::</span><span style="color: #007788;">currentTime</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #0000ff;">else</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000040;">++</span>m_fps<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour mettre à jour la widget, j&rsquo;utilise un QTimer avec un délai de 0.</p>
<p>ATTENTION : Il en faut pas laisser le programme tourner trop longtemps avec cette méthode. Le programme tourne en boucle et utilise la carte graphique au maximum de ses capacités, ce qui augmente progressivement sa température. Personnellement, je n&rsquo;ai pas pris le risque de tester si cela pouvait endommager la carte graphique.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">m_timer <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> QTimer<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
connect<span style="color: #008000;">&#40;</span>m_timer, SIGNAL<span style="color: #008000;">&#40;</span>timeout<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">this</span>, SLOT<span style="color: #008000;">&#40;</span>timerUpdate<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
m_timer<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>start<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">timerUpdate</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; updateGL<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Performances</h2>
<p>J&rsquo;ai réalisé le test sur un ordinateur portable équipé d&rsquo;une carte Nvidia 8600M GT avec 512 Mo et un widget de 256 x 256 pixels. Avec cette configuration, les mesures donnent un FPS moyen de 5000 fps avec de pointes à 5200 fps, c&rsquo;est à dire des temps de rendu de l&rsquo;ordre de 0,2 millisecondes (soit 250 fois plus rapide que les premières versions).</p>
<h1>Les sources</h1>
<p><a href="http://www.developpez.net/forums/attachments/p67224d1284552523/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/benchmark.zip/">Télécharger les sources des benchmarks.</a></p>
<p><a href="http://www.developpez.net/forums/attachments/p67225d1284552535/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/colorpickeropengl.zip/">Télécharger les sources de la version OpenGL.</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Déboguer avec OpenGL 4</title>
		<link>https://blog.developpez.com/gpu/?p=6</link>
		<comments>https://blog.developpez.com/gpu/?p=6#comments</comments>
		<pubDate>Thu, 23 Aug 2012 22:03:57 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Lorsque l&#8217;on débute l&#8217;apprentissage d&#8217;OpenGL et des shaders (et même ensuite), on est vite confronté au problème du débogage, soit parce que le programme s&#8217;arrête brusquement, soit parce que le résultat obtenu ne correspond pas à ce que l&#8217;on attend. &#8230; <a href="https://blog.developpez.com/gpu/?p=6">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Lorsque l&rsquo;on débute l&rsquo;apprentissage d&rsquo;OpenGL et des shaders (et même ensuite), on est vite confronté au problème du débogage, soit parce que le programme s&rsquo;arrête brusquement, soit parce que le résultat obtenu ne correspond pas à ce que l&rsquo;on attend. Traditionnellement, on utilise la fonction <em>glGetError</em>, mais elle est encore trop souvent &laquo;&nbsp;oubliée&nbsp;&raquo; par les développeurs et elle donne finalement assez peu d&rsquo;informations.<br />
Heureusement, cette problématique a été prise en compte dans les dernières spécifications d&rsquo;OpenGL avec l&rsquo;ajout de nouvelles extensions pour le débogage. Ce billet de blog aborde les fonctionnalités de débogage introduites dans OpenGL 4.1 avec l&rsquo;extension ARB_debug_output et complétées dans OpenGL 4.3 avec l&rsquo;extension KHR_debug.<br />
Les outils externes de débogage ne sont pas abordés.<br />
<span id="more-6"></span></p>
<p><a href="http://www.developpez.net/forums/d1255099/applications/developpement-2d-3d-jeux/api-graphiques/opengl/deboguer-opengl/">Vous pouvez commenter cet article sur le forum</a></p>
<h1>Les nouvelles extensions</h1>
<h2>L&rsquo;extension ARB_debug_output (GL 4.1)</h2>
<p>Dans la version OpenGL 4.1, a été ajouté l&rsquo;extension ARB_debug_output, qui est une promotion de l&rsquo;extension GL_AMD_debug_output proposée par AMD. Cette extension ajoute la possibilité de créer des contextes avec un mode de débogage. En l&rsquo;activant, un système d&rsquo;événements est activé et permet d&rsquo;obtenir des informations variées, par exemple sur les problèmes rencontrés lors de la compilation des shaders GLSL, des appels de fonction non valides ou des problèmes potentiels de performance. Les messages générés par ce système peuvent être stockés dans une pile (&laquo;&nbsp;message log&nbsp;&raquo;) ou être récupérés par une fonction callback définie par l&rsquo;utilisateur.</p>
<h2>L&rsquo;extension KHR_debug (GL 4.3)</h2>
<p>Dans le but d&rsquo;uniformiser les différentes versions d&rsquo;OpenGL (en particulier avec OpenGL ES), l&rsquo;évolution d&rsquo;OpenGL tend à reprendre des fonctions provenant d&rsquo;OpenGL ES. C&rsquo;est le cas de l&rsquo;extension KHR_debug dans OpenGL 4.3 qui est une promotion de l&rsquo;extension ARB_debug_output d&rsquo;OpenGL 4.1 et des extensions EXT_debug_marker et EXT_debug_label d&rsquo;OpenGL ES. Cette extension ajoute ainsi des fonctions pour annoter les événements ou des groupes de commandes OpenGL.</p>
<h1>Création d&rsquo;un contexte de débogage (GL 4.1)</h1>
<p>La première chose à faire pour utiliser un contexte de débogage est de vérifier que l&rsquo;extension ARB_debug_output est bien prise en charge. Un exemple de code pour vérifier une extension est donné dans le tutoriel <a href="http://alexandre-laurent.developpez.com/tutoriels/OpenGL/OpenGL-Extensions/#L2-B">Les extensions OpenGL</a>.</p>
<p>Pour créer un contexte de débogage, il faut simplement créer un contexte en appelant la fonction <em>CreateContextAttribs</em> avec le paramètre CONTEXT_DEBUG_BIT. En fonction du système d&rsquo;exploitation, on aura donc un code équivalent à celui-ci :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> attribs<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <br />
<span style="color: #008000;">&#123;</span> <br />
<span style="color: #339900;">#ifdefWIN32 </span><br />
&nbsp; &nbsp; WGL_CONTEXT_MAJOR_VERSION_ARB, <span style="color: #0000dd;">4</span>, <br />
&nbsp; &nbsp; WGL_CONTEXT_MINOR_VERSION_ARB, <span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, <br />
&nbsp; &nbsp; WGL_CONTEXT_PROFILE_MASK, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, <br />
<span style="color: #339900;">#endif </span><br />
<span style="color: #339900;">#ifdef__linux__ </span><br />
&nbsp; &nbsp; GLX_CONTEXT_MAJOR_VERSION_ARB, <span style="color: #0000dd;">4</span>, <br />
&nbsp; &nbsp; GLX_CONTEXT_MINOR_VERSION_ARB, <span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, <br />
&nbsp; &nbsp; GLX_CONTEXT_PROFILE_MASK, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, <br />
<span style="color: #339900;">#endif </span><br />
&nbsp; &nbsp; <span style="color: #0000dd;">0</span> <br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// intialisation </span><br />
HDC hdc<span style="color: #008080;">;</span> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// Handle to a device context </span><br />
HGLRC hglrc<span style="color: #008080;">;</span> &nbsp; &nbsp;<span style="color: #666666;">// Handle to an OpenGL rendering context </span><br />
hglrc <span style="color: #000080;">=</span> wglCreateContext <span style="color: #008000;">&#40;</span>hdc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
wglMakeCurrent <span style="color: #008000;">&#40;</span>hdc, hglrc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// contexte attribs </span><br />
<span style="color: #0000ff;">int</span> pixelFormat, numFormats<span style="color: #008080;">;</span> <br />
glChoosePixelFormatARB<span style="color: #008000;">&#40;</span>hdc, attribList, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">1</span>, <span style="color: #000040;">&amp;</span>pixelFormat, <br />
&nbsp; &nbsp; <span style="color: #000040;">&amp;</span>numFormats<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
HGLRC wglCreateContextAttribsARB<span style="color: #008000;">&#40;</span>HDC hDC, HGLRC hshareContext, <br />
&nbsp; &nbsp; <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span>attribList<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp;<br />
<span style="color: #666666;">// après utilisation </span><br />
wglMakeCurrent <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span> <span style="color: #008080;">;</span> &nbsp;<br />
wglDeleteContext <span style="color: #008000;">&#40;</span>hglrc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les fonctionnalités de débogage sont activées en utilisant la constante GL_DEBUG_OUTPUT. Celle-ci peut être activée ou désactivée avec <em>glEnable</em> et <em>glDisable</em>. Par défaut, cette constante est activée dans un contexte de débogage et désactivée dans le cas contraire.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">// active les messages de débogage </span><br />
glEnable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
<br />
<span style="color: #666666;">// désactive les messages de débogage</span><br />
glDisable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Plusieurs niveaux de débogage sont possibles en fonction de la création ou non d&rsquo;un contexte de débogage et de si l&rsquo;on active GL_DEBUG_OUTPUT :
<ul>
<li>si on ne crée pas un contexte de débogage et que l&rsquo;on active GL_DEBUG_OUTPUT, les messages envoyés et le contenu sont laissés à l&rsquo;appréciation des implémentations d&rsquo;OpenGL, mais l&rsquo;appel des fonctions de débogage ne produit pas d&rsquo;erreur ;</li>
<li>si on crée un contexte de débogage et que l&rsquo;on n&rsquo;active pas GL_DEBUG_OUTPUT, aucun message de débogage n&rsquo;est lancé ;</li>
<li>si on crée un contexte de débogage et que l&rsquo;on active GL_DEBUG_OUTPUT, toutes les fonctionnalités de débogage sont activées.</li>
</ul>
<h1>Créer des contextes de débogage à partir d&rsquo;une bibliothèque (GL 4.1)</h1>
<p>Il existe plusieurs bibliothèques graphiques qui permettent de travailler sur des contextes OpenGL (SFML, SDL, Qt, etc.). Voyons comment créer un contexte de débogage dans ces cas d&rsquo;utilisation.</p>
<h2>Avec <a href="http://freeglut.sourceforge.net/">FreeGlut</a></h2>
<p>FreeGlut fournit directement une constante pour créer un contexte en mode débogage : GLUT_DEBUG.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">// FreeGlut </span><br />
glutInitContextFlags<span style="color: #008000;">&#40;</span>GLUT_DEBUG<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h2>Avec <a href="http://qt-project.org/">Qt</a></h2>
<p>La bibliothèque Qt fournit des outils pour créer et manipuler directement des fenêtres contenant un contexte OpenGL avec le module <a href="http://qt-project.org/doc/qt-4.8/qtopengl.html">QtOpenGL</a>. Pour créer un contexte spécifique d&rsquo;une version OpenGL, il suffit simplement d&rsquo;utiliser la fonction <a href="http://qt-project.org/doc/qt-4.8/qglformat.html#setVersion">setVersion</a> de la classe <a href="qt-project.org/doc/qt-4.8/qglformat.html">QGLFormat</a> :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include QtOpenGL</span><br />
... <br />
<span style="color: #007788;">QGLFormat</span> format<span style="color: #008080;">;</span> <br />
format.<span style="color: #007788;">setVersion</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">4</span>, <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
format.<span style="color: #007788;">setProfile</span><span style="color: #008000;">&#40;</span> QGLFormat<span style="color: #008080;">::</span><span style="color: #007788;">CoreProfile</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// nécessite Qt &gt;= 4.8 </span><br />
format.<span style="color: #007788;">setSampleBuffers</span><span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">true</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
GLWidget<span style="color: #000040;">*</span> w <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> QGLWidget<span style="color: #008000;">&#40;</span>format<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://qt-project.org/wiki/How_to_use_OpenGL_Core_Profile_with_Qt">How to use OpenGL Core Profile with Qt</a> sur le wiki de Qt.</p>
<h2>Avec <a href="http://www.sfml-dev.org/index-fr.php">SFML 2.0</a></h2>
<p>La bibliothèque SFML permet de demander lors de la création d&rsquo;une fenêtre la version du contexte OpenGL à utiliser avec la classe <a href="http://www.sfml-dev.org/documentation/2.0/structsf_1_1ContextSettings.php">sf::ContextSettings</a>. S&rsquo;il n&rsquo;est pas possible de créer un contexte avec les paramètres demandés, SFML va créer un contexte le plus proche possible. Il est donc important de vérifier la version de contexte réellement créée.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include SFML/OpenGL.hpp</span><br />
... <br />
<span style="color: #007788;">sf</span><span style="color: #008080;">::</span><span style="color: #007788;">ContextSettings</span> settings<span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">depthBits</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">24</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">stencilBits</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">8</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">antialiasingLevel</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">4</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">majorVersion</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">4</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">minorVersion</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
sf<span style="color: #008080;">::</span><span style="color: #007788;">Window</span> window<span style="color: #008000;">&#40;</span>sf<span style="color: #008080;">::</span><span style="color: #007788;">VideoMode</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">800</span>, <span style="color: #0000dd;">600</span><span style="color: #008000;">&#41;</span>, <span style="color: #FF0000;">&quot;OpenGL&quot;</span>, <br />
&nbsp; &nbsp; sf<span style="color: #008080;">::</span><span style="color: #007788;">Style</span><span style="color: #008080;">::</span><span style="color: #007788;">Default</span>, settings<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
sf<span style="color: #008080;">::</span><span style="color: #007788;">ContextSettings</span> settings <span style="color: #000080;">=</span> window.<span style="color: #007788;">getSettings</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;depth bits:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">depthBits</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <br />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;stencil bits:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">stencilBits</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <br />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;antialiasing level:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">antialiasingLevel</span> <br />
&nbsp; &nbsp; <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <br />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;version:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">majorVersion</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;.&quot;</span> <br />
&nbsp; &nbsp; <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">minorVersion</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://www.sfml-dev.org/tutorials/2.0/window-opengl.php">Using OpenGL in a SFML window</a> sur le site de SFML.</p>
<h2>Avec <a href="http://www.libsdl.org/">SDL 1.3</a></h2>
<p>La bibliothèque SDL fournit les constantes SDL_GL_CONTEXT_MAJOR_VERSION pour définir la version du contexte que l&rsquo;on souhaite utiliser.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SDL_GL_SetAttribute<span style="color: #008000;">&#40;</span>SDL_GL_CONTEXT_MAJOR_VERSION, <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
SDL_GL_SetAttribute<span style="color: #008000;">&#40;</span>SDL_GL_CONTEXT_MINOR_VERSION, <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
mainwindow <span style="color: #000080;">=</span> SDL_CreateWindow<span style="color: #008000;">&#40;</span>PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, <br />
&nbsp; &nbsp; SDL_WINDOWPOS_CENTERED, <span style="color: #0000dd;">512</span>, <span style="color: #0000dd;">512</span>, <br />
&nbsp; &nbsp; SDL_WINDOW_OPENGL <span style="color: #000040;">|</span> SDL_WINDOW_SHOWN<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
maincontext <span style="color: #000080;">=</span> SDL_GL_CreateContext<span style="color: #008000;">&#40;</span>mainwindow<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://www.opengl.org/wiki/Tutorial1:_Creating_a_Cross_Platform_OpenGL_3.2_Context_in_SDL_%28C_/_SDL%29">Creating a Cross Platform OpenGL 3.2 Context in SDL</a> sur le site de SFML.</p>
<h1>Les modes de synchronisation (GL 4.1)</h1>
<p>Par défaut, les appels de fonction OpenGL sont asynchrones, ce qui veut dire que les fonctions peuvent simplement envoyer les commandes aux contextes OpenGL puis passent à l&rsquo;instruction suivante dans le code. Par exemple, le code suivant peut poser des problèmes puisque rien ne garantit que l&rsquo;on mesure réellement le temps d’exécution de la commande :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">boost<span style="color: #008080;">::</span><span style="color: #007788;">timer</span> t<span style="color: #008080;">;</span> <br />
glDrawElement<span style="color: #008000;">&#40;</span>...<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000ff;">double</span> elapsed_time <span style="color: #000080;">=</span> t.<span style="color: #007788;">elapsed</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Lorsque l&rsquo;on débogue une application utilisant OpenGL, il peut alors y avoir un décalage entre l&rsquo;appel d&rsquo;une fonction et une erreur générée. Pour faciliter le débogage, il est possible de changer le mode de synchronisation pour forcer OpenGL à attendre la fin de la commande avant de passer à l&rsquo;instruction suivante dans le code. Cette fonctionnalité garantit la synchronisation dans un contexte, mais pas la synchronisation entre plusieurs contextes, qui reste sous la responsabilité de l&rsquo;application.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">// active le mode synchrone</span><br />
glEnable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT_SYNCHRONOUS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Il est possible de tester le mode avec <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsEnabled.xml">glIsEnabled</a> et de le désactiver avec <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml">glDisable</a>. Activer cette fonctionnalité peut être très coûteux en termes de performance et doit être utilisée uniquement pour le débogage.</p>
<h1>La pile des évènements (GL 4.1)</h1>
<p>La pile des évènements, appelée &laquo;&nbsp;message log&nbsp;&raquo; contient les messages lancés dans un contexte de débogage. Cette pile est de taille limitée, ce qui signifie que si elle est pleine, les événements les plus anciens seront perdus. Il faut donc la vider régulièrement en lisant les messages. Lorsque l&rsquo;on utilise plusieurs contextes, chaque contexte possède sa propre pile des événements.</p>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGet.xml">glGetIntegerv</a> permet d&rsquo;obtenir des informations sur les capacités et le contenu de la pile.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GLint maxMessages, totalMessages, len, maxLen, lens<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <br />
GLenum source, type, id, severity, severities<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_MAX_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>maxMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Nombre de messages maximum que peut contenir la pile : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, <br />
&nbsp; &nbsp; maxMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Nombre de messages contenus actuellement dans la pile : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, <br />
&nbsp; &nbsp; totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_MAX_DEBUG_MESSAGE_LENGTH_ARB, <span style="color: #000040;">&amp;</span>maxLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Taille maximale de message : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, maxLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB, <span style="color: #000040;">&amp;</span>len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Taille du prochain message : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les messages contenus dans la pile (GL 4.1)</h1>
<p>Les messages dans la pile contiennent plusieurs informations comme l&rsquo;origine du message, son type et son importance.</p>
<p><em>Origine du message</em> :</p>
<ul>
<li>GL_DEBUG_SOURCE_API : le message est lancé lors d&rsquo;un appel d&rsquo;une fonction OpenGL ;</li>
<li>GL_DEBUG_SOURCE_WINDOW_SYSTEM : le message est lancé par le gestionnaire de fenêtre ;</li>
<li>GL_DEBUG_SOURCE_SHADER_COMPILER : le message est lancé par le compilateur de shader ;</li>
<li>GL_DEBUG_SOURCE_THIRD_PARTY : le message est lancé par une bibliothèque externe ;</li>
<li>GL_DEBUG_SOURCE_APPLICATION : le message est lancé par l&rsquo;application (voir la partie &laquo;&nbsp;Envoyer un message personnalisé&nbsp;&raquo;) ;</li>
<li>GL_DEBUG_SOURCE_OTHER : le message ne provient pas d&rsquo;une des sources précédentes.</li>
</ul>
<p><em>Type de message</em> (l&rsquo;utilisation des constantes spécifiques d&rsquo;OpenGL 4.3 sera décrite dans la partie &laquo;&nbsp;L&rsquo;extension KHR_debug&nbsp;&raquo; de ce billet) :</p>
<ul>
<li>GL_DEBUG_TYPE_ERROR : message d&rsquo;erreur récupérable avec glEvent ;</li>
<li>GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR : utilisation fonction dépréciée ;</li>
<li>GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR : appel qui provoque un comportement indéfini ;</li>
<li>GL_DEBUG_TYPE_PORTABILITY : problèmes de portabilité ;</li>
<li>GL_DEBUG_TYPE_PERFORMANCE : notifications de performance ;</li>
<li>GL_DEBUG_TYPE_OTHER : ne correspond pas aux types précédents ;</li>
<li>GL_DEBUG_TYPE_MARKER : annotation (GL 4.3) ;</li>
<li>GL_DEBUG_TYPE_PUSH_GROUP : entrée dans un groupe (GL 4.3) ;</li>
<li>GL_DEBUG_TYPE_POP_GROUP : sortie d&rsquo;un groupe (GL 4.3).</li>
</ul>
<p><em>Importance du message</em> :</p>
<ul>
<li>GL_DEBUG_SEVERITY_NOTIFICATION : les messages qui ne concernent pas les performances et les erreurs ;</li>
<li>GL_DEBUG_SEVERITY_LOW : les alertes de performance concernant les changements redondants de contextes, les comportements indéfinis triviaux ;</li>
<li>GL_DEBUG_SEVERITY_MEDIUM : les alertes de performance sévères, les alertes de compilation ou de linkage GLSL, utilisation d&rsquo;un comportement déprécié ;</li>
<li>GL_DEBUG_SEVERITY_HIGH  : les erreurs OpenGL, les comportements indéfinis dangereux, les erreurs de compilation ou de link GLSL.</li>
</ul>
<p>Les messages sont identifiés de façon unique grâce à la combinaison de leur type, leur source et un numéro d&rsquo;identification.</p>
<p>Le dernier élément composant un message est une chaîne de caractères terminée par le caractère NULL (chaîne de caractères, style C) et donnant des informations plus détaillées sur le message.</p>
<h1>Lire les messages dans la pile (GL 4.1)</h1>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetDebugMessageLog.xml">glGetDebugMessageLog</a> permet de lire un ou plusieurs messages contenus dans la pile.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GLuint glGetDebugMessageLog<span style="color: #008000;">&#40;</span> &nbsp;<br />
&nbsp; &nbsp; GLuint count, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// nombre de messages que l'on souhaite </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupérer </span><br />
&nbsp; &nbsp; GLsizei bufSize, &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// taille du tampon de caractères </span><br />
&nbsp; &nbsp; GLenum <span style="color: #000040;">*</span> sources, &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les sources </span><br />
&nbsp; &nbsp; Glenum <span style="color: #000040;">*</span> types, &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les types </span><br />
&nbsp; &nbsp; GLuint <span style="color: #000040;">*</span> ids, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les identifiants </span><br />
&nbsp; &nbsp; GLenum <span style="color: #000040;">*</span> severities, &nbsp; &nbsp;<span style="color: #666666;">// récupère l'importance des messages </span><br />
&nbsp; &nbsp; GLsizei <span style="color: #000040;">*</span> lengths, &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// tableau contenant la taille des chaînes </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// pour chaque message </span><br />
&nbsp; &nbsp; GLchar <span style="color: #000040;">*</span> messageLog<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp; <span style="color: #666666;">// récupère les chaînes de caractères des </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// messages</span></div></td></tr></tbody></table></div>
<p>Pour récupérer un message :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> message <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, len, <span style="color: #000040;">&amp;</span>source, <span style="color: #000040;">&amp;</span>type, <span style="color: #000040;">&amp;</span>id, <span style="color: #000040;">&amp;</span>severity, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour récupérer les dix premiers messages :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> messages <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> maxLen <span style="color: #000040;">*</span> <span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span>, maxLen<span style="color: #000040;">*</span><span style="color: #0000dd;">10</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, severities, lens, <br />
&nbsp; &nbsp; messages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #666666;">// retourne une chaîne séparée par NULL </span><br />
<span style="color: #666666;">// lens retourne la taille de chaque message</span></div></td></tr></tbody></table></div>
<p>Pour effacer tous les messages dans la pile :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span>totalMessages, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Une erreur GL_INVALID_VALUE est lancée si le paramètre <em>bufSize</em> est négatif.</p>
<h1>Envoyer un message personnalisé (GL 4.1)</h1>
<p>Il est possible d&rsquo;envoyer un message personnalisé avec la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageInsert.xml">glDebugMessageInsert</a>. Cela permet d&rsquo;écrire des bibliothèques graphiques ou de transmettre des erreurs entre différentes parties d&rsquo;une application.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glDebugMessageInsert<span style="color: #008000;">&#40;</span>GLenum source, GLenum type, GLuint id, &nbsp;<br />
&nbsp; &nbsp; GLenum severity, GLsizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres sont équivalents aux autres fonctions. Si <em>length</em> est négatif, alors <em>message</em> est une chaîne de caractères terminée par NULL.</p>
<p>Par exemple :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glDebugMessageInsert<span style="color: #008000;">&#40;</span>GL_DEBUG_SOURCE_APPLICATION_ARB, <br />
&nbsp; &nbsp; GL_DEBUG_TYPE_ERROR_ARB, <span style="color: #0000dd;">1234</span>, GL_DEBUG_SEVERITY_LOW_ARB, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; <span style="color: #FF0000;">&quot;Un exemple de message personnalise&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction glDebugMessageInsert peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : <em>type</em> n&rsquo;est pas une valeur valide ou <em>source</em> ne vaut pas DEBUG_SOURCE_APPLICATION ou DEBUG_-<br />
SOURCE_THIRD_PARTY ;</li>
<li>INVALID_VALUE : <em>severity</em> n&rsquo;est pas une valeur valide ;</li>
<li>INVALID_VALUE : le nombre de caractères de <em>message</em> est supérieur à MAX_DEBUG_MESSAGE_LENGTH.</li>
</ul>
<h1>Les filtres de messages (GL 4.1)</h1>
<p>Dans de nombreux cas, il est souhaitable de pouvoir limiter les messages, pour éviter de perdre des messages s&rsquo;ils sont trop nombreux et éviter de devoir gérer un trop grand nombre de messages. Il est alors possible d&rsquo;ajouter un ou plusieurs filtres, pour supprimer certains types de messages ou au contraire n&rsquo;en garder que certains. Les filtres appliqués ne seront actifs que sur les nouveaux messages et non sur ceux qui sont déjà sur la pile.</p>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageControl.xml">glDebugMessageControl</a> permet d&rsquo;ajouter un filtre :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glDebugMessageControl<span style="color: #008000;">&#40;</span>GLenum source, GLenum type, <br />
&nbsp; &nbsp; GLenum severity, GLsizei count, <span style="color: #0000ff;">const</span> GLuint <span style="color: #000040;">*</span> ids, <br />
&nbsp; &nbsp; GLboolean enabled<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres <em>source</em>, <em>type</em> et <em>severity</em> prennent l&rsquo;une des valeurs décrites au-dessus (GL_DEBUG_SOURCE_API, GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_SOURCE_APPLICATION ou GL_DEBUG_SOURCE_OTHER pour <em>source</em>, GL_DEBUG_TYPE_ERROR, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DEBUG_TYPE_PORTABILITY, GL_DEBUG_TYPE_PERFORMANCE ou GL_DEBUG_TYPE_OTHER pour <em>type</em> et GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_MEDIUM ou GL_DEBUG_SEVERITY_HIGH pour <em>severity</em>) ou GL_DONT_CARE pour ne pas prendre en compte le paramètre.</p>
<p>Le paramètre <em>ids</em> permet de donner un tableau d&rsquo;identifiants de taille <em>count</em>. Si le paramètre <em>count</em> est supérieur à 0, alors le filtre s&rsquo;applique aux messages dont les identifiants correspondent aux valeurs données dans le tableau <em>ids</em>. Dans ce cas, les paramètres <em>source</em> et <em>type</em> ne doivent pas être GL_DONT_CARE et <em>severity</em> doit être GL_DONT_CARE.</p>
<p>Le paramètre <em>enabled</em> permet de préciser si le filtre supprime les messages correspondant aux critères (GL_FALSE) ou les garde (GL_TRUE).</p>
<p>Par exemple, pour garder tous les messages :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glDebugMessageControl<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Par exemple, pour ne garder que les messages importants :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glDebugMessageControl<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour désactiver les messages correspondant à l&rsquo;appel de fonctions dépréciées :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DONT_CARE, &nbsp;<br />
&nbsp; &nbsp; GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, GL_DONT_CARE, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; GL_FALSE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour ne garder que les messages correspondant à une liste d&rsquo;identifiants donnés :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">// on supprime tous les messages </span><br />
glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, <br />
&nbsp; &nbsp; <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, FALSE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// on ne garde ensuite que les messages possédant les identifiants 1280 ou 1282 </span><br />
GLuintid<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">1280</span>, <span style="color: #0000dd;">1282</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> <br />
glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DEBUG_SOURCE_API_ARB, &nbsp;<br />
&nbsp; &nbsp; GL_DEBUG_TYPE_ERROR_ARB, GL_DONT_CARE, <span style="color: #0000dd;">2</span>, id, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction GLDebugMessageControl peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : utilisation d&rsquo;une valeur incorrecte pour <em>source</em>, <em>type</em> ou <em>severity</em> ;</li>
<li>INVALID_VALUE : <em>count</em> est négatif ;</li>
<li>INVALID_OPERATION : <em>count</em> est positif, mais <em>source</em> ou <em>type</em> valent DONT_CARE ou severity ne vaut pas DONT_CARE.</li>
</ul>
<p>Pour éviter d&rsquo;avoir à écrire deux codes, pour les versions debug et release, il est possible de créer une macro définissant ou non une fonction appelant les filtres :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#ifdef OPENGL_DEBUG </span><br />
&nbsp; &nbsp; <span style="color: #339900;">#define GLDebugMessageControl(source, type, sev, num, id, enabled) \\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDebugMessageControlARB<span style="color: #008000;">&#40;</span>source, type, sev, num, id, enabled<span style="color: #008000;">&#41;</span> <br />
<span style="color: #339900;">#else </span><br />
&nbsp; &nbsp; <span style="color: #339900;">#define GLDebugMessageControl(source, type, sev, num, id, enabled) </span><br />
<span style="color: #339900;">#endif</span></div></td></tr></tbody></table></div>
<h1>Les fonctions callback (GL 4.1)</h1>
<p>Une autre possibilité pour récupérer les messages est de créer une fonction callback qui sera appelée dès qu&rsquo;un message est lancé. Les messages ne sont alors plus mis dans la pile et ne peuvent être lus avec <em>glGetDebugMessageLog</em>. Par contre, les filtres ajoutés avec <em>GLDebugMessageControl</em> continuent de fonctionner.</p>
<p>Une fonction callback doit avoir la signature suivante :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span>APIENTRY <span style="color: #000040;">*</span>DEBUGPROC<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>GLenum source, GLenum type, GLuint id, GLenum severity, &nbsp;<br />
&nbsp; &nbsp; GLsizei length, <span style="color: #0000ff;">const</span> GLchar<span style="color: #000040;">*</span> message, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres <em>source</em>, <em>type</em>, <em>id</em>, <em>severity</em> et <em>message</em> correspondent aux paramètres des messages comme décrit au-dessus. Le paramètre <em>length</em> est la taille de la chaîne de caractères <em>message</em>. La mémoire allouée pour le paramètre <em>message</em> est gérée directement par OpenGL. Sa portée correspond à la fonction callback, donc il est nécessaire de copier le message si on souhaite l&rsquo;utiliser en dehors de la fonction. Le paramètre <em>userParam</em> est un pointeur vers des données pouvant être utilisées dans le corps de la fonction et passées lorsque l&rsquo;on attache la fonction callback à un contexte.</p>
<p>Elle ne doit pas appeler de fonction OpenGL ou du système de fenêtrage. Cette fonction est appelée par un thread différent du thread appelant la fonction GL, il faut donc faire particulièrement attention au respect du thread-safe.<br />
Lorsque l&rsquo;on travaille avec plusieurs contextes OpenGL, il faut fournir une fonction callback pour chaque contexte pour lesquels on souhaite capturer les messages. Dans une application multithread, il est possible d&rsquo;avoir une fonction callback sur un contexte appelé par plusieurs threads différents, mais l&rsquo;application est responsable du respect du thread-safe.</p>
<p>Par exemple, la fonction suivante permet d&rsquo;afficher dans la console les informations des messages reçus.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> DebugLog<span style="color: #008000;">&#40;</span>GLenumsource, GLenumtype, GLuintid, GLenumseverity, &nbsp;<br />
&nbsp; &nbsp; GLsizeilength, constGLchar<span style="color: #000040;">*</span>message, GLvoid<span style="color: #000040;">*</span>userParam<span style="color: #008000;">&#41;</span> <br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Message reçu :<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>source<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_API <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_API<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_WINDOW_SYSTEM <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_WINDOW_SYSTEM<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_SHADER_COMPILER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_SHADER_COMPILER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_THIRD_PARTY <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_THIRD_PARTY<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_APPLICATION <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_APPLICATION<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_OTHER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_OTHER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source inconnue<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>type<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_ERROR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_ERROR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_PORTABILITY <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_PORTABILITY<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_PERFORMANCE <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_PERFORMANCE<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_OTHER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_OTHER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type inconnu<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>severity<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_LOW <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_LOW<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_MEDIUM <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_MEDIUM<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_HIGH <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_HIGH<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type inconnu<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Message : %s<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageCallback.xml">glDebugMessageCallback</a> permet d&rsquo;attacher une fonction callback à un contexte. Elle prend en paramètre la fonction callback et un pointeur vers des données utilisateurs. Sa signature est la suivante :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glDebugMessageCallback<span style="color: #008000;">&#40;</span>DEBUGPROC callback, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le code d&rsquo;exemple suivant présente comment attacher une fonction callback et modifier les données utilisateurs entre deux messages.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> myData<span style="color: #008080;">;</span> <br />
glDebugMessageCallbackARB<span style="color: #008000;">&#40;</span>DebugLog, <span style="color: #000040;">&amp;</span>myData<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
myData <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <br />
glEnable<span style="color: #008000;">&#40;</span>GL_UNIFORM_BUFFER<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// erreur </span><br />
&nbsp;<br />
myData<span style="color: #000080;">=</span><span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <br />
glPolygonMode<span style="color: #008000;">&#40;</span>GL_FRONT, GL_LINE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// erreur</span></div></td></tr></tbody></table></div>
<p>Pour supprimer une fonction callback, il suffit d&rsquo;appeler <em>glDebugMessageCallback</em> avec des valeurs nulles ;</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glDebugMessageCallback<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetPointerv.xml">glGetPointerv</a> permet de récupérer la fonction callback en utilisant le paramètre GL_DEBUG_CALLBACK_FUNCTION et les données <em>userParam</em> avec GL_DEBUG_CALLBACK_USER_PARAM :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>callback<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>GLenum, GLenum, GLuint, GLenum, GLsizei, <span style="color: #0000ff;">const</span> GLchar<span style="color: #000040;">*</span>, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetPointerv<span style="color: #008000;">&#40;</span>GL_DEBUG_CALLBACK_FUNCTION, <span style="color: #008000;">&#40;</span>GLvoid <span style="color: #000040;">**</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;</span>callback<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008080;">;</span> <br />
glGetPointerv<span style="color: #008000;">&#40;</span>GL_DEBUG_CALLBACK_USER_PARAM, <span style="color: #008000;">&#40;</span>GLvoid <span style="color: #000040;">**</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;</span>userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les annotations de débogage (GL 4.3)</h1>
<p>Un des problèmes que l&rsquo;on peut rencontrer lorsque l&rsquo;on débogue une application est de savoir quels objets provoquent une erreur. Il est nécessaire alors de garder une table contenant les identifiants des objets. Dans OpenGL 4.3 a été ajouté les annotations de débogage (debug label), qui permettent d&rsquo;attacher une chaîne de caractères à n&rsquo;importe quel objet OpenGL grâce à la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glObjectLabel.xml">glObjectLabel</a> :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glObjectLabel<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">enum</span> identifier, uint name, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le paramètre <em>name</em> correspond au numéro retourné par les fonctions create. Le paramètre identifier indique le type d&rsquo;objet correspondant à name. Il peut prendre les valeurs suivantes :</p>
<ul>
<li>BUFFER</li>
<li>FRAMEBUFFER</li>
<li>PROGRAM_PIPELINE</li>
<li>PROGRAM</li>
<li>QUERY</li>
<li>RENDERBUFFER</li>
<li>SAMPLER</li>
<li>SHADER</li>
<li>TEXTURE</li>
<li>TRANSFORM_FEEDBACK</li>
<li>VERTEX_ARRAY</li>
</ul>
<p>La fonction <em>glObjectLabel</em> peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si <em>identifier</em> n&rsquo;est pas une valeur valide ;</li>
<li>INVALID_VALUE : si <em>name</em> ne correspond pas à un objet valide de type <em>identifier</em> ;</li>
<li>INVALID_VALUE : si la taille de la chaîne de caractères <em>label</em> est plus grande que MAX_LABEL_LENGTH.</li>
</ul>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetObjectLabel.xml">glGetObjectLabel</a> permet de récupérer l&rsquo;annotation associée avec un objet identifié par <em>identifier</em> et <em>name</em> :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glGetObjectLabel<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">enum</span> identifier, uint name, sizei bufSize, sizei <span style="color: #000040;">*</span>length, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Cette fonction peut retourner les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si <em>identifier</em> ne correspond pas à un type d&rsquo;objet valide ou si name ne correspond pas à un objet valide de type donné ;</li>
<li>INVALID_VALUE : si <em>bufSize</em> est négatif.</li>
</ul>
<p>En plus de la fonction <em>glObjectLabel</em>, la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glObjectPtrLabel.xml">glObjectPtrLabel</a> permet d&rsquo;annoter un objet de synchronisation (un objet de synchronisation permet de tester si des commandes OpenGL sont en cours ou terminées ; voir le chapitre 4 &#8211; Event model des spécifications d&rsquo;OpenGL 4.3 pour plus de détails).</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glObjectPtrLabel<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>ptr, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction glObjectPtrLabel peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_VALUE : si <em>ptr</em> ne correspond pas à un objet de synchronisation valide ;</li>
<li>INVALID_VALUE : si la taille de la chaîne de caractères <em>label</em> est plus grande que MAX_LABEL_LENGTH.</li>
</ul>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetObjectPtrLabel.xml">glGetObjectPtrLabel</a> permet de récupérer le label d&rsquo;un objet de synchronisation :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glGetObjectPtrLabel<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>ptr, sizei bufSize, size <span style="color: #000040;">*</span>length, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les groupes de débogage (GL 4.3)</h1>
<p>Les groupes permettent d&rsquo;annoter un ensemble de fonctions OpenGL. Un message GL_DEBUG_TYPE_PUSH_GROUP est envoyé lorsque l&rsquo;on entre dans le groupe puis GL_DEBUG_TYPE_POP_GROUP lorsque l&rsquo;on sort. Il est également possible d&rsquo;utiliser plusieurs groupes, qui seront alors hiérarchisés dans une pile de groupes. Les filtres appliqués sont actifs sur le groupe courant et les groupes qui seront inclus dans ce groupe. Au démarrage, la pile contient un groupe par défaut. Ce système permet ainsi de retrouver plus facilement l&rsquo;origine des messages. </p>
<p>Les fonctions <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glPushDebugGroup.xml">glPushDebugGroup</a> et <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glPopDebugGroup.xml">glPopDebugGroup</a> permettent de débuter et finir un groupe.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> glPushDebugGroup<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">enum</span> source, uint id, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000ff;">void</span> glPopDebugGroup<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le message généré contient la chaîne de caractères <em>message</em>, l&rsquo;identifiant <em>id</em>, le type sera DEBUG_TYPE_PUSH_GROUP ou DEBUG_TYPE_POP_GROUP, la source devra être GL_DEBUG_SOURCE_APPLICATION ou GL_DEBUG_SOURCE_THIRD_PARTY et <em>severity</em> sera GL_DEBUG_SEVERITY_NOTIFICATION.</p>
<p>La fonction <em>glPushDebugGroup</em> peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si la source ne correspond pas à DEBUG_SOURCE_APPLICATION ou DEBUG_SOURCE_THIRD_PARTY ;</li>
<li>INVALID_VALUE : si la taille de <em>message</em> est supérieure à MAX_DEBUG_MESSAGE_LENGTH ;</li>
<li>STACK_OVERFLOW : si le nombre de groupes dépasse MAX_DEBUG_GROUP_STACK_DEPTH &#8211; 1.</li>
</ul>
<p>La fonction <em>glPopDebugGroup</em> peut générer une erreur STACK_UNDERFLOW si la pile de groupes ne contient que le groupe par défaut.</p>
<h1>Notes sur les implémentations</h1>
<p>Les situations pouvant générer des messages et le contenu de ces messages sont laissés à l&rsquo;appréciation des implémentations. On observe donc des différences de comportement entre les différentes implémentations.<br />
Pour le moment, la taille de la pile semble être de 128 messages et la taille des messages au maximum de 1024 octets chez AMD et NVIDIA.</p>
<p><em>Exemples de situations et de message générés</em></p>
<p>Lorsque l&rsquo;on attache un tampon mémoire sur un objet ne correspondant pas à un tampon, NVIDIA ne donne aucun message alors que AMD retourne un message signalant une fonction dépréciée :</p>
<blockquote><p>glBindBuffer in a Core context performing invalid operation<br />
with parameter &laquo;&nbsp;name&nbsp;&raquo; set to &lsquo;0x5&prime; which was removed<br />
from Core OpenGL (GL_INVALID_OPERATION)</p></blockquote>
<p>Lorsque l&rsquo;on appelle une fonction dépréciée ou avec une combinaison dépréciée de paramètres, par exemple <em>glPolygonMode(GL_FRONT, GL_LINE)</em>, NVIDIA et AMD retournent une erreur GL_INVALID_ENUM :</p>
<blockquote><p>// NVIDIA<br />
GL_INVALID_ENUM error generated. Polygonmodes for &laquo;&nbsp;face&nbsp;&raquo; are<br />
disabled in the current profile.<br />
// AMD<br />
Using glPolygonMode in a Core context with parameter<br />
&laquo;&nbsp;face&nbsp;&raquo; and enum &lsquo;0x404&prime; which was removed from<br />
Core OpenGL (GL_INVALID_ENUM)     </p></blockquote>
<p>Les messages peuvent également servir lorsqu&rsquo;il n&rsquo;y a pas d&rsquo;erreur, par exemple pour faire le suivi des appels de fonction. Par exemple, lorsque l&rsquo;on attache un tampon mémoire et que les données sont correctement envoyées, NVIDIA lance le message suivant en GL_DEBUG_SEVERITY_LOW alors que AMD ne lance rien.</p>
<blockquote><p>Buffer detailed info: Buffer object 3 (bound to<br />
GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint<br />
is GL_ENUM_88e4) will use VIDEO memory as<br />
the source for buffer object operations.</p></blockquote>
<p>Lorsqu&rsquo;on appelle la fonction glDrawElement pour lancer un rendu alors que la mémoire graphique est pleine, NVIDIA va générer le message suivant :</p>
<blockquote><p>Unknown internal debug message . The NVIDIA<br />
OpenGL driver has encountered an out of memory<br />
error. This application might behave inconsistently and fail.</p></blockquote>
<p>Pour terminer, une situation posant des problèmes de performance. Lorsque l&rsquo;on utilise un nombre important de Vertex Array Object de petites tailles, NVIDIA lancera un message signalant une perte de performance alors que AMD ne donne aucun message.</p>
<h1>Sources et remerciements</h1>
<p>Certains exemples (en particulier les messages d&rsquo;erreurs générés dans certaines situations) proviennent du livre <a href="http://openglinsights.com/">OpenGL Insight</a> de Patrick Cozzi et Christophe Riccio, dont certains chapitres sont accessibles gratuitement sur le site du livre. Merci également à Christophe Riccio pour ses revues des spécifications d&rsquo;OpenGL qu&rsquo;il publie sur <a href="http://www.g-truc.net/">g-truc</a>. Vous pouvez également consulter les <a href="http://www.opengl.org/registry/doc/glspec43.core.20120806.pdf">spécifications d&rsquo;OpenGL 4.3</a>, en particulier le chapitre consacré au débogage : &laquo;&nbsp;Chapter 20 &#8211; Debug Output&nbsp;&raquo;.<br />
Merci à <a href="http://www.developpez.net/forums/u283256/f-leb/">f-leb</a> pour sa relecture orthographique.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL dans Qt5</title>
		<link>https://blog.developpez.com/gpu/?p=11</link>
		<comments>https://blog.developpez.com/gpu/?p=11#comments</comments>
		<pubDate>Tue, 29 May 2012 08:55:39 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le support d&#8217;OpenGL dans Qt5 a été modifié pour mieux l&#8217;intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt5. OpenGL dans Qt4 Dans Qt4, les fonctionnalités d&#8217;OpenGL sont implémentées dans &#8230; <a href="https://blog.developpez.com/gpu/?p=11">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Le support d&rsquo;OpenGL dans Qt5 a été modifié pour mieux l&rsquo;intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt5.<br />
<span id="more-11"></span><br />
<strong><em>OpenGL dans Qt4</em></strong></p>
<p>Dans Qt4, les fonctionnalités d&rsquo;OpenGL sont implémentées dans un module spécifique, QtOpenGL. Ce module était utilisé par différentes classes pour bénéficier de l’accélération matérielle. Il existe plusieurs méthodes pour activer l&rsquo;accélération matérielle :</p>
<ul>
<li>pour activer par défaut l&rsquo;utilisation de OpenGL, utiliser la ligne de commande &laquo;&nbsp;-graphicssystem opengl&nbsp;&raquo; ou la fonction QApplication::setGraphicsSystem(&laquo;&nbsp;opengl&nbsp;&raquo;) ;</li>
<li>pour QGraphicsView (QtGraphics) ou QDeclarativeView (QtQuick), utiliser la fonction setViewport(new QGLWidget) ;</li>
<li>on peut également utiliser QPainter directement sur un QGLWidget ;</li>
<li>avec le QML Viewer, utilisez la commande &laquo;&nbsp;-opengl&nbsp;&raquo;.</li>
</ul>
<p><em><strong>L&rsquo;organisation des modules</strong></em><br />
Dans Qt4, on a donc un problème dans l&rsquo;organisation des modules. Beaucoup de classes de QtGui peuvent dépendre des classes appartenant à QtOpenGL alors que ce module dépend normalement de QtGui.<br />
C&rsquo;est pour cela que de nouvelles classes font leur apparition dans Qt5 et que les différents modules ont été réorganisés :</p>
<ul>
<li>les classes QOpenGL appartiennent au module QtGui et fournissent les fonctionnalités de base permettant l’accélération matérielle pour toute les classes de rendu de Qt ;</li>
<li>la classe QWidget n&rsquo;est plus le parent de toutes les classes de rendu. Cette classe et ses dérivées (QGraphicsView) sont transférées dans le module &laquo;&nbsp;widgets&nbsp;&raquo; ;</li>
<li>QtQuick 2 utilise maintenant scenegraph à la place de QWidget et la classe QDeclarativeView devient QQuickView et OpenGL est utilisé par défaut ;</li>
<li>QtOpenGL continue d&rsquo;exister pour fournir la classe QGLWidget et ses dérivés. Le code OpenGL Qt4 est donc compatible avec Qt5 ;</li>
<li>le module Qt3d fait son apparition pour fournir un moteur 3D plus avancé. Ce module est suffisamment important et fera donc l&rsquo;objet d&rsquo;un article spécifique.</li>
</ul>
<p>Remarque : il faut faire attention de ne pas confondre le module QtOpenGL, contenant les classes commençant par QGL, et le module QtGui, contenant les classes commençant par QOpenGL (sans t).</p>
<p><strong><em>Les classes de QtGui dans Qt5</em></strong><br />
Le module QtGui de Qt5 réutilise des classes existantes du module QtOpenGL de Qt4. Les noms sont explicites :</p>
<ol>
<li>QOpenGLBuffer ;</li>
<li>QOpenGLContext ;</li>
<li>QOpenGLFramebufferObject ;</li>
<li>QOpenGLFramebufferObjectFormat ;</li>
<li>QOpenGLShader ;</li>
<li>QOpenGLShaderProgram.</li>
</ol>
<p>Plusieurs nouvelles classes font leur apparition :</p>
<ol>
<li>QOpenGLContextGroup : groupe de contextes OpenGL pouvant partager des ressources. Cette classe est gérée automatiquement par les objets QOpenGLContext ;</li>
<li>QOpenGLFunctions : fournit un accès indépendant de la plateforme aux fonctions d&rsquo;OpenGL ;</li>
<li>QOpenGLPaintDevice : permet de dessiner dans un contexte OpenGL avec QPainter ;</li>
<li>QOpenGLStaticContext : manque de documentation ;</li>
<li>QOpenGLContextData : manque de documentation ;</li>
<li>QWindowsGLContext : manque de documentation.</li>
</ol>
<p><strong><em>Que faut-il modifier pour utiliser OpenGL dans Qt5</em></strong><br />
Tout d&rsquo;abord, il faut Qt5. Le plus simple est d&rsquo;utiliser les dépôts PPA sur Ubuntu : https://launchpad.net/~forumnokia/+archive/fn-ppa. Qt5 sera installé dans le répertoire /opt/qt5. Pour ajouter cette version de Qt dans QtCreator, il faut aller dans le menu &laquo;&nbsp;Outils&nbsp;&raquo; puis &laquo;&nbsp;Options…&nbsp;&raquo;, allez dans &laquo;&nbsp;Compiler et exécuter…&nbsp;&raquo; puis l&rsquo;onglet &laquo;&nbsp;Versions de Qt&nbsp;&raquo;. Cliquer sur &laquo;&nbsp;Ajouter&nbsp;&raquo; et aller chercher le fichier &laquo;&nbsp;/opt/qt5/bin/qmake&nbsp;&raquo;. Voilà, Qt5 est prêt à être utilisé.</p>
<p>Normalement, vous pouvez utiliser vos projets directement, mais il est préférable de prendre l&rsquo;habitude d&rsquo;ajouter le module &laquo;&nbsp;widgets&nbsp;&raquo; (remarque : l&rsquo;ajout des modules core et gui n&rsquo;est pas obligatoire puisqu&rsquo;ils sont inclus par défaut) :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QT += core gui opengl <br />
greaterThan(QT_MAJOR_VERSION, 4) { <br />
&nbsp; &nbsp; QT += widgets <br />
}</div></td></tr></tbody></table></div>
<p>Amusez-vous bien !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introduction aux geometry shaders</title>
		<link>https://blog.developpez.com/gpu/?p=1</link>
		<comments>https://blog.developpez.com/gpu/?p=1#comments</comments>
		<pubDate>Thu, 12 Apr 2012 08:14:02 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Geometry shaders]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[A la demande de LittleWhite, mon premier bloc technique est consacré à l&#8217;utilisation des geometry shader. Il n&#8217;y a rien de tres compliqué donc je présente un exemple simple apres quelques rappels. Pour ceux qui ne connaissent pas du tout &#8230; <a href="https://blog.developpez.com/gpu/?p=1">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A la demande de LittleWhite, mon premier bloc technique est consacré à l&rsquo;utilisation des geometry shader. Il n&rsquo;y a rien de tres compliqué donc je présente un exemple simple apres quelques rappels. Pour ceux qui ne connaissent pas du tout les geometry shaders, je ferais un article plus detaille sur ce sujet.<br />
Pour faire au plus simple, j&rsquo;utilise Qt et en particulier QShaderProgram, qui gère les geometry shaders depuis Qt 4.7.<br />
<span id="more-1"></span></p>
<p><em><strong>Quelques rappels</strong></em><br />
Les geometry shaders sont optionnels et s&rsquo;intercalent entre les vertex shaders et les fragment shaders. Ils travaillent sur des primitives (triangle, ligne, points, avec un maximum de 6 vertices) et permettent de générer d&rsquo;autres primitives. Ils sont disponibles dans le Core depuis OpenGL 3.2 / GLSL 1.5 ou avant avec l&rsquo;extension GL_ARB_geometry_shader4 (en ajoutant le code #extension GL_EXT_geometry_shader4 : enable dans le geometry shader).</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #666666;">// Rechercher la présence de GL_EXT_geometry_shader4 pour &nbsp; </span><br />
&nbsp; &nbsp; <span style="color: #666666;">// tester si les geometry shaderssont pris en charge </span><br />
&nbsp; &nbsp; glGetString<span style="color: #008000;">&#40;</span>GL_EXTENSIONS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; glGetStringi<span style="color: #008000;">&#40;</span>GL_EXTENSIONS, i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GL 3.2 </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Créer un geometry shader </span><br />
&nbsp; &nbsp; glCreateShader<span style="color: #008000;">&#40;</span>GL_GEOMETRY_SHADER<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; QGLShader shader<span style="color: #008000;">&#40;</span>QGLShader<span style="color: #008080;">::</span><span style="color: #007788;">Geometry</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// Qt 4.7 </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Gérer les informations de position </span><br />
&nbsp; &nbsp; gl_PositionIn<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// position du vertex i en entrée </span><br />
&nbsp; &nbsp; gl_Position<span style="color: #008080;">;</span> <span style="color: #666666;">// position du nouveau vertex émis </span><br />
&nbsp; &nbsp; gl_in<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span>.<span style="color: #007788;">gl_Position</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GLSL &gt; 330 </span><br />
&nbsp; &nbsp; gl_in.<span style="color: #007788;">length</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GLSL &gt; 330, nombre de vertices en entrée </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Générer des vertices et primitives (GLSL) </span><br />
&nbsp; &nbsp; EmitVertex<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; EndPrimitive<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Spécifier le type de primitives en entrée et sortie </span><br />
&nbsp; &nbsp; <span style="color: #666666;">// (GLSL) </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>triangles<span style="color: #008000;">&#41;</span> in<span style="color: #008080;">;</span> <span style="color: #666666;">// points, lines, triangles, lines_adjacency ou triangles_adjacency </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>triangle_strip<span style="color: #008000;">&#41;</span> out<span style="color: #008080;">;</span> <span style="color: #666666;">// points, line_strip ou triangle_strip </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>max_vertices <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span> out<span style="color: #008080;">;</span> <span style="color: #666666;">// maximum = GL_MAX_GEOMETRY_OUTPUT_VERTICES </span><br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// (Qt) </span><br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryInputType</span><span style="color: #008000;">&#40;</span>GL_TRIANGLES<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryOutputType</span><span style="color: #008000;">&#40;</span>GL_LINE_STRIP<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryOutputVertexCount</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">6</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Lors de l&rsquo;appel à glDrawArray ou glDrawElement, il faut que le type spécifié corresponde au type d&rsquo;entrée du geometry shader. Les correspondances autorisées sont :</p>
<ol>
<li>points : GL_POINTS</li>
<li>lines : GL_LINES, GL_LINE_LOOP ou GL_LINE_STRIP</li>
<li>triangles : GL_TRIANGLES, GL_TRIANGLE_FAN ou GL_TRIANGLE_STRIP</li>
<li>lines_adjacency : GL_LINES_ADJACENCY</li>
<li>triangles_adjacency : GL_TRIANGLES_ADJACENCY</li>
</ol>
<p>Les nouveaux types ADJACENCY (GL_LINES_ADJACENCY, GL_LINE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY et GL_TRIANGLE_STRIP_ADJACENCY) permettent d&rsquo;accéder aux vertices des primitives voisines de la primitive en cours de traitement.</p>
<p><img src="http://gbelz.developpez.com/blog/geometry-shader.png" alt="Exemple d'affichage des vecteurs normaux" title="Exemple d'affichage des vecteurs normaux" /></p>
<p><strong><em>Un exemple simple</em></strong><br />
L&rsquo;exemple choisit est tres tres classique. Il permet d&rsquo;afficher le mailage d&rsquo;un mesh, les vecteurs normaux des faces et de calculer les vecteurs normaux de chaque face (flat mode). Cet exemple me permet également d&rsquo;introduire quelques classes simples, pour lire un fichier .obj (version simplifiee), calculer les vecteurs normaux, initialiser un contexte GL avec Qt.</p>
<p>Pour l&rsquo;affichage des vecteurs normaux et des triangles, on a besoin des positions et des normales, que l&rsquo;on passent donc aux shaders en attributs. </p>
<p>Pour afficher les vecteurs normaux dans le geometry shader, on prend un seul vertex en entree (input = points) et l&rsquo;on retourne une ligne (output = lignes, size = 2), dont le premier point est la position du vertex et le second point est la position du vertex auquel on ajoute le vecteur normal (multiplie par une constante, passee comme uniform, pour modifier la longueur du vecteur)</p>
<p>Pour afficher les triangles, on recupere un triangle en entree (input = triangles) et l&rsquo;on retourne 3 lignes (output = lignes, size = 6). Chaque points correspond a la position d&rsquo;un vertex decale legerement par le vecteur normal (pour que les lignes soient bien visibles et ne soient pas cachees par les triangles).</p>
<p><a href="http://gbelz.developpez.com/blog/geometry-shader.zip">Télécharger le projet d&rsquo;exemple</a></p>
<p><strong><em>A suivre&#8230;</em></strong></p>
<ol>
<li><a href="http://www.google.fr/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=4&amp;cts=1331312136494&amp;ved=0CEwQFjAD&amp;url=http%3A%2F%2Fweb.engr.oregonstate.edu%2F~mjb%2Fcs519%2FHandouts%2Fgeometry_shaders.1pp.pdf&amp;ei=ATZaT6zoFIiz8QPy3IXPDg&amp;usg=AFQjCNG9d-4Lpr0TbpuvK0iQrvmRVXKaMw&amp;sig2=zf5Oc9N-aIUMtgqDR-FXqw">Shrink, explosion, subdivision, silhouette, hedgehog</a></li>
<li><a href="http://www.twodee.org/blog/?p=805">Explosion, cheveux</a></li>
<li><a href="http://bat710.univ-lyon1.fr/~jpfarrug/Geometry.pdf">Instanciation et culling</a></li>
<li><a href="http://bat710.univ-lyon1.fr/~jciehl/Public/educ/M2PROIMA/2011/opengl_cm4.pdf">Instanciation et culling</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>La technique d&#8217;instanciation</title>
		<link>https://blog.developpez.com/gpu/?p=3</link>
		<comments>https://blog.developpez.com/gpu/?p=3#comments</comments>
		<pubDate>Wed, 11 Apr 2012 12:01:48 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Instanciation]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[L&#8217;instanciation est une technique permettant de dessiner plusieurs copies du même objet. Cette technique sera intéressante dans des scènes contenant des objets similaires : une forêt d&#8217;arbre, le feuillage d&#8217;un arbre, une foule, l&#8217;herbe d&#8217;une pelouse. L&#8217;instanciation Lorsque l&#8217;on souhaite &#8230; <a href="https://blog.developpez.com/gpu/?p=3">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>L&rsquo;instanciation est une technique permettant de dessiner plusieurs copies du même objet. Cette technique sera intéressante dans des scènes contenant des objets similaires : une forêt d&rsquo;arbre, le feuillage d&rsquo;un arbre, une foule, l&rsquo;herbe d&rsquo;une pelouse.<br />
<span id="more-3"></span></p>
<p><strong><em>L&rsquo;instanciation</em></strong><br />
Lorsque l&rsquo;on souhaite afficher de nombreux objets, la première approche pourrait être de faire plusieurs appels à glDrawArrays et glDrawElements. Le nombre d&rsquo;appels aux fonctions de dessin peut cependant diminuer fortement les performances. Une optimisation possible est d&rsquo;utiliser glMultiDrawArrays ou glMultiDrawElements, qui prennent des tableaux de données et permettent donc de faire qu&rsquo;un seul appel. Cependant, il est nécessaire d&rsquo;envoyer les données correspondantes à tous les objets que l&rsquo;on souhaite créer, ce qui peut saturer la bande passante du GPU.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #666666;">// Extension GL_ARB_draw_instanced pour DrawArraysInstanced() et glDrawElementsInstanced() </span><br />
&nbsp; &nbsp; <span style="color: #666666;">// Extension GL_ARB_instanced_arrays pour VertexAttribDivisor() </span><br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Pour dessiner plusieurs objets </span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> glMultiDrawArrays<span style="color: #008000;">&#40;</span>GLenum mode, GLint <span style="color: #000040;">*</span>first, GLsizei <span style="color: #000040;">*</span>count, GLsizei primcount<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> glMultiDrawElements<span style="color: #008000;">&#40;</span>GLenum mode, GLsizei <span style="color: #000040;">*</span>count, GLenum type, GLvoid <span style="color: #000040;">**</span>indices, GLsizei primcount<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>L&rsquo;instanciation proprement dite permet de créer plusieurs instances d&rsquo;un objet. On envoie les données que pour un seul objet, ce qui réduit la bande passante.</p>
<p>Pour personnaliser chaque instance, on fournit un tableau de données (Instanced Array), chaque élément du tableau correspondant à une instance. On pourra passer ainsi modifier la position des instances, les paramètres de texture pour personnaliser les instances, ajouter du bruit, etc. Le paramètre <em>divisor</em> permet de spécifier quand on passe à l&rsquo;élément suivant dans un buffer. Pour <em>divisor</em> = 0, chaque vertex lit un nouvel élément dans le buffer. Avec <em>divisor</em> = 1, chaque instance lit un nouvel élément. Avec <em>divisor</em> = 2, un nouvel élément est lu toutes les 2 instances, etc.</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; // Création de plusieurs instances d'un objet <br />
&nbsp; &nbsp; void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount); <br />
&nbsp; &nbsp; void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); <br />
&nbsp;<br />
&nbsp; &nbsp; // Pour connaître l'identifiant de l'instance (GLSL) <br />
&nbsp; &nbsp; gl_InstanceID; // entre 0 et primcount-1 <br />
&nbsp;<br />
&nbsp; &nbsp; // Définir le mode de lecture des buffers <br />
&nbsp; &nbsp;glVertexAttribDivisor(location, divisor)</div></td></tr></tbody></table></div>
<p><em><strong>Un exemple simple</strong></em><br />
Le code d&rsquo;exemple affiche des cubes en utilisant glDrawElementsInstanced. Le curseur permet de sélectionner le nombre d&rsquo;instances à créer. Le bouton permet de basculer entre la vue des cubes pleins et en fil de fer. Les FPS et le nombre d&rsquo;instances sont indiqués dans le titre de la fenêtre. Je peux obtenir plus de 10 000 instances en même temps à 30 FPS (soit plus de 120 000 triangles) sur mon portable équipé d&rsquo;une 8600M GT.</p>
<p>Pour ceux qui testeraient avec du matériel plus puissant, il est possible d&rsquo;augmenter le nombre d&rsquo;instance maximal en modifiant le facteur multiplicateur à la ligne 127 du fichier glwidget.cpp ou la valeur maximale du QSlider à la ligne 22 du fichier mainwindow.cpp. J&rsquo;ai pu ainsi créer plus de 400 000 instances (4,8 millions de triangles) avant d&rsquo;arriver à 30 FPS sur une tour équipée d&rsquo;une GTX 460.</p>
<p><img src="http://gbelz.developpez.com/blog/instanciation.png" alt="Exemple d'affichage des cubes pleins (en haut) et en fil de fer (en bas)" title="Exemple d'affichage des cubes pleins (en haut) et en fil de fer (en bas)" /></p>
<p><a href="http://gbelz.developpez.com/blog/instanciation.zip">Télécharger le projet d&rsquo;exemple</a></p>
<p><em><strong>Au suivre&#8230;</strong></em><br />
* <a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch07.html">gpu gems chap 7</a><br />
* <a href="http://sol.gfxile.net/instancing.html">http://sol.gfxile.net/instancing.html</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les queries objects</title>
		<link>https://blog.developpez.com/gpu/?p=5</link>
		<comments>https://blog.developpez.com/gpu/?p=5#comments</comments>
		<pubDate>Mon, 02 Apr 2012 11:10:51 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Query object]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Les queries objects permettent d&#8217;interroger OpenGL pour obtenir des informations à propos des traitements effectués. Par exemple, les queries objects permetttent de récupérer les nombres d&#8217;instances/primitives restant après un occlusion culling dans un geometry shader. On utilise également des tableaux &#8230; <a href="https://blog.developpez.com/gpu/?p=5">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Les queries objects permettent d&rsquo;interroger OpenGL pour obtenir des informations à propos des traitements effectués. Par exemple, les queries objects permetttent de récupérer les nombres d&rsquo;instances/primitives restant après un occlusion culling dans un geometry shader. On utilise également des tableaux de queries objects pour tester chaque rendu et la technique de conditional rendering pour faire les tests de culling directement sur le GPU.<br />
<span id="more-5"></span></p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp;<span style="color: #666666;">// Pour créer des queries objects </span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">void</span> glGenQueries<span style="color: #008000;">&#40;</span>GLsizei n, GLuint <span style="color: #000040;">*</span>ids<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;GLuint query<span style="color: #008080;">;</span> <br />
&nbsp; &nbsp;GLuint queries_array<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp;glGenQueries<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, <span style="color: #000040;">&amp;</span>query<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp;glGenQueries<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span>, query_array<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #666666;">// Détruire des queries objects </span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">void</span> glDeleteQueries<span style="color: #008000;">&#40;</span>GLsizei n, <span style="color: #0000ff;">const</span> GLuint <span style="color: #000040;">*</span>ids<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;glDeleteQueries<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, <span style="color: #000040;">&amp;</span>query<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp;glDeleteQueries<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span>, query_array<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #666666;">// Lancer la query </span><br />
&nbsp; &nbsp;glBeginQuery<span style="color: #008000;">&#40;</span>GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_SAMPLES_PASSED : nombre de pixels écris </span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_ANY_SAMPLES_PASSED : true si au moins 1 pixel écris (GL &gt;= 3.3) </span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_PRIMITIVES_GENERATED </span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN &nbsp;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_TIME_ELAPSED : temps d'exécution en nanosecondes </span><br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #666666;">// Arrêter la query </span><br />
&nbsp; &nbsp;glEndQuery<span style="color: #008000;">&#40;</span>GL_SAMPLES_PASSED<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #666666;">// Récupérer le résultat de la query </span><br />
&nbsp; &nbsp;glGetQueryObjectuiv<span style="color: #008000;">&#40;</span>query, GL_QUERY_RESULT_AVAILABLE, <span style="color: #000040;">&amp;</span>result<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp;glGetQueryObject<span style="color: #008000;">&#40;</span>query, GL_QUERY_RESULT, <span style="color: #000040;">&amp;</span>count<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
&nbsp; &nbsp;<span style="color: #666666;">// Conditionnal rendering </span><br />
&nbsp; &nbsp;glBeginConditionalRender<span style="color: #008000;">&#40;</span>query, GL_QUERY_WAIT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// GL_QUERY_WAIT, GL_QUERY_NO_WAIT, GL_QUERY_BY_REGION_WAIT </span><br />
&nbsp; &nbsp;glEndConditionalRender<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
