Author Topic: OpenGL 2.x: Pyramides/Mipmap temps réel ?  (Read 7628 times)

0 Members and 1 Guest are viewing this topic.

Offline krabob

  • Base
    • Pouet.net
    • View Profile
    • www.m4nkind.com
  • Ancienneté: 1994
  • Groupe: Mankind
  • Rôle: code amiga / linux / OpenGL
  • Ville: Toulouse
OpenGL 2.x: Pyramides/Mipmap temps réel ?
« on: 18 December 2010 à 20:09:55 »
 :o
 Pour relancer un sujet dans le droit fil de ce forum, voilà une question de code qu'elle est intéressante:
 Pour du MIPmapping ou d'autres trucs en GLSL, il peut être utile de construire les "autres niveaux de mimap" d'une image dynamique, ou le niveau 0 correspondrait à un FBO, redessiné en temps réel.
 J'ai une routine qui construit un niveau a partir du niveau du dessus avec des shaders, mais les niveaux de la pyramide sont des textures indépendantes, pas "une seule texture" avec plusieurs levels: en effet: il est possible d'attacher un FBO a chaque level d'une texture, mais si on fait ça j'imagine que c'est pas légal, parce que tu te retrouves à écrire la même texture que tu lis, même si le niveau écris n'est en théorie pas lu, un texture2d() est susceptible de lire ce qui est écrit.
 Flairant ce problème, Je m'en suis tenu à garder autant de textures que de niveaux, puis de finasser avec le shader qui va ensuite utiliser la pyramide (en faisant un mip maison avec 2 texture2d(), pas très élégant tout ça) .

 Dans les docs de gl"ES"2, j'avais cru voir une méthode GL pour re-construire  automatiquement tout les niveaux >0 d'une texture. Il me semble l'avoir testé sous la petite implémentation qui la proposait (une beta du tegra sdk) et avoir constaté des perfs de daube.

 Une telle méthode est elle dispo sur les implémentations courantes (la dernière fois ou j'ai vraiment fait du GL c'était en 2002/2004, à l'époque il fallait créer tout ses niveaux au cpu ). Quelqu'un connait-il une autre bidouille pour construire une pyramide en temps réel ? ou un truc genre faire du ping-pong entre 2 pyramides puis recopier un des niveaux sur 2 vers l'autre ?
 Merci les mecs, c'est puissant !
8)
« Last Edit: 18 December 2010 à 20:13:31 by krabob »
Votez comme ça Mélenchon ... ou Clément Wittman, ... ou Eva ! Oo

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #1 on: 18 December 2010 à 20:30:20 »
Mmmh, chais pas si ça peut aider mais dans DX10 t'as la notion de "TextureView" qui ressemble un peu aux vues dans un DB.
En gros tu peux créer N views qui sont chacune un niveau de mip-map de ta texture et en mettre une lecture pendant que l'autre est en écriture sans que ça gène...
'fin bien sûr, tu peux écrire que si ta texture est également une render target... Donc ça sert pas à créer des mip-maps d'une simple texture read-only.

Bref. Ma réponse ne sert à rien mais juste pour dire que dans DX ils considèrent plus vraiment des textures ou des vertex buffers ou des choucroutes : c'est tout unifié en mémoire.
Je sais pas si y a un quelconque équivalent en GL ?

