Page 1 sur 2

Comment faire une lib en C ou C++ ? un truc très simple

Publié : sam. 15/avr./2006 11:50
par comtois
Je cherche à accélérer les calculs de mes procédures collisions 3D.

Je me demandais si en les faisant en C , je ne gagnerais pas un peu ?

Et quel est le moyen le plus simple pour utiliser les fonctions ainsi créées sous PureBasic ?
Lib static et utiliser Import ?
Dll ?
Créer une lib PureBasic ?

Je n'ai pas encore compris comment il fallait s'y prendre :oops:

Est-ce que quelqu'un aurait un exemple à me montrer , un truc tout simple que je pourrais compiler et tester chez moi ?

Pour l'instant je fais des essais avec Dev-C++ 4.9.9.2
Je n'arrive à rien.

Je ne ferai rien de compliqué dans mes fonctions, j'ai juste besoin de faire des calculs.
Par exemple ceci :

int AdditionVecteur( int *Vecteur1, int *Vecteur2)
{
int *Somme
*Somme := *Vecteur1 + *Vecteur2
Return *Somme
}

Ne faites pas attention à la syntaxe ,il faut que je me documente un peu plus à ce sujet :)

Voila en gros le genre de fonction dont j'ai besoin.

Si quelqu'un pouvait faire un petit tutoriel sur le sujet ça serait sympa :)

Publié : sam. 15/avr./2006 12:16
par erix14
Tu ne gagneras rien du tout en passant en C pour faire des calculs, à croire que tu n'as jamais vu le code assembleur généré par PureBasic :lol: :lol: :lol:
Il faut que tu travailles sur tes algorithmes, c'est le seul moyen. ( il n'y a rien de magique dans le C.)

Publié : sam. 15/avr./2006 12:35
par comtois
erix14 a écrit :Tu ne gagneras rien du tout en passant en C pour faire des calculs, à croire que tu n'as jamais vu le code assembleur généré par PureBasic :lol: :lol: :lol:
Il faut que tu travailles sur tes algorithmes, c'est le seul moyen. ( il n'y a rien de magique dans le C.)
ça ne m'aiderait pas beaucoup de voir le code assembleur , je n'y connais rien.

Mais je suis d'accord avec toi, c'est clair que je gagnerai plus en bossant sur les algorithmes :)
Je travaille aussi sur cette piste d'ailleurs.

Néanmoins, si je regarde les tests réalisés sur le forum anglais, il semblerait que certains calculs soient mieux optimisés par les compilos en C qu'en PureBasic ?

Voir ici

Il est surtout question de comparer BlitzMax et PureBasic dans ce post , mais certains tests font référence au C. et apparemment il est toujours le plus rapide. A quoi ça tient ? est-ce le code en Blitz ou PureBasic qui est mal traduit ? je n'ai pas approfondi la chose ,et je voulais faire mes propres tests en prenant comme base mes fonctions de collisions.
Elles ne comportent que du calcul, pas d'affichage , rien qui pourrait fausser les résultats.

Publié : sam. 15/avr./2006 12:56
par Flype
Question en passant :
Obtiens-tu un gain significatif en compilant un exécutable adapté à ton CPU grâce aux directives 3DNOW, SSE, SSE2, ... ?

Publié : sam. 15/avr./2006 13:21
par comtois
j'avais testé ça
CPU Dynamique : Les fonctions génériques ainsi que les fonctions spécifiques à tous les CPU supportés seront intégrées à l'exécutable. Le choix des fonctions à utiliser se fera au démarrage de l'exécutable, en détectant dynamiquement le processeur sur lequel il est lancé. Cela crée des exécutables plus gros, mais que seront aussi rapides que possible.
Je n'ai pas mis en place un moyen de mesurer les performances.
J'utilise toujours ma démo Temple, et je regarde le comportement du FPS, Ce n'est pas forcément significatif je te l'accorde.
D'autant plus que je suis souvent à 60 , avec parfois des chutes à 55.

