Work around a bug observed with ATI graphics cards where instanced draw calls fail when all attributes are non-instanced, by repeating the draw call.

TRAC #19489
Signed-off-by: Daniel Koch
Author: Nicolas Capens

git-svn-id: http://angleproject.googlecode.com/svn/trunk@974 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 9d63e6b..2783a44 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -2245,7 +2245,7 @@
     }
 }
 
-GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances)
+GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw)
 {
     TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
 
@@ -2255,7 +2255,7 @@
         return err;
     }
 
-    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram(), instances);
+    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram(), instances, repeatDraw);
 }
 
 // Applies the indices and element array bindings to the Direct3D 9 device
@@ -2941,7 +2941,8 @@
 
     applyState(mode);
 
-    GLenum err = applyVertexBuffer(first, count, instances);
+    GLsizei repeatDraw = 1;
+    GLenum err = applyVertexBuffer(first, count, instances, &repeatDraw);
     if (err != GL_NO_ERROR)
     {
         return error(err);
@@ -2974,7 +2975,10 @@
                     mAppliedIBSerial = countingIB->getSerial();
                 }
 
-                mDevice->DrawIndexedPrimitive(primitiveType, 0, 0, count, 0, primitiveCount);
+                for (int i = 0; i < repeatDraw; i++)
+                {
+                    mDevice->DrawIndexedPrimitive(primitiveType, 0, 0, count, 0, primitiveCount);
+                }
             }
             else
             {
@@ -3027,7 +3031,8 @@
     }
 
     GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
-    err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances);
+    GLsizei repeatDraw = 1;
+    err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances, &repeatDraw);
     if (err != GL_NO_ERROR)
     {
         return error(err);
@@ -3051,7 +3056,10 @@
         }
         else
         {
-            mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
+            for (int i = 0; i < repeatDraw; i++)
+            {
+                mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
+            }
         }
     }
 }
@@ -4055,19 +4063,35 @@
     }
 }
 
-GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances)
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances, GLsizei *repeatDraw)
 {
+    *repeatDraw = 1;
+
     int indexedAttribute = MAX_VERTEX_ATTRIBS;
+    int instancedAttribute = MAX_VERTEX_ATTRIBS;
 
     if (instances > 0)
     {
         // Find an indexed attribute to be mapped to D3D stream 0
         for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
         {
-            if (attributes[i].active && attributes[i].divisor == 0)
+            if (attributes[i].active)
             {
-                indexedAttribute = i;
-                break;
+                if (indexedAttribute == MAX_VERTEX_ATTRIBS)
+                {
+                    if (attributes[i].divisor == 0)
+                    {
+                        indexedAttribute = i;
+                    }
+                }
+                else if (instancedAttribute == MAX_VERTEX_ATTRIBS)
+                {
+                    if (attributes[i].divisor != 0)
+                    {
+                        instancedAttribute = i;
+                    }
+                }
+                else break;   // Found both an indexed and instanced attribute
             }
         }
 
@@ -4088,28 +4112,36 @@
 
             if (instances > 0)
             {
-                if (i == indexedAttribute)
+                // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
+                if (instancedAttribute == MAX_VERTEX_ATTRIBS)
                 {
-                    stream = 0;
-                }
-                else if (i == 0)
-                {
-                    stream = indexedAttribute;
-                }
-
-                UINT frequency = 1;
-                
-                if (attributes[i].divisor == 0)
-                {
-                    frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+                    *repeatDraw = instances;
                 }
                 else
                 {
-                    frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+                    if (i == indexedAttribute)
+                    {
+                        stream = 0;
+                    }
+                    else if (i == 0)
+                    {
+                        stream = indexedAttribute;
+                    }
+
+                    UINT frequency = 1;
+                    
+                    if (attributes[i].divisor == 0)
+                    {
+                        frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+                    }
+                    else
+                    {
+                        frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+                    }
+                    
+                    device->SetStreamSourceFreq(stream, frequency);
+                    mInstancingEnabled = true;
                 }
-                
-                device->SetStreamSourceFreq(stream, frequency);
-                mInstancingEnabled = true;
             }
 
             if (mAppliedVBs[stream].serial != attributes[i].serial ||
@@ -4132,7 +4164,7 @@
         }
     }
 
-    if (instances == 0)
+    if (instances == 0 || instancedAttribute == MAX_VERTEX_ATTRIBS)
     {
         if (mInstancingEnabled)
         {
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index e094f61..2b9c516 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -244,7 +244,7 @@
     VertexDeclarationCache();
     ~VertexDeclarationCache();
 
-    GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances);
+    GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances, GLsizei *repeatDraw);
 
     void markStateDirty();
 
@@ -511,7 +511,7 @@
 
     bool applyRenderTarget(bool ignoreViewport);
     void applyState(GLenum drawMode);
-    GLenum applyVertexBuffer(GLint first, GLsizei count, GLsizei instances);
+    GLenum applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw);
     GLenum applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
     void applyShaders();
     void applyTextures();