Perso, je fais tous mes mips en software au moment où je load la texture.
En même temps, c'est juste fait à l'initialisation, est-ce que c'est réellement le genre de trucs à optimiser ?? :-*
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #2 on: 19 December 2010 à 02:01:57 »
Perso, je fais tous mes mips en software au moment où je load la texture.
En même temps, c'est juste fait à l'initialisation, est-ce que c'est réellement le genre de trucs à optimiser ?? :-*
Tiens, j'avais vu ça dans ton code effectivement... je m'étais demandé pourquoi tu faisais comme ça... quand par exemple il y a déjà la méthode GenereateMips (mais je n'ai jamais testé pour voir si c'est bien implémenté sur le GPU... j'imagine que oui quand même). Bon, la différence aussi, c'est que tu peux créer tes textures en immutable, alors qu'avec un GenerateMips, elles doivent obligatoirement être aussi des rendertargets...

  même si le niveau écris n'est en théorie pas lu, un texture2d() est susceptible de lire ce qui est écrit.
 Flairant ce problème, Je m'en suis tenu à garder autant de textures que de niveaux, puis de finasser avec le shader qui va ensuite utiliser la pyramide (en faisant un mip maison avec 2 texture2d(), pas très élégant tout ça) .
Je m'y connais pas assez en gl, mais t'as pas autre chose que texture2d? en hlsl, tu peux sampler une texture en indiquant directement le mipmap à sampler par exemple...

ponce

  • Guest
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #3 on: 19 December 2010 à 02:20:30 »
glGenerateMipmaps fait ce que tu veux, ça construit les niveaux 1 à GL_TEXTURE_MAX_LEVEL à partir du niveau 0 je crois.
C'est rapide et ca se pipeline bien.

(Si tu veux supporter les ATI R500, attention car glGenerateMipmaps en crée pas forcément ces niveaux de mipmaps si ils n'existent pas.)

Par contre si un jour tu te sens limité par le box filter pas beau du mipmapping et que tu veux du beau flou gaussien tu peux vouloir faire tes mipmaps à la main avec deux pyramides et N FBO (un par niveau à construire). J'ai une implémentation de ça qui traine quelque part si il faut. Mais bon faut pas pousser mémé avec un marteau, pour une utilisation dans des niveaux pas trop élevé je te conseille le glGenerateMipmaps.

A noter qu'il existe un hint GL_GENERATE_MIPMAP_HINT pour choisir la qualité des mipmaps mais il me semble que la qualité NICEST est horriblement longue dans certaines implémentations (à tester).
« Last Edit: 19 December 2010 à 02:24:09 by ponce »

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #4 on: 19 December 2010 à 02:24:40 »
Tiens, j'avais vu ça dans ton code effectivement... je m'étais demandé pourquoi tu faisais comme ça... quand par exemple il y a déjà la méthode GenereateMips (mais je n'ai jamais testé pour voir si c'est bien implémenté sur le GPU... j'imagine que oui quand même). Bon, la différence aussi, c'est que tu peux créer tes textures en immutable, alors qu'avec un GenerateMips, elles doivent obligatoirement être aussi des rendertargets...

Oui voilà, si t'es en immutable alors zob pour le GenerateMips...
J'avais essayé de mettre ce flag à true dans mes premiers tests et effectivement, ça plantait tout le temps... Ta remarque sur le fait que ça marche que pour les render targets fait que ce flag prend tout son sens maintenant, thanks ! ;D
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #5 on: 19 December 2010 à 12:35:38 »
Oui voilà, si t'es en immutable alors zob pour le GenerateMips...
J'avais essayé de mettre ce flag à true dans mes premiers tests et effectivement, ça plantait tout le temps... Ta remarque sur le fait que ça marche que pour les render targets fait que ce flag prend tout son sens maintenant, thanks ! ;D
Code: [Select]
// For mipmaps, use GPU mipmap generator (for rendertarget and flags generate mipmaps)
if (description.MipLevels > 1)
{
    description.BindFlags |= BindFlags.RenderTarget;
    description.OptionFlags = ResourceOptionFlags.GenerateMipMaps;
}
Il ne faut pas oublier aussi de mettre le flag GenerateMipMaps dans OptionFlags dans Texture2DDescription. ;)

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #6 on: 19 December 2010 à 13:02:24 »
Code: [Select]
// For mipmaps, use GPU mipmap generator (for rendertarget and flags generate mipmaps)
if (description.MipLevels > 1)
{
    description.BindFlags |= BindFlags.RenderTarget;
    description.OptionFlags = ResourceOptionFlags.GenerateMipMaps;
}
Il ne faut pas oublier aussi de mettre le flag GenerateMipMaps dans OptionFlags dans Texture2DDescription. ;)

Mais par contre, il y a sans doute un inconvénient à gérer des textures read/write (i.e. render targets) par rapport à des readonly (i.e. immutable)... Les perfs sans doute non ? Certaines cartes doivent exploiter le fait qu'une zone mémoire est readonly pour speeder les calculs, d'où mon choix de générer les mips à la pougne au CPU et créer que des textures immutables... P'têt que je pourrais rajouter l'option "GenerateMipMaps" pour les render targets par contre ?

Mais est-ce que ça implique que si tu mets l'option sur une render target 1024x1024, quand tu écris par exemple dans le niveau 0 de cette RT, ça va automatiquement générer les 10 autres niveaux dans ton dos ? (genre, quand tu unbind la RT ?)
J'ai pas vu beaucoup d'explications à propos de ce flag...


Kraboub : on te rend ton thread ! Désolé ! ;D
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #7 on: 19 December 2010 à 13:09:51 »
Mais par contre, il y a sans doute un inconvénient à gérer des textures read/write (i.e. render targets) par rapport à des readonly (i.e. immutable)... Les perfs sans doute non ? Certaines cartes doivent exploiter le fait qu'une zone mémoire est readonly pour speeder les calculs, d'où mon choix de générer les mips à la pougne au CPU et créer que des textures immutables... P'têt que je pourrais rajouter l'option "GenerateMipMaps" pour les render targets par contre ?
La doc dit que le driver/la carte graphique peut optimiser les choses, mais je n'ai jamais vraiment fait un test pour vérifier qu'il y a par exemple un bénéfice sur les perfs. Il faudrait tester.
Mais est-ce que ça implique que si tu mets l'option sur une render target 1024x1024, quand tu écris par exemple dans le niveau 0 de cette RT, ça va automatiquement générer les 10 autres niveaux dans ton dos ? (genre, quand tu unbind la RT ?)
J'ai pas vu beaucoup d'explications à propos de ce flag...
Normalement, les mipmaps ne se génèrent que si tu appelles ID3D10Device::GenerateMips

nystep

  • Guest
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #8 on: 15 August 2011 à 17:13:02 »
Je m'excuse de ressusciter ce thread, mais j'ai le même problème sous OpenGL. La nouvelle extension ARB_shader_image_load_store devrait résoudre le problème, mais en attendant qu'elle soit vraiment supportée par les drivers, je me trouve forcé de faire un ping-pong entre deux textures mipmappées, et de copier les résultats qui sont stockés sur la texture temporaire.

Dans mon cas, je souhaite construire la pyramide de mipmaps où chaque élément est le maximum des 4 texels du niveau inférieur (n-1).

Offline MooZ

  • Base
    • Pouet.net
    • View Profile
    • Lair of the procrastinators
  • Groupe: BlockoS
  • Rôle: Dieu vivant du code sans fin
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #9 on: 15 August 2011 à 22:43:01 »
Voilà en gros ce que j'ai dans mon super code de la mort qui tue qui prend la poussière (en espérant que j'ai compris ta question :) )
La création des fbo pour le downsampling (tu peux les utiliser dans l'autre sens aussi) :
Code: [Select]
for(int i=0; i<_mipmap[0]->Level(); ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, _downsampleFbo[i]);
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _mipmap[0]->Id(), i+1 );
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
GLenum err = glGetError();
Log_Error("Failed with error %x : %s", status, gluErrorString(err));
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}

