Moteur Graphique
Quelle est cette histoire sur l'anti-aliasing?
Pas d'allocation mémoire sur le tas pendant le cycle de dessin!
Représentation en virgule flottante
Browser Enhancement Technologies
Floats vs. Doubles
Le moteur graphique de Jmol est entièrement écrit en
Java. Il n'y a pas de Java3D, OpenGL ou d'autre type
d'accélération matérielle.
Le moteur graphique est un moteur graphique spécialisé,
et non une libraire graphique 3D générique.
Le moteur de dessin a été conçu exprès
pour l'affichage de molécules, il fait donc un bon travail
pour le dessin de sphères et de cylindres.
Il s'agit d'une implémentation entièrement logicielle
d'un z-buffer. Il y a un int[] pixelBuffer qui contient les valeurs
ARGB et un short[] zBuffer qui contient la profondeur du pixel
à ce point.
Pendant le cycle de redessin, la scène complète est
dessinée dans le pixelBuffer. Puis la scène
complète est dessinée sous la forme d'image avec une
seule opération Graphics.drawImage(...).
Il n'utilise pas une liste d'affichage de triangles. Ce serait trop
lent. Au lieu de ceci, il y a des routines optimisées pour
dessiner des sphères et des cylindres.
Si vous voyez des façons d'améliorer la vitesse
de dessin, faîtes le nous savoir!
L'anti-aliasing n'est pas actuellement activé dans Jmol.
La plus grosse partie du mécanisme est en place, mais est
actuellement désactivé. Il est actuellement
désactivé à cause de problèmes de
performances sur des matériels plus anciens. Nous
prévoyons de compléter l'implémentation et de
le réactiver dans une version future ... quand nous aurons un
peu plus de temps pour déterminer comment ce doit être
géré sur des machines plus anciennes.
Le moteur Graphics3D Jmol est entièrement
implémenté sous forme logicielle. Il ne peut pas utiliser
les appels aux graphiques Sun 2D car ils n'offrent pas la fonction
de zBuffer qui permet de décider pixel par pixel si un pixel
doit être dessiné.
La technique d'anti-aliasing utilisée dans le moteur Graphics3D
de Jmol est appelé de l'anti-aliasing-scène-totale. La
scène entière est dessinée dans un buffer qui est
deux fois plus large et deux fois plus haut. Ainsi, 4 pixels sont
convertis en 1 pixel, avec un mélange approprié des
valeurs RVB.
Le résultat final est qu'elle prend plus de mémoire pour
contenir le zBuffer et le pixelBuffer. Et elle prend beaucoup plus de
cycles CPU pour dessiner une scène. Le dessin prend 4 fois plus
de temps. Globalement, il faut probablement 3 fois plus de temps pour
dessiner une scène.
Sur les machines récentes avec beaucoup de puissance CPU, ce
n'est probablement pas un problème. Sur des machines plus
anciennes, ce ne serait pas acceptable. En conséquence, nous
devons mettre en place des options.
Jmol n'alloue pas de mémoire sur le tas lors du cycle de
redessin. Pour des raisons de performance, il est important que
nous continuions à suivre cette règle.
[Dave a lu un brouillon de ce mémo (version anglaise)
et a donné sa permission d'utiliser son code comme exemple]
En faisant une petite 'revue de code' du code récemment
contribué par Dave pour Ribbons/Mesh, j'ai vu quelque chose
qui mérite d'être discuté.
Pour être clair, Dave a écrit du code excellent. Mais
avec une petite modification nous pouvons nous assurer de maintenir
des performances optimales. Et je vais utiliser ce code comme exemple
pour faire prendre conscience des problèmes d'allocation
mémoire dans Jmol.
Pour dessiner les Ribbons, Dave avait besoin de deux tableaux d'objets
Point3i pour conserver les coordonnées écran des bords de
ses rubans. Ainsi, il alloue les tableaux et les remplit avec de
nouveaux objets Point3i. Des choses sont calculées, des choses
sont dessinées et de jolis rubans apparaissent à
l'écran.
Et puis les objets temporaires sont poubellisés. Et à
cet endroit réside un petit problème: les objets
temporaires que nous allouons et libérons pendant le cycle
de redessin.
Pourquoi est-ce un problème?
Bien, les cycles de redessin peuvent se produire plutôt
rapidement ... espérons 30 fois par secondes pendant les
rotations. Ainsi, si nous allouons des objets sur le tas [en
utilisant new SomeObject(...)], alors nous pouvons aboutir à
l'allocation de beaucoup d'entre eux rapidement.
En fait, le problème n'est pas avec l'allocation. Le
problème est avec la *désallocation*; nous supprimons
immédiatement les objets. Ces objets supprimés donnent
du travail inutile au garbage collector Java, qui doit parcourir la
mémoire pour rechercher les structures supprimées.
Quand le garbade collector se déclenche il peut parfois
entraîner des pauses ou des 'hocquets' dans les réponses
du système ... une mauvaise chose.
En conséquence, nous devons nous en occuper en faisant notre
maximum pour 'recycler' les objets mémoire pendant le cycle de
redessin.
Nous pouvons obtenir ceci en associant les objets temporaires à
des instances des classes Renderer. Nous pouvons demander aux instances
de Renderer d'allouer/stocker les objets temporaires pour nous, et
nous pouvons réutiliser les mêmes objets temporaires
à chaque fois pendant le cycle de redessin.
Il y a d'autres parties du système ou ces règles ne
s'appliquent pas vraiment. Par exemple, pendant les opérations
d'E/S nous sommes libres d'allouer/libérer autant de choses
que nous le voulons. Pendant les E/S nous devons faire beaucoup
d'analyse de texte. Cette analyse entraîne beaucoup de
chaînes de caractères temporaires qui ont une
durée de vie très courte. Mais c'est bon car nous ne
lisons pas de fichiers aussi souvent et parce que les utilisateurs
s'attendent à ce que ce soit une opération relativement
lente.
Quelqu'un a soulevé un point que je pense être
d'intérêt général.
Concernant l'affichage des paramètre des cellules cristallines:
> Dans certains cas, les valeurs a, b, ou c etc s'affichent avec
> des décimales 'supplémentaires'. L'applet 10pre8
> affiche a=10.436999 alors que le champ CRYST1 du fichier pdb a la
> valeur 10.437. Probablement une erreur 'd'arrondi' avec les
> calculs des coordonées de la cellule.
En fait, ce cas particulier est un point plus subtil. Il ne s'agit pas
vraiment d'un problème 'd'arrondi' car aucun calcul n'est fait
sur ces nombres.
Mais c'est quand même un problème. Et la cause
de ce problème est d'intérêt
général pour ceux qui travaillent avec des nombres
à virgule flottante.
Nous avons l'habitude de travailler en base 10 ... 10 doigts. De temps
en temps nous tombons sur des nombre rationels qui ne peuvent pas
être représenté en base 10. Les exemples les plus
courants sont peut-être 1/3 et 2/3. Nous les écrivons
0.33 ou 0.67 ou nous ajoutons quelques chiffres (0.33333 0.66667) si
nous avons besoin de plus de précision dans nos calculs.
Et bien, nous rencontrons le même problème dans le
monde de l'informatique. Et les gens se sont battus avec des
manières de régler ce problème depuis le
début des ordinateurs.
La plupart des ordinateurs actuels utilisent
généralement une représentation en virgule
flottante définie en 1985 par l'organisation de normalisation
IEEE:
IEEE Std 754-1985
IEEE Standard for Binary Floating-Point Arithmetic
Il s'agit d'une représentation 'base 2' (binaire) des nombres
à virgule flottante, et non une représentation
'base 10'. Fondamentalement, celà signifie qu'il y a un autre
ensemble de nombres rationels qui ne peuvent pas être
représentés de façon exacte.
Dans ce cas, aucun calcul n'a été effectué
sur le nombre 10.437 ... il a été lu directement depuis
le fichier. Mais le nombre 10.437 ne peut pas être
représenté exactement en binaire ... nous finissons
donc avec 10.436999 (Je n'ai pas vraiment vérifié, mais
je suppose que c'est le cas).
D'autres faits en vrac:
-
COBOL supportait les nombres décimaux et à virgule
fixe pour régler ce problème pour gérer les
dollars et les cents dans un environnement d'affaire.
-
Une des représentation sur les mainframes IBM était
en base 16 (au lieu de base 2). Bien que ceci ne règle
pas ce problème particulier, il donnait de meilleurs
performances (pendant le processus de 'normalisation').
-
Les gens qui veulent de hautes performances ne suivent
généralement pas la norme IEEE.
-
Les spécifications de la Machine Virtuelle Java initiale
*nécessitait* une représentation IEEE (et le
comportement opérationnel associé) pour les nombres
à virgule flottante. Ceci (devait) assure la
portabilité entre plateformes ... les mêmes calculs
devaient donner le même résultat sur
différents systèmes. Cette exigence a
été quelque peu relâchée depuis ...
pour permettre de meilleures performances de calcul ... et à
cause de l'admission qu'il s'agit d'un problème insoluble.
-
Je pense que le plupart des gens sont d'accord pour dire que la
norme IEEE a des erreurs, mais les gens doivent la suivre
-
Les systèmes permettant de faire des maths
symboliques/pures (Mathematice, MATLAB, Macsyma) supportent les
nombres rationels (représentation fractionnelle d'entiers
... 1/3, 2/3) pour essayer d'éviter ce type de
problème pour les nombres rationels.
Je vais essayer de donner un bref aperçu de 4 techniques
différentes qui peuvent être utilisées pour
ajouter des fonctions au navigateur. Il est important d'utiliser une
terminologie correcte pour ne pas faire de confusion.
Dans l'ordre du plus simple au plus complexe:
Application d'Aide
Une application d'Aide est une application normale qui est
lancée automatiquement quand le navigateur reçoit un
fichier dont il ne sait pas quoi faire. Le type du fichier est
identifié par quelque chose appelé le 'type MIME'.
Regardons un exemple en utilisant une installation propre de
Netscape/Mozilla. (Nous allons dire Netscape/Mozilla parce que
Internet Explorer a un support 'spécial' pour d'autres
produits MSFT).
La première fois que Mozilla reçoit un fichier .doc
avec le type mime 'application/msword' il ne sait pas quoi faire avec
ce fichier. Il sait que ce fichier n'est pas de type 'text/html' ou
'image/jpeg', il ne sait donc pas comment gérer ce type de
façon native.
En conséquence, Mozilla demande à l'utilisateur si
il/elle veut sauver le fichier ou lancer une application. Si
l'utilisateur sélectionne une application alors il/elle peut
choisir de toujours lancer cette application quand des fichiers de ce
type mime sont rencontrés.
Chaque navigateur a sa table d''associations' entre types mime et
applications ... bien que la table de Safari semble bien cachée.
Une application d'aide peut être n'importe quelle application
... y compris l'application Jmol.
Il faut remarquer que pour que ce schéma fonctionne
réellement le serveur web doit être configuré
pour envoyer le bon type mime. Ce n'est généralement
pas un problème pour les applications majeures. Cependant,
c'est un problème pour les types de fichiers moins connus sur
les serveurs web avec des administrateurs système novices ...
ce qui est souvent le cas avec les personnes essayant de construire
et déployer des applications web Chime.
Applet Non Vérifiée (Non Signée)
C'est une Applet Java qui est intégrée dans une page
web. La plupart des applets non signées sont relativement
petites et se téléchargent rapidement. L'utilisateur
ne les remarque pas vraiment. Il s'agit des petits systèmes de
menu, jeux, etc.
Ce type d'applet est 'non vérifiée' dans le sens
où elle provient d'un serveur web quelconque quelque part sur
le web. En conséquence nous ne lui faisons pas confiance. En
conséquence, les applets non vérifiées sont
placées dans un espace sécurisé. Elles ne peuvent
pas lire ou écrire sur le disque dur local et elles peuvent
seulement discuter avec le serveur web d'où elles proviennent.
Si elles essayent de faire autre chose, elles sont
immédiatement décapitées.
JmolApplet est une applet non vérifiée ... plus grosse
et plus complexe que la plupart des applets non
vérifiées.
Applet Vérifiées (ou Signées)
Les restrictions de sécurité placées sur les
applets non vérifiées sont plutôt strictes. Et
les gens veulent développer des applications web qui peuvent
faire des choses plus fantaisistes ... comme enregistrer des fichiers
sur le disque dur local.
Avant que ce type d'applet soit exécuté, le navigateur
demande explicitement à l'utilisateur la permission de lancer
cette applet. En disant oui l'utilisateur donne essentiellement la
permission au logiciel d'être installé sur le disque dur
local.
Pour protéger tous les intervenants, une Applet
Vérifiée est *signée* avec une signature
numérique cryptée. Le cryptage permet aussi de s'assurer
que le code de l'applet n'a pas été modifié par
un tiers.
Une 'autorité de certification' est une organisation à
laquelle vous faîtes confiance pour la vérification.
Actuellement, il n'y a pas de JmolApplet 'signée'. Dans le
futur, quand il y en aura une, j'irais voir une 'autorité de
certification' et leur prouver que je suis membre du projet Jmol.
Il me donneront alors un jeu de clé numérique.
J'utiliserai alors le jeu de clés pour produire une
SignedJmolApplet.
Quand un utilisateur ira sur une page web qui a la SignedJmolApplet,
le navigateur lui demandera si il fait confiance à l'applet.
Il dira 'oui' et la session continuera.
La SignedJmolApplet qui est installée sur le disque dur peut
maintenant lire/écrire des fichiers sur le disque dur. Elle
peut aussi lire/écrire des donné sur n'importe quel
endroit du web.
Ceci donnera à la SignedJmolApplet beaucoup plus de marge pour
faire des choses intéressantes ... comme lire des fichiers de
modèles moléculaires locaux ... ou extraire directement
des fichiers depuis des bases de données sur le web.
Il faut noter que cette SignedJmolApplet n'est toujours qu'une applet
qui n'existe que dans le contexte d'une page web
particulière. Ce n'est pas une application arbitraire qui
peut être lancée à n'importe quel moment.
Un utilisateur ne peut pas l'exécuter à moins qu'elle ne
fasse partie d'une page web à laquelle ils ont accès.
Cependant, ceci devrait inclure une page web qui provient d'un
CR-ROM ou qui est stockée sur un système de fichiers
local.
Dans le futur, nous espérons avoir une SignedJmolApplet.
Cependant, nous voudrons conserver la JmolApplet non signée
pour ceux qui veulent construire des sites web plus simples qui ne
nécessitent pas de permission explicite pour écrire
sur le disque dur local.
J'aimerais que la JmolApplet soit 'simple' ... avec des fonctions
limitées ... mais un bon support pour simplement afficher
des molécules pour les étudiants débutants et
les visiteurs occasionnels.
La SignedJmolApplet sera pour les utilisateurs sérieux qui
veulent plus de fonctions.
Plug-in
Pour comprendre un plug-in il est utile de se rappeler l'application
d'aide. Une application d'aide n'est pas associée à une
page web spécifique. Au contraire, elle est associée
à un type de fichier particulier, un type mime particulier. Le
navigateur web lancera MS Word chaque fois qu'il voit un document
avec le type mime 'application/msword'.
Un plug-in fonctionne de façon similaire. Mais l'affichage
des données est inclus dans la fenêtre du navigateur.
A un certain niveau, il s'agit d'un logiciel qui étend les
capacités du navigateur lui-même. D'où viennent
les fichier ne compte pas. Quand le navigateur voit un type mime non
natif il peut vérifier sa liste de plug-ins installés et
voir si l'un d'entre eux peut le gérer.
Deux exemples populaires sont Flash et Acrobat Reader. Les gens
installent généralement ces choses une fois et ne s'en
occupe plus.
Une fois qu'un plug-in est installé il peut faire tout ce qu'il
veut comme n'importe quel logiciel installé.
Développer et maintenir des plug-ins est très
coûteux et cher. Bien que Netscape ait défini une API
de plug-in, le fait est que le comportement dynamique de chaque
navigateur sur chaque plateforme est différent. Et beaucoup de
navigateurs 'implémentent/supportent' l'API de Plug-in
Netscape, mais ce sont des implémentations différentes
et elles ont des comportements différents. Le problème
fondamental est que vous essayez de prendre une bout de logiciel
compliqué (votre joli plug-in) et de l'inclure dans une autre
bout de logiciel compliqué (le navigateur web), à
côté d'autres plug-ins. Et, en général,
vous partagez la même mémoire et certaines des
mêmes structures de données. En conséquence,
quand quelqu'un fait une erreur, les choses ont tendance à
casser.
En écrivant ceci il devient plus clair qu'avant qu'un Plug-in
Jmol n'existera jamais.
C'est suffisant pour maintenant.
Plusieurs personnes ont demandé pourquoi le code de Jmol
utilise des floats au lieu de doubles. En vérité,
beaucoup des plus jeunes programmeurs Java n'ont probablement
jamais vu un programme avec autant de floats.
La réponse est qu'ils sont plus petits ... les floats
occupent 4 octets et les doubles 8 octets. Et pourtant, ils ont
suffisamment de plage d'utilisation et de précision pour
nos besoins.
Donc, pourquoi est-ce important qu'ils soient plus petits? Vous vous
dites probablement que la mémoire ne coûte pas cher et,
en général, vous avez raison.
Cependant, Jmol doit pouvoir fonctionner en tant qu'applet sur des
JVMs 1.1, où le total de mémoire virtuelle est quelque
peu plus petit.
Plus important, la bande passante mémoire n'est jamais
bon marché. Les fabricants de CPU font tout ce qu'ils peuvent
pour essayer de concevoir des caches plus grands pour essayer
d'accroître la bande passante mémoire effective.
Ainsi, en travaillant avec des floats sur 4 octets au lieu de
doubles sur 8 octets, nous pouvons utiliser plus efficacement la
mémoire système ... les différents niveaux de
cache + la bande passante mémoire globale. Nous pouvons
stocker plus de données dans un cache de taille fixe et nous
pouvons récupérer plus de données de la
mémoire à chaque fois que nous accédons à
une ligne de cache.
Franchement, c'est aussi facile d'utiliser des floats ... et il n'y a
pas de raison de gâcher.
|