Set the stream source frequencies for instanced draw calls. Searches for an indexed (non-instanced) attribute to ensure it gets mapped to stream 0.
TRAC #19489
Signed-off-by: Daniel Koch
Author: Nicolas Capens
git-svn-id: https://angleproject.googlecode.com/svn/trunk@969 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index eb53c7c..0e01a10 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
@@ -2250,7 +2250,7 @@
}
}
-GLenum Context::applyVertexBuffer(GLint first, GLsizei count)
+GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances)
{
TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
@@ -2260,7 +2260,7 @@
return err;
}
- return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram());
+ return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram(), instances);
}
// Applies the indices and element array bindings to the Direct3D 9 device
@@ -2810,6 +2810,11 @@
mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
@@ -2869,6 +2874,11 @@
mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
quad[0][0] = -0.5f;
quad[0][1] = mRenderTargetDesc.Height - 0.5f;
@@ -2911,7 +2921,7 @@
}
}
-void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
+void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
{
if (!mState.currentProgram)
{
@@ -2936,7 +2946,7 @@
applyState(mode);
- GLenum err = applyVertexBuffer(first, count);
+ GLenum err = applyVertexBuffer(first, count, instances);
if (err != GL_NO_ERROR)
{
return error(err);
@@ -2963,7 +2973,7 @@
}
}
-void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances)
{
if (!mState.currentProgram)
{
@@ -3001,7 +3011,7 @@
}
GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
- err = applyVertexBuffer(indexInfo.minIndex, vertexCount);
+ err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances);
if (err != GL_NO_ERROR)
{
return error(err);
@@ -3028,20 +3038,6 @@
}
}
-void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
-{
- UNIMPLEMENTED(); // TODO
-
- drawArrays(mode, first, count);
-}
-
-void Context::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount)
-{
- UNIMPLEMENTED(); // TODO
-
- drawElements(mode, count, type, indices);
-}
-
// Implements glFlush when block is false, glFinish when block is true
void Context::sync(bool block)
{
@@ -3990,8 +3986,28 @@
}
}
-GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program)
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances)
{
+ int indexedAttribute = 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)
+ {
+ indexedAttribute = i;
+ break;
+ }
+ }
+
+ if (indexedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ return GL_INVALID_OPERATION;
+ }
+ }
+
D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1];
D3DVERTEXELEMENT9 *element = &elements[0];
@@ -3999,17 +4015,45 @@
{
if (attributes[i].active)
{
- if (mAppliedVBs[i].serial != attributes[i].serial ||
- mAppliedVBs[i].stride != attributes[i].stride ||
- mAppliedVBs[i].offset != attributes[i].offset)
+ int stream = i;
+
+ if (instances > 0)
{
- device->SetStreamSource(i, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
- mAppliedVBs[i].serial = attributes[i].serial;
- mAppliedVBs[i].stride = attributes[i].stride;
- mAppliedVBs[i].offset = attributes[i].offset;
+ 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;
}
- element->Stream = i;
+ if (mAppliedVBs[stream].serial != attributes[i].serial ||
+ mAppliedVBs[stream].stride != attributes[i].stride ||
+ mAppliedVBs[stream].offset != attributes[i].offset)
+ {
+ device->SetStreamSource(stream, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
+ mAppliedVBs[stream].serial = attributes[i].serial;
+ mAppliedVBs[stream].stride = attributes[i].stride;
+ mAppliedVBs[stream].offset = attributes[i].offset;
+ }
+
+ element->Stream = stream;
element->Offset = 0;
element->Type = attributes[i].type;
element->Method = D3DDECLMETHOD_DEFAULT;
@@ -4019,6 +4063,19 @@
}
}
+ if (instances == 0)
+ {
+ if (mInstancingEnabled)
+ {
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+
+ mInstancingEnabled = false;
+ }
+ }
+
static const D3DVERTEXELEMENT9 end = D3DDECL_END();
*(element++) = end;
@@ -4073,6 +4130,7 @@
}
mLastSetVDecl = NULL;
+ mInstancingEnabled = true; // Forces it to be disabled when not used
}
}