Added methods for applying the current transform feedback buffers.

BUG=angle:495

Change-Id: I2d9fbf9c245bc519b8c5a724ca3912aaa7a23d97
Reviewed-on: https://chromium-review.googlesource.com/185034
Tested-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/Buffer.cpp b/src/libGLESv2/Buffer.cpp
index 7af7c80..a032ce6 100644
--- a/src/libGLESv2/Buffer.cpp
+++ b/src/libGLESv2/Buffer.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 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.
 //
@@ -141,6 +141,12 @@
     return mMapLength;
 }
 
+void Buffer::markTransformFeedbackUsage()
+{
+    mBufferStorage->markTransformFeedbackUsage();
+    invalidateStaticData();
+}
+
 rx::StaticVertexBufferInterface *Buffer::getStaticVertexBuffer()
 {
     return mStaticVertexBuffer;
diff --git a/src/libGLESv2/Buffer.h b/src/libGLESv2/Buffer.h
index 33bbff8..a45e9dd 100644
--- a/src/libGLESv2/Buffer.h
+++ b/src/libGLESv2/Buffer.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 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.
 //
@@ -49,6 +49,8 @@
     rx::BufferStorage *getStorage() const;
     unsigned int size() const;
 
+    void markTransformFeedbackUsage();
+
     rx::StaticVertexBufferInterface *getStaticVertexBuffer();
     rx::StaticIndexBufferInterface *getStaticIndexBuffer();
     void invalidateStaticData();
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 8c1cd3c..a6dba2a 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 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.
 //
@@ -2619,7 +2619,38 @@
     return programBinary->applyUniformBuffers(boundBuffers);
 }
 
+bool Context::applyTransformFeedbackBuffers()
+{
+    TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
+    if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+    {
+        Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+        GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+        for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+        {
+            transformFeedbackBuffers[i] = mState.transformFeedbackBuffers[i].get();
+            transformFeedbackOffsets[i] = mState.transformFeedbackBuffers[i].getOffset();
+        }
+        mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
 
+void Context::markTransformFeedbackUsage()
+{
+    for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    {
+        Buffer *buffer = mState.transformFeedbackBuffers[i].get();
+        if (buffer)
+        {
+            buffer->markTransformFeedbackUsage();
+        }
+    }
+}
 
 void Context::clear(GLbitfield mask)
 {
@@ -2945,6 +2976,8 @@
         return gl::error(err);
     }
 
+    bool transformFeedbackActive = applyTransformFeedbackBuffers();
+
     applyShaders(programBinary);
     applyTextures(programBinary);
 
@@ -2961,6 +2994,11 @@
     if (!skipDraw(mode))
     {
         mRenderer->drawArrays(mode, count, instances);
+
+        if (transformFeedbackActive)
+        {
+            markTransformFeedbackUsage();
+        }
     }
 }
 
@@ -3008,6 +3046,11 @@
         return gl::error(err);
     }
 
+    bool transformFeedbackActive = applyTransformFeedbackBuffers();
+    // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
+    // layer.
+    ASSERT(!transformFeedbackActive);
+
     applyShaders(programBinary);
     applyTextures(programBinary);
 
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index cc01ccb..1692f19 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 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.
 //
@@ -464,6 +464,8 @@
     void applyTextures(ProgramBinary *programBinary);
     void applyTextures(ProgramBinary *programBinary, SamplerType type);
     bool applyUniformBuffers();
+    bool applyTransformFeedbackBuffers();
+    void markTransformFeedbackUsage();
 
     void detachBuffer(GLuint buffer);
     void detachTexture(GLuint texture);
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 58e4932..2834f21 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -1670,6 +1670,16 @@
 
         if (context)
         {
+            gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
+            if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
+                curTransformFeedback->getDrawMode() != mode)
+            {
+                // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
+                // that does not match the current transform feedback object's draw mode (if transform feedback
+                // is active), (3.0.2, section 2.14, pg 86)
+                return gl::error(GL_INVALID_OPERATION);
+            }
+
             context->drawArrays(mode, first, count, 0);
         }
     }
@@ -1696,6 +1706,16 @@
 
             if (context)
             {
+                gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
+                if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
+                    curTransformFeedback->getDrawMode() != mode)
+                {
+                    // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
+                    // that does not match the current transform feedback object's draw mode (if transform feedback
+                    // is active), (3.0.2, section 2.14, pg 86)
+                    return gl::error(GL_INVALID_OPERATION);
+                }
+
                 context->drawArrays(mode, first, count, primcount);
             }
         }
