On OpenGL nuances

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

On OpenGL nuances

Postby Julio Jerez » Thu Jan 13, 2011 8:13 pm

Does any one know why in OpenGL a Display List is about twice as fast as a Vertex Buffer Objects and 3 to 5 time faster than a Vertex Array.

for what I can see a display list does not offer the possibility of sharing vertices, so they will use more memory and will not use the vertex cache in the GPU
yet a display List of GL_TRIANGLES or GL_TRINGLE_LIST is way faster tha VS and VBO.

could it be that the driver internally optimize DL to share Vertices?
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGl nuance

Postby JernejL » Fri Jan 14, 2011 4:28 am

It's possible it caches the data in the gpu memory itself somehow, and just initiates a pre-compiled gpu program to render the shapes again, which could explain the speed.

Anyway, VBOs are still the way to go, most of older gpus are still faster at VBOs than display lists.

Also, why do you need to share data between shapes? if it's a single shape (as a VBO usually also is), then you can just render the same display list at different places.
Help improving the Newton Game Dynamics WIKI
User avatar
JernejL
 
Posts: 1587
Joined: Mon Dec 06, 2004 2:00 pm
Location: Slovenia

Re: On OpenGl nuance

Postby thedmd » Fri Jan 14, 2011 5:41 am

Display List data is indeed cached in GPU memory, but there is one significant difference between them and VBO. Execution time of DL is a constant, for VBO this is not true. Performance of VBO depends from various factors, most important are vertex format and data size. If you choose those two wisely, VBO performance will be better than DL. Unfortunately I cannot give you a hint how vertex format should look like and what VBO sizes are best, because I do not have much experience in this area. I just to use DirectX.
thedmd
 

Re: On OpenGL nuances

Postby Julio Jerez » Fri Jan 14, 2011 11:35 am