Et lors du rendu:
Code: [Select]
// Tu fais d'abord ton rendu dans _mimap[0] avec le level 0
for(int i=0; i<_mipmap[0]->Level(); ++i)
{
w>>=1; h>>=1;
glViewport(0, 0, w,h);
glBindFramebuffer(GL_FRAMEBUFFER, _downsampleFbo[i]);
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _mipmap[0]->Id(), i+1 );
glDrawBuffer( GL_COLOR_ATTACHMENT0 );

// Et la tu n'as qu'à binder ton shader qui fait juste un gl_FragData = max(tex00, max(tex01,  max(tex11, tex10)));
_mipmap[0]->Bind(0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i);
g_UnitQuad.Draw();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
_mipmap[0]->Unbind();
}
La scène est marne en 77.

Offline MsK`

  • Base
    • Pouet.net
    • View Profile
  • Rôle: Code
  • Ville: Paris/RP
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #10 on: 16 August 2011 à 11:37:25 »
C'est moi ou ça sent les histopyramides ? Pour des marching cubes ? Je serais super intéressé par le résultat :)

nystep

  • Guest
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #11 on: 16 August 2011 à 15:15:36 »
Merci beaucoup Mooz, j'avoue que ça marche mieux comme ça. :)
J'ai cru au début que ça marchait pas car les niveaux de mipmaps était tous à 0, mais en fait c'était un typo dans le vertex shader .. :-[ Maintenant ça va (presque), reste quelques soucis d'offset car je n'obtiens pas toujours le bon maximum, ce qui génère des artefacts, mais c'est déjà mieux.. :)

Code: [Select]
    void texture2d::generateMipmapsMax()
    {
        static int mipmapSzXID, mipmapSzYID, mipmapLodID;

        static shader* shMaxMipmap;
        static shaderUniformSet *shMaxMipmapUniforms;
        static shaderTextureSet *shMaxMipmapTextures;

        int renderSx, renderSy;
        int maxMipmapLevel = 16;

        glBindTexture( target, textureId );
        glGenerateMipmap( target );
        glGetTexLevelParameteriv( target, 0, GL_TEXTURE_WIDTH, &renderSx );
        glGetTexLevelParameteriv( target, 0, GL_TEXTURE_HEIGHT, &renderSy );
        glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
        glTexParameteri( target, GL_TEXTURE_WRAP_S, GL_CLAMP );
        glTexParameteri( target, GL_TEXTURE_WRAP_T, GL_CLAMP );

        if (!shMaxMipmap)
        {
            shMaxMipmap = new shader;
            shMaxMipmap->load( "shMaxMipmap" );

            shMaxMipmapUniforms = new shaderUniformSet;
            mipmapSzXID = shMaxMipmapUniforms->addInt( "mipmapSzX" );
            mipmapSzYID = shMaxMipmapUniforms->addInt( "mipmapSzY" );
            mipmapLodID = shMaxMipmapUniforms->addInt( "lod" );

            shMaxMipmapTextures = new shaderTextureSet;
            shMaxMipmapTextures->add( this, "tex", 0 );
        }

        static unsigned int fboPyramid[16];

        glPushAttrib( GL_VIEWPORT_BIT );

        for (int i=1; i<maxMipmapLevel; i++)
        {
            renderSx /= 2;
            renderSy /= 2;

            if (renderSx == 0 || renderSy == 0) break;

            shMaxMipmapUniforms->updateInt( mipmapSzXID, renderSx );
            shMaxMipmapUniforms->updateInt( mipmapSzYID, renderSy );
            shMaxMipmapUniforms->updateInt( mipmapLodID, 0 );
            glTexParameteri( target, GL_TEXTURE_BASE_LEVEL, i-1 );

            assert( glGetError() == GL_NO_ERROR );

            glGenFramebuffers( 1, &fboPyramid[i] );
            glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboPyramid[i] );
            glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, textureId, i );

            assert( glGetError() == GL_NO_ERROR );

            /// render to texture
            glViewport( 0, 0, renderSx, renderSy );

            glUseProgram( shMaxMipmap->programID );
            shMaxMipmapTextures->setTextures( shMaxMipmap );
            shMaxMipmapUniforms->setUniforms( shMaxMipmap );

            static float quadTexCoords[8] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f };
            static float quadVertex[12] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f };
            static unsigned int quadIndices[6] = { 0, 1, 2, 0, 2, 3 };

            glEnableClientState( GL_VERTEX_ARRAY );
            glVertexPointer( 3, GL_FLOAT, 0, quadVertex );
            glEnableClientState( GL_TEXTURE_COORD_ARRAY );
            glTexCoordPointer( 2, GL_FLOAT, 0, quadTexCoords );

            glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, quadIndices );

            glDisableClientState( GL_TEXTURE_COORD_ARRAY );
            glDisableClientState( GL_VERTEX_ARRAY );

            shMaxMipmapTextures->unSetTextures();
            glUseProgram( 0 );

            glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );

            assert( glGetError() == GL_NO_ERROR );
        }

        glBindTexture( target, textureId );
        glTexParameteri( target, GL_TEXTURE_BASE_LEVEL, 0 );
        glBindTexture( target, 0 );
        glPopAttrib();

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #12 on: 16 August 2011 à 16:47:53 »
A noter que moi j'ai eu des soucis en faisant Width >>= 2 et compagnie sur les petits niveaux de détails genre 4x4, 2x2 et 1x1...
J'ai dû utiliser :
Code: [Select]
Width = MAX( 1, (Width+1) >> 1);
Height = MAX( 1, (Height+1) >> 1);

C'est dans le cas où vos tailles de textures ne sont pas des puissances de 2.
Si on fait un downsampling classique où l'on sample 4 texels pour n'en donner plus qu'un par exemple, on ne veut pas passer d'une taille de 3x2 => 1x1 mais plutôt 3x2 => 2x1 sinon on rate un texel...
.  Pom  .

Offline MooZ

  • Base
    • Pouet.net
    • View Profile
    • Lair of the procrastinators
  • Groupe: BlockoS
  • Rôle: Dieu vivant du code sans fin
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #13 on: 16 August 2011 à 22:27:00 »
Les textures dont la taille n'est pas une puissance de 2 sont ma bête noire :(
Comment fait-t-on lorsque ça ne tombe pas juste? Par exemple lorsqu'on calcule une moyenne sur 8x8 et une des dimension n'est pas un multiple de 8.
Je pensais mettre à jour le poids de la manière suivante
Code: [Select]
w += (1.0 - step(u, 1.0)) * (1.0 - step(v, 1.0)) Mais j'ai plutôt l'impression de me faire chier pour rien.
La scène est marne en 77.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : OpenGL 2.x: Pyramides/Mipmap temps réel ?
« Reply #14 on: 16 August 2011 à 23:12:39 »
Tu peux aussi utiliser l'address mode CLAMP, comme ça si tu dépasses de 1 pixel bah tu resamples le dernier pixel...
.  Pom  .