@@ -1730,13 +1750,21 @@
               case GL_UNSIGNED_INT:
                 if (!context->supports32bitIndices())
                 {
-                    return gl::error(GL_INVALID_ENUM);    
+                    return gl::error(GL_INVALID_ENUM);
                 }
                 break;
               default:
                 return gl::error(GL_INVALID_ENUM);
             }
-        
+
+            gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
+            if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+            {
+                // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
+                // while transform feedback is active, (3.0.2, section 2.14, pg 86)
+                return gl::error(GL_INVALID_OPERATION);
+            }
+
             context->drawElements(mode, count, type, indices, 0);
         }
     }
@@ -1772,13 +1800,21 @@
                   case GL_UNSIGNED_INT:
                     if (!context->supports32bitIndices())
                     {
-                        return gl::error(GL_INVALID_ENUM);    
+                        return gl::error(GL_INVALID_ENUM);
                     }
                     break;
                   default:
                     return gl::error(GL_INVALID_ENUM);
                 }
-            
+
+                gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
+                if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+                {
+                    // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
+                    // while transform feedback is active, (3.0.2, section 2.14, pg 86)
+                    return gl::error(GL_INVALID_OPERATION);
+                }
+
                 context->drawElements(mode, count, type, indices, primcount);
             }
         }
diff --git a/src/libGLESv2/renderer/BufferStorage.h b/src/libGLESv2/renderer/BufferStorage.h
index 61cf201..c057b63 100644
--- a/src/libGLESv2/renderer/BufferStorage.h
+++ b/src/libGLESv2/renderer/BufferStorage.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2014 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.
 //
@@ -26,6 +26,7 @@
     virtual void copyData(BufferStorage* sourceStorage, unsigned int size,
                           unsigned int sourceOffset, unsigned int destOffset) = 0;
     virtual void clear() = 0;
+    virtual void markTransformFeedbackUsage() = 0;
     virtual unsigned int getSize() const = 0;
     virtual bool supportsDirectBinding() const = 0;
     unsigned int getSerial() const;
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index f15482c..fc9374e 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 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.
 //
@@ -132,6 +132,7 @@
     virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], gl::VertexAttribCurrentValueData currentValues[],
                                      GLint first, GLsizei count, GLsizei instances) = 0;
     virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
+    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) = 0;
 
     virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances) = 0;
     virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
index 29f5dff..2429696 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2013-2014 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.
 //
@@ -165,6 +165,12 @@
     mResolvedDataRevision = 0;
 }
 
+void BufferStorage11::markTransformFeedbackUsage()
+{
+    DirectBufferStorage11 *transformFeedbackStorage = getStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+    transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1);
+}
+
 unsigned int BufferStorage11::getSize() const
 {
     return mSize;
@@ -420,9 +426,9 @@
         bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
         break;
 
-      case BUFFER_USAGE_VERTEX:
+      case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
         bufferDesc->Usage = D3D11_USAGE_DEFAULT;
-        bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
+        bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
         bufferDesc->CPUAccessFlags = 0;
         break;
 
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.h b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
index 7cf976b..b4647f1 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.h
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2013-2014 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.
 //
@@ -19,11 +19,11 @@
 
 enum BufferUsage
 {
-    BUFFER_USAGE_STAGING = 0,
-    BUFFER_USAGE_VERTEX = 1,
-    BUFFER_USAGE_INDEX = 2,
-    BUFFER_USAGE_PIXEL_UNPACK = 3,
-    BUFFER_USAGE_UNIFORM = 4,
+    BUFFER_USAGE_STAGING,
+    BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK,
+    BUFFER_USAGE_INDEX,
+    BUFFER_USAGE_PIXEL_UNPACK,
+    BUFFER_USAGE_UNIFORM,
 };
 
 typedef size_t DataRevision;
@@ -41,6 +41,7 @@
     virtual void copyData(BufferStorage* sourceStorage, unsigned int size,
                           unsigned int sourceOffset, unsigned int destOffset);
     virtual void clear();
+    virtual void markTransformFeedbackUsage();
     virtual unsigned int getSize() const;
     virtual bool supportsDirectBinding() const;
 
diff --git a/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp b/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
index 748b058..fb64669 100644
--- a/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
+++ b/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
@@ -133,7 +133,8 @@
             ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
             ilKey.elementCount++;
 
-            vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX) : vertexBuffer->getBuffer();
+            vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
+                                             : vertexBuffer->getBuffer();
             vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
             vertexStrides[i] = attributes[i].stride;
             vertexOffsets[i] = attributes[i].offset;
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index 0c5104c..e73b20d 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 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.
 //