well what I am seen is that Display List are about 5 time faster that Vertex array, but that may be because in Alchemedia editor I have to do lot of work to extract the geometry for rendering in the four viewports.
I am using display List as Geometry cache and what I like about it is that they do not need Maintenance, just an integer that I can keep track and regenerate each time part of the mesh changes.
However I am having lot of problem having OpenGL to render in multiples viewports.
When I use Vertex array, the textures only show up in one of the view ports, the other three come in white color.
When I use Display List then it only renders in the first viewport but the textures do not show up.
It is like everything that is in the GPU memory is only associated with one viewport.
I though that the function wglMakeCurrent is what associate the device wit the corrent viewport but aparentlly not.
The is what I do at the beginning of rendering on one view port
Code: Select all
void alchemediaView::OnDraw(CDC* dc)
{
   alchemediaDoc* doc = GetDocument();
   ASSERT_VALID(doc);
   if (!(doc && doc->GetCurWorld()))
      return;


   BOOL state = wglMakeCurrent(dc->GetSafeHdc(), m_renderContext);
   _ASSERTE (state);

And this is the change from Vertex Array to display List.


Code: Select all
void alchemediaStaticMesh::UpdateDisplayList(dScene* const world, dScene::dTreeNode* const myNode) const
{
   if (!m_dipalyList) {

      m_dipalyList = glGenLists(1);

      glNewList(m_dipalyList, GL_COMPILE);

      int stride = NewtonMeshGetPointStrideInByte(m_mesh) / sizeof (dFloat);
      float* const vertexArray = NewtonMeshGetPointArray(m_mesh);
      float* const normalArray = NewtonMeshGetNormalArray(m_mesh);
      float* const uv0Array = NewtonMeshGetUV0Array(m_mesh);

      for (void* ptr = world->GetFirstChild(myNode); ptr; ptr = world->GetNextChild(myNode, ptr)) {
         dScene::dTreeNode* const materialNode = world->GetNodeFromLink (ptr);
         dNodeInfo* const info = world->GetInfoFromNode(materialNode);
         if (info->IsType(dMaterialNodeInfo::GetRttiType())) {
            dMaterialNodeInfo* const material = (dMaterialNodeInfo*) info;

            glMaterialfv(GL_FRONT, GL_SPECULAR, &material->GetSpecularColor().m_x);
            glMaterialfv(GL_FRONT, GL_AMBIENT, &material->GetAmbientColor().m_x);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, &material->GetDiffuseColor().m_x);
            glMaterialfv(GL_FRONT, GL_EMISSION, &material->GetEmissiveColor().m_x);
            glMaterialf(GL_FRONT, GL_SHININESS, material->GetShininess());

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

            dTextureNodeInfo* diffuseTex = NULL;
            dScene::dTreeNode* diffTexNode = world->FindTextureByTextId (materialNode, material->GetDiffuseTextId());
            if (diffTexNode){
               diffuseTex = (dTextureNodeInfo*) world->GetInfoFromNode(diffTexNode);
            }

            if (diffuseTex && (diffuseTex->GetInternalId() != -1)) {
               glEnable(GL_TEXTURE_2D);      
               glBindTexture(GL_TEXTURE_2D, GLuint (diffuseTex->GetInternalId()));
            } else {
               glDisable(GL_TEXTURE_2D);
            }

            glBegin(GL_TRIANGLES);
            int id = material->GetId();
            for (void* face = NewtonMeshGetFirstFace (m_mesh); face; face = NewtonMeshGetNextFace (m_mesh, face)) {

               if (!NewtonMeshIsFaceOpen (m_mesh, face)) {
                  int materialID = NewtonMeshGetFaceMaterial (m_mesh, face);   
                  if (materialID == id) {
                     int vertexCount = NewtonMeshGetFaceIndexCount (m_mesh, face);
                     int indices[1024];
                     NewtonMeshGetFacePointIndices (m_mesh, face, indices);

                     int index = indices[0] * stride;
                     dVector uv0 (uv0Array[index], uv0Array[index + 1], 0.0f, 0.0f);
                     dVector normal0 (normalArray[index], normalArray[index + 1], normalArray[index + 2], 0.0f);
                     dVector point0 (vertexArray[index], vertexArray[index + 1], vertexArray[index + 2], 0.0f);

                     index = indices[1] * stride;
                     dVector uv1 (uv0Array[index], uv0Array[index + 1], 0.0f, 0.0f);
                     dVector normal1 (normalArray[index], normalArray[index + 1], normalArray[index + 2], 0.0f);
                     dVector point1 (vertexArray[index], vertexArray[index + 1], vertexArray[index + 2], 0.0f);

                     for (int i = 2; i < vertexCount; i ++) {

                        int index = indices[i] * stride;
                        dVector uv2 (uv0Array[index], uv0Array[index + 1], 0.0f, 0.0f);
                        dVector normal2 (normalArray[index], normalArray[index + 1], normalArray[index + 2], 0.0f);
                        dVector point2 (vertexArray[index], vertexArray[index + 1], vertexArray[index + 2], 0.0f);

                        glTexCoord2f(uv0.m_x, uv0.m_y);
                        glNormal3f (normal0.m_x, normal0.m_y, normal0.m_z);
                        glVertex3f(point0.m_x, point0.m_y, point0.m_z);

                        glTexCoord2f(uv1.m_x, uv1.m_y);
                        glNormal3f (normal1.m_x, normal1.m_y, normal1.m_z);
                        glVertex3f(point1.m_x, point1.m_y, point1.m_z);

                        glTexCoord2f(uv2.m_x, uv2.m_y);
                        glNormal3f (normal2.m_x, normal2.m_y, normal2.m_z);
                        glVertex3f(point2.m_x, point2.m_y, point2.m_z);

                        uv1 = uv2;
                        normal1 = normal2;
                        point1 = point2;
                     }
                  }
               }
            }
            glEnd();
         }
      }

      glEndList();
   }
}