Hier soir j'ai changé certains calculs , je les fais en double plutôt qu'en float, je m'attendais à des ralentissements , et c'est le contraire, on dirait que ça accélère, le FPS est plus stable.
C'est pas magique c'est seulement qu'en faisant des calculs plus précis je peux stopper l'algo de test plus tôt , donc même si c'est plus long de calculer en double, ça élimine d'autres calculs qui se faisaient plus souvent avant (du moins c'est comme ça que je l'analyse pour l'instant, faut de prendre le temps de tout tracer).

Ceux qui avaient un FPS de de 35 devraient essayer de compiler les sources pour voir si ça change quelque chose avec les différentes options de compilation.

Bref ça ne résoud pas mon problème de test d'une fonction écrite en C :)

Publié : sam. 15/avr./2006 13:50
par erix14
Je viens de regarder les tests réaliser sur le forum anglais. J'ai l'impression qu'il a de tout et n'importe quoi.
Pour mettre les choses au clair (avec PureASM :D ) :

Code : Tout sélectionner

; f.f = Cos(30.5)
	FLD	 dword [F1]
	FCOS
	FSTP	 dword [v_f]
Aucun langage ne peut aller plus vite que ça.

Code : Tout sélectionner

; f = Sqr(f)
	FLD	 dword [v_f]
	FSQRT
	FSTP	 dword [v_f]
Aucun langage ne peut aller plus vite que ça.

Code : Tout sélectionner

; f = Pow(15, 2)
	PUSH	 dword 1073741824
	PUSH	 dword 1097859072
	CALL	 _PB_Pow@8
	FSTP	 dword [v_f]
Là par contre, c'est une catastrophe, à éviter comme la peste. Il faut faire à la place 15*15 (ça sert à rien de prendre un autre compilateur, quand on le sait, il suffit simplement de corriger soi-même)

Code : Tout sélectionner

; x.f = 15/((454.2*f)+8)
	FLD	 dword [v_f]
	FMUL	 dword [F2]
	FADD	 dword [F3]
	FDIVR	 dword [F4]
	FSTP	 dword [v_x]
Je ne pense pas qu'on puisse aller plus vite ou peut-être avec le registre ebp (à voir).

J'aimerais que tu me mettes une boucle que tu aimerais absolument optimiser, pour que je puisse y jeter un oeil.

Publié : sam. 15/avr./2006 14:42
par comtois
oui il y a de tout et n'importe quoi , c'est pourquoi je ne veux pas rentrer dans les détails du post que j'ai collé :)

Il y a une autre raison pour laquelle j'aimerais être capable de faire une fonction en C ou C++ et la lire avec PureBasic, c'est que la plupart des algos que je peux trouver sont écrits dans ces langages.
Le but serait de tester rapidement l'efficacité de ces fonctions, sans avoir à les retranscrire en PureBasic. D'autant plus que je ne comprends pas forcément tout :?

Par exemple j'ai trouvé un algo pour tester l'intersection d'un triangle avec une box, son auteur prétend que c'est le plus rapide, mais c'était en 2001 ou 2002 je crois. C'est celui que j'utilise actuellement, il était simple à recoder en PureBasic.

Depuis j'en ai trouvé un autre plus récent, et bien sûr son auteur prétend qu'il est plus rapide que celui que je viens de citer. Les résultats sont publiés dans des revues universitaires, je peux espérer qu'il dit vrai :)

Mais celui ci est plus complexe à aborder, je sens que je vais galérer pour l'adapter, et j'aurais voulu le tester sans le retranscrire.

Sinon pour en revenir à nos moutons , c'est difficile d'extraire une boucle puisque c'est l'ensemble des mes fonctions de collisions ainsi que l'octree que je voulais coder en C pour tester.

Mais soit, prenons par exemple ces deux fonctions (très sollicités pour le calcul d'une collision) :

Code : Tout sélectionner

Macro SOUSTRACTION_VECTEUR(V, V1, V2)
   V\x = V1\x - V2\x
  	V\y = V1\y - V2\y
  	V\z = V1\z - V2\z
EndMacro 

Macro PRODUIT_SCALAIRE(V1, V2)
  	(V1\x * V2\x + V1\y * V2\y + V1\z * V2\z) 
EndMacro

Procedure TestPointDansTriangle1(*point.s_Vecteur, *pa.s_Vecteur, *pb.s_Vecteur, *pc.s_Vecteur)
   Define.s_Vecteur e10, e20, vp 
   Define.f a, b, c, ac_bb, d, e, x, y, z
   
   SOUSTRACTION_VECTEUR(e10, *pb, *pa)
   SOUSTRACTION_VECTEUR(e20, *pc, *pa)
   
   a = PRODUIT_SCALAIRE(e10, e10)
   b = PRODUIT_SCALAIRE(e10, e20)
   c = PRODUIT_SCALAIRE(e20, e20)
   ac_bb = (a * c) - (b * b)
   SOUSTRACTION_VECTEUR(vp, *point, *pa)
   d = PRODUIT_SCALAIRE(vp, e10)
   e = PRODUIT_SCALAIRE(vp, e20)
   x = (d * c) - (e * b)
   y = (e * a) - (d * b)
   z = x + y - ac_bb
   ProcedureReturn ((PeekL(@z) & ~(PeekL(@x) | PeekL(@y))) & $80000000)
EndProcedure

Procedure.b ChercheLaPlusPetiteSolution(a.f, b.f, c.f, maxR.f, *Solution.Float)
	Define.f Determinant, t1, t2, q
	
	;Cherche les solutions d'une équation de cette forme : At²+Bt+C=0
 	;http://fr.wikipedia.org/wiki/%C3%89quation_du_second_degr%C3%A9 (bas de la page "Gain de précision")
	 	
	;Calcul le déterminant
 	Determinant = b * b - 4.0 * a * c
 	
 	;Si le déterminant est inférieur ou égal à zéro , il n'y a pas d'intersection significative.
 	If Determinant < 0.0 : ProcedureReturn #False : EndIf

;	If a = 0.0
;		t1 = -c / b
;		t2 = 0.0
;	Else
	 	;Calcul les deux solutions 
	 	If b < 0.0
			q = 0.5 * (-b - Sqr(Determinant)) 
		Else
			q = 0.5 * (-b + Sqr(Determinant)) 
		EndIf
		t1 = q / a
 		t2 = c / q
	;EndIf
	
	;Est-ce vraiment utile ? 
	If t2 < t1
	   Swap  t1, T2
	EndIf   
	
 	;Renvoie la solution la plus petite si elle est valide
 	If t1 > 0  And t1 < maxR 
  		*Solution\f = t1
  		ProcedureReturn #True
 	EndIf
 	If t2 > 0  And t2 < maxR
  		*Solution\f = t2
  		ProcedureReturn #True
 	EndIf
 	;Pas de solution
 	ProcedureReturn #False
EndProcedure

Publié : sam. 15/avr./2006 15:04
par erix14
Je vais regarder ça, déjà à première vue les 3 PeekL c'est 3 PeekL de trop :)

Publié : sam. 15/avr./2006 16:02
par erix14
Voilà ce que je peux faire pour la première procédure : :D

Code : Tout sélectionner

Structure FloatLong
     StructureUnion
          f.f
          l.l
     EndStructureUnion
EndStructure

Procedure TestPointDansTriangle1(*point.s_Vecteur, *pa.s_Vecteur, *pb.s_Vecteur, *pc.s_Vecteur)
   ; a testé : cela peut faire gagner du temps si une très grande majorité des points sont en dehors des alentours du triangle
   If *point\x < *pa\x And *point\x < *pb\x And *point\x < *pb\x : ProcedureReturn #False : EndIf
   If *point\x > *pa\x And *point\x > *pb\x And *point\x > *pb\x : ProcedureReturn #False : EndIf
   If *point\y < *pa\y And *point\y < *pb\y And *point\y < *pb\y : ProcedureReturn #False : EndIf
   If *point\y > *pa\y And *point\y > *pb\y And *point\y > *pb\y : ProcedureReturn #False : EndIf
   If *point\z < *pa\z And *point\z < *pb\z And *point\z < *pb\z : ProcedureReturn #False : EndIf
   If *point\z > *pa\z And *point\z > *pb\z And *point\z > *pb\z : ProcedureReturn #False : EndIf
   
   Define.s_Vecteur e10, e20, vp
   Define.f a, b, c, d, e
   Define.FloatLong x, y, z
   
   SOUSTRACTION_VECTEUR(e10, *pb, *pa)
   SOUSTRACTION_VECTEUR(e20, *pc, *pa)
   
   a = PRODUIT_SCALAIRE(e10, e10)
   b = PRODUIT_SCALAIRE(e10, e20)
   c = PRODUIT_SCALAIRE(e20, e20)
   SOUSTRACTION_VECTEUR(vp, *point, *pa)
   d = PRODUIT_SCALAIRE(vp, e10)
   e = PRODUIT_SCALAIRE(vp, e20)
   x\f = (d * c) - (e * b)
   y\f = (e * a) - (d * b)
   z\f = x + y - (a * c) - (b * b)
   
   ProcedureReturn ((z\l & ~x\l | y\l) & $80000000)
EndProcedure

Publié : sam. 15/avr./2006 17:20
par erix14
Pour la deuxième procédure, même en assembleur on ne peut pas faire grand-chose...

Publié : sam. 15/avr./2006 18:13
par comtois
Je n'avais pas pensé à la structure FloatLong :)
Mais malheureusement ta procédure ne fonctionne pas.
Je passe au travers des sols , et c'est la chute libre ... ou alors je reste coincé dans un triangle.

Par contre j'ai repris ce test

Code : Tout sélectionner

   Define.s_Vecteur TestPlus, TestMoins
   TestPlus\x = *point\x + #Epsilon
   TestPlus\y = *point\y + #Epsilon
   TestPlus\z = *point\z + #Epsilon
   TestMoins\x = *point\x - #Epsilon
   TestMoins\y = *point\y - #Epsilon
   TestMoins\z = *point\z - #Epsilon
   If TestPlus\x < *pa\x And TestPlus\x < *pb\x And TestPlus\x < *pc\x : ProcedureReturn #False : EndIf
   If TestMoins\x > *pa\x And TestMoins\x > *pb\x And TestMoins\x > *pc\x : ProcedureReturn #False : EndIf
   If TestPlus\y < *pa\y And TestPlus\y < *pb\y And TestPlus\y < *pc\y : ProcedureReturn #False : EndIf
   If TestMoins\y > *pa\y And TestMoins\y > *pb\y And TestMoins\y > *pc\y : ProcedureReturn #False : EndIf
   If TestPlus\z < *pa\z And TestPlus\z < *pb\z And TestPlus\z < *pc\z : ProcedureReturn #False : EndIf
   If TestMoins\z > *pa\z And TestMoins\z > *pb\z And TestMoins\z > *pc\z : ProcedureReturn #False : EndIf
Si je ne mettais pas #Epsilon , je passais aussi au travers des sols, ou je pouvais rester coincer. Maintenant reste à mesurer si ça améliore la vitesse. Comme j'utilise un octree pour réduire le nombre de triangles à tester, je ne sais pas si la différence est flagrante, mais le peu que ça fait gagner c'est déjà ça de pris :)

Merci pour ta contribution, je vais éplucher encore ta procédure pour tenter de comprendre pourquoi elle ne fonctionne pas !

J'ai essayé de remplacer le PeekL par la structure FloatLong dans ma procédure, et ça ne fonctionne pas non plus !

Publié : sam. 15/avr./2006 18:41
par erix14
J'ai essayé de remplacer le PeekL par la structure FloatLong dans ma procédure, et ça ne fonctionne pas non plus !
C'est bizarre :? avec mes tests il n'y a aucun problème :

Code : Tout sélectionner

Structure FloatLong
     StructureUnion
          f.f
          l.l
     EndStructureUnion
EndStructure 

   x.FloatLong\f = 3.14
   y.f = 3.14

   Debug PeekL(@y)
   Debug PeekL(@x\f)
   Debug x\l
Tiens-moi au courant si tu trouves pourquoi...

Publié : sam. 15/avr./2006 19:52
par comtois
C'est pas ta structure FloatLong qui est en cause , elle fonctionne parfaitement .

J'ai fait une erreur en voulant l'utiliser , toi aussi d'ailleurs :)
J'avais mis ça

Code : Tout sélectionner

   x\f = (d * c) - (e * b)
   y\f = (e * a) - (d * b)
   z\f = x + y - ac_bb
Au lieu de ça(compare la troisième ligne)

Code : Tout sélectionner

   x\f = (d * c) - (e * b)
   y\f = (e * a) - (d * b)
   z\f = x\f + y\f - ac_bb
J'ai aussi corrigé ça dans ta procédure > + (b * b)

Code : Tout sélectionner

z\f = x\f + y\f - (a * c) + (b * b)
Et ce n'était pas suffisant , les parenthèses semblent faire la différence

Code : Tout sélectionner

ProcedureReturn ((z\l & ~(x\l | y\l)) & $80000000)

Voila , maintenant ta procédure semble donner les mêmes résultats que la mienne, et serait un poil plus rapide , je vais donc l'adopter.

Merci pour ces quelques millisecondes grapillées :)

Publié : sam. 15/avr./2006 20:05
par erix14
Effectivement, la prochaine fois je ferai plus attention :lol:

Publié : dim. 16/avr./2006 9:22
par comtois
C'est bon j'ai réussi !!!!!
Youpiii !!

Bon je vais commencer par refaire la fonction TestPointDansTriangle() et comparer le résultat :)