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();