// draw scene in Gouraud shaded normal textured mode
void alchemediaStaticMesh::DrawGouraudShaded(dScene* world, dScene::dTreeNode* myNode, const dVector& color, int* const workBuffer, int worlfBufferInBytes) const
{
   _ASSERTE (world->GetInfoFromNode(myNode) == this);


#if 1
   // this uses Vertex arrays but it is slow and only show the textures in one viewport

   int bufferSize = (worlfBufferInBytes / sizeof (int)) / 2;
   int* buffer0 = &workBuffer[0];
   int* buffer1 = &workBuffer[bufferSize];

   int* doubleBufferPtr[2];
   doubleBufferPtr[0] = buffer0;
   doubleBufferPtr[1] = buffer1;

   //   int vertexCount = NewtonMeshGetPointCount(m_mesh);
   int stride = NewtonMeshGetPointStrideInByte(m_mesh);
   //   float* vertexList = NewtonMeshGetPointArray(m_mesh);

   float* const vertexArray = NewtonMeshGetPointArray(m_mesh);
   float* const normalArray = NewtonMeshGetNormalArray(m_mesh);
   float* const uv0Array = NewtonMeshGetUV0Array(m_mesh);

   glPushMatrix();
   glMultMatrix(&m_matrix[0][0]);

   glEnableClientState (GL_VERTEX_ARRAY);
   glEnableClientState (GL_NORMAL_ARRAY);
   glEnableClientState (GL_TEXTURE_COORD_ARRAY);

   glVertexPointer (4, GL_FLOAT, stride, vertexArray);
   glNormalPointer (GL_FLOAT, stride, normalArray);
   glTexCoordPointer (2, GL_FLOAT, stride, uv0Array);


   int pointCount = 0;
   int bufferIndex = 0;
   int* buffer = doubleBufferPtr[bufferIndex];

   for (void* ptr = world->GetFirstChild(myNode); ptr; ptr = world->GetNextChild(myNode, ptr)) {
      dScene::dTreeNode* materialNode = world->GetNodeFromLink (ptr);
      dNodeInfo* info = world->GetInfoFromNode(materialNode);
      if (info->IsType(dMaterialNodeInfo::GetRttiType())) {
         dMaterialNodeInfo* material = (dMaterialNodeInfo*) info;

         glMaterialfv(GL_FRONT, GL_SPECULAR, &material->GetSpecularColor().m_x);
         glMaterialfv(GL_FRONT, GL_AMBIENT, &material->GetAmbientColor().m_x);
         glMaterialfv(GL_FRONT, GL_DIFFUSE, &material->GetDiffuseColor().m_x);
         glMaterialfv(GL_FRONT, GL_EMISSION, &material->GetEmissiveColor().m_x);
         glMaterialf(GL_FRONT, GL_SHININESS, material->GetShininess());

         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

         dTextureNodeInfo* diffuseTex = NULL;
         dScene::dTreeNode* diffTexNode = world->FindTextureByTextId (materialNode, material->GetDiffuseTextId());
         if (diffTexNode){
            diffuseTex = (dTextureNodeInfo*) world->GetInfoFromNode(diffTexNode);
         }

         if (diffuseTex && (diffuseTex->GetInternalId() != -1)) {
            glEnable(GL_TEXTURE_2D);      
            glBindTexture(GL_TEXTURE_2D, GLuint (diffuseTex->GetInternalId()));
         } else {
            glDisable(GL_TEXTURE_2D);
         }

         int id = material->GetId();
         for (void* face = NewtonMeshGetFirstFace (m_mesh); face; face = NewtonMeshGetNextFace (m_mesh, face)) {

            if (!NewtonMeshIsFaceOpen (m_mesh, face)) {
               int materialID = NewtonMeshGetFaceMaterial (m_mesh, face);   
               if (materialID == id) {
                  int vertexCount = NewtonMeshGetFaceIndexCount (m_mesh, face);
                  if ((pointCount + 3 * (vertexCount - 2)) >= bufferSize) {
                     glDrawElements (GL_TRIANGLES, pointCount, GL_UNSIGNED_INT, buffer);
                     bufferIndex = (bufferIndex + 1) & 1;
                     buffer = doubleBufferPtr[bufferIndex];
                     pointCount = 0;
                  }
                  int indices[1024];
                  NewtonMeshGetFacePointIndices (m_mesh, face, indices);

                  for (int i = 2; i < vertexCount; i ++) {
                     buffer[pointCount + 0] = indices[0];
                     buffer[pointCount + 1] = indices[i - 1];
                     buffer[pointCount + 2] = indices[i];
                     pointCount += 3;
                  }
               }
            }
         }

         if (pointCount) {
            glDrawElements (GL_TRIANGLES, pointCount, GL_UNSIGNED_INT, buffer);
            bufferIndex = (bufferIndex + 1) & 1;
            buffer = doubleBufferPtr[bufferIndex];
            pointCount = 0;
         }
      }
   }

   glDisableClientState(GL_VERTEX_ARRAY);   // disable vertex arrays
   glDisableClientState(GL_NORMAL_ARRAY);   // disable normal arrays
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);   // disable normal arrays

   glPopMatrix();

#else

   // this uses Display list it is extremely fast, about 5 time faster than VA and VBO, however
    // it only render on view port without textures. It look like anythonmg stored on teh device memory only renders i one viewport
    // does anyone know what is wrong?  I cannot figure it out

   UpdateDisplayList(world, myNode);

   glPushMatrix();
   glMultMatrix(&m_matrix[0][0]);

   glCallList(m_dipalyList);

   glPopMatrix();

#endif
}



does anyone had made an application using Open GL and rendering to different view ports?
if so can you tell my what I am doing wrong?
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGL nuances