@@ -1180,6 +1180,44 @@
     return err;
 }
 
+void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[])
+{
+    ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    bool requiresUpdate = false;
+    for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    {
+        if (transformFeedbackBuffers[i])
+        {
+            BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(transformFeedbackBuffers[i]->getStorage());
+            ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+
+            d3dBuffers[i] = buffer;
+            d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast<UINT>(offsets[i]) : -1;
+        }
+        else
+        {
+            d3dBuffers[i] = NULL;
+            d3dOffsets[i] = 0;
+        }
+
+        if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i])
+        {
+            requiresUpdate = true;
+        }
+    }
+
+    if (requiresUpdate)
+    {
+        mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets);
+        for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+        {
+            mAppliedTFBuffers[i] = d3dBuffers[i];
+            mAppliedTFOffsets[i] = offsets[i];
+        }
+    }
+}
+
 void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
 {
     if (mode == GL_LINE_LOOP)
@@ -1683,6 +1721,13 @@
     mAppliedVertexShader = NULL;
     mAppliedGeometryShader = NULL;
     mAppliedPixelShader = NULL;
+
+    for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    {
+        mAppliedTFBuffers[i] = NULL;
+        mAppliedTFOffsets[i] = 0;
+    }
+
     memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants));
     memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants));
 
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/libGLESv2/renderer/d3d11/Renderer11.h
index 1a1ea0e..27eb7db 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.h
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 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.
 //
@@ -81,6 +81,7 @@
     virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], gl::VertexAttribCurrentValueData currentValues[],
                                      GLint first, GLsizei count, GLsizei instances);
     virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]);
 
     virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances);
     virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
@@ -343,10 +344,16 @@
     // Currently applied primitive topology
     D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
 
+    // Currently applied index buffer
     unsigned int mAppliedIBSerial;
     unsigned int mAppliedStorageIBSerial;
     unsigned int mAppliedIBOffset;
 
+    // Currently applied transform feedback buffers
+    ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+
+    // Currently applied shaders
     ID3D11VertexShader *mAppliedVertexShader;
     ID3D11GeometryShader *mAppliedGeometryShader;
     ID3D11PixelShader *mAppliedPixelShader;
diff --git a/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp b/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp
index 81cd4aa..5f0ef75 100644
--- a/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp
+++ b/src/libGLESv2/renderer/d3d9/BufferStorage9.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2013-2014 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.
 //
@@ -78,6 +78,11 @@
     mSize = 0;
 }
 
+void BufferStorage9::markTransformFeedbackUsage()
+{
+    UNREACHABLE();
+}
+
 unsigned int BufferStorage9::getSize() const
 {
     return mSize;
diff --git a/src/libGLESv2/renderer/d3d9/BufferStorage9.h b/src/libGLESv2/renderer/d3d9/BufferStorage9.h
index df13423..07ceb37 100644
--- a/src/libGLESv2/renderer/d3d9/BufferStorage9.h
+++ b/src/libGLESv2/renderer/d3d9/BufferStorage9.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2013-2014 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.
 //
@@ -27,6 +27,7 @@
     virtual void copyData(BufferStorage* sourceStorage, unsigned int size,
                           unsigned int sourceOffset, unsigned int destOffset);
     virtual void clear();
+    virtual void markTransformFeedbackUsage();
     virtual unsigned int getSize() const;
     virtual bool supportsDirectBinding() const;
 
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
index fde80b8..f719323 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
@@ -1,6 +1,6 @@
 #include "precompiled.h"
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 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.
 //
@@ -1447,6 +1447,11 @@
     return err;
 }
 
+void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[])
+{
+    UNREACHABLE();
+}
+
 void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
 {
     startScene();
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.h b/src/libGLESv2/renderer/d3d9/Renderer9.h
index f568cb1..6c9a509 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.h
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.h
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2014 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.
 //
@@ -83,6 +83,8 @@
                                      GLint first, GLsizei count, GLsizei instances);
     virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
 
+    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]);
+
     virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances);
     virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);