Postby Julio Jerez » Fri Jan 14, 2011 12:28 pm

Oh I beileve I found whi the display list do not render on different windows, aparantly device objects are not shared between windows contex by default
But it looks like there is a way to force OpenGl to share display list by using this function wglShareLists

http://msdn.microsoft.com/en-us/library/ms537565(VS.85).aspx

I will try
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGL nuances

Postby Julio Jerez » Fri Jan 14, 2011 12:48 pm

wow it is awesome, all I have to do was adding this
Code: Select all
   // share all display List among view ports
   wglShareLists(m_viewPort0->m_renderContext, m_viewPort1->m_renderContext);
   wglShareLists(m_viewPort0->m_renderContext, m_viewPort2->m_renderContext);
   wglShareLists(m_viewPort0->m_renderContext, m_viewPort3->m_renderContext);


and the mesh I am going to use for the collsion tree demo is a mediaon size public domanin mess called teh SponzaAtrium with 66500 triangles
It is rendered 4 time, one in each viewport and is does like knife through butter.
with Vertex Arrays you can see the disply refreshing when I move the screen but with Dsiplay List is trully real time.
So at list in teh case caching for reending in a Level editor Disaply List are a very, very good compormize.
The are simple to use, selt maintaned and Fast, Amazing.

now all I have ot find is a small bug the is misng a textuyre is soem face and I will post 2.30 with new demos and some improvements.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGL nuances

Postby thedmd » Fri Jan 14, 2011 3:29 pm

Nice you found the solution. wglShareLists() was my bet. I think it will works also for textures.
I'm looking forward to see your progress.
thedmd
 

Re: On OpenGL nuances

Postby Julio Jerez » Fri Jan 14, 2011 3:50 pm

Yes It fixes the missing texture too, awesome.
The ony problem now is that I do no see hwo I can render Skin Meshes using Display List.
I do not think it is possible, but Maybe I can use Vertex Arrays for Skin meshes.

Anyway I also have a set of Icons provide by Newton and Forum user TSX. so now I have all I need to complete teh Navagation part of the editor.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGL nuances

Postby Leadwerks » Fri Jan 14, 2011 10:30 pm

I'm really surprised you are even using this. Use vertex buffer objects. Don't bother with display lists. It's not even supported anymore in newer versions of OpenGL.

It may be possible that with a simple mesh display lists can somehow render faster, but with a a few thousand vertices VBO will always be fastest.
User avatar
Leadwerks
 
Posts: 569
Joined: Fri Oct 27, 2006 2:54 pm

Re: On OpenGL nuances

Postby Julio Jerez » Fri Jan 14, 2011 11:13 pm

but I tried that and rendering 240,000 triangles Display list are much much faster than both VBO and VA.
I know it does not make sence bu it is what I am seeing.

there is also anothe thong, VBO are not a standar feature in opengl you must use ARB extension.
ARB extersnion may fail from systems to systems, at leat that was what I experience ion teh pass when I tryied.
I had all kind of bugs reports from Linux, Mac, and even older windows users on ATI systems.
That is why I had to change to use Vertex Arrays.
The was 3 or 4 year ago, so maybe VBO are standart now

I will probably will end up using VBO too, but for now display List are very eassy to use and I can move on, on the mesh editor.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: On OpenGL nuances

Postby thedmd » Sat Jan 15, 2011 9:36 am

Julio Jerez wrote:but I tried that and rendering 240,000 triangles Display list are much much faster than both VBO and VA.
I know it does not make sence bu it is what I am seeing.

Unfortunate thing is, performance of VBO seems to be dependent from vertex format. D3D9 recommend to keep vertices aligned to 32 bytes, maybe for OpenGL this also be true. More unfortunate thing is, I didn't found any hints how to use VBO to gain performance instead of penalty.

I agree with Julio. It is more important to go forward with the work on the Newton. All support tools can be optimized latter if they works in current state. There are people on the forum who want to contribute something to Newton. This is probably the place where they can help.
thedmd
 

Re: On OpenGL nuances

Postby Leadwerks » Mon Jan 17, 2011 5:17 pm

Some drivers will render in software mode if your vertex data isn't 32-bit aligned, like if you used an RGB color array instead of RGBA.
User avatar
Leadwerks
 
Posts: 569
Joined: Fri Oct 27, 2006 2:54 pm

Re: On OpenGL nuances

Postby Julio Jerez » Mon Jan 17, 2011 5:48 pm

32 bit or 32 bytes?
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles



Return to General Discussion

Who is online

Users browsing this forum: No registered users and 2 guests