Pass uniform buffers active bound to uniform blocks of the active program to HLSL/D3D constant buffers.

TRAC #22892

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Author: Jamie Madill

git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2339 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 10283d6..584b4ac 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -22,6 +22,7 @@
 #include "libGLESv2/renderer/Renderer.h"
 #include "libGLESv2/renderer/VertexDataManager.h"
 #include "libGLESv2/Context.h"
+#include "libGLESv2/Buffer.h"
 
 #undef near
 #undef far
@@ -317,6 +318,12 @@
     return GL_INVALID_INDEX;
 }
 
+UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
+{
+    ASSERT(blockIndex < mUniformBlocks.size());
+    return mUniformBlocks[blockIndex];
+}
+
 template <typename T>
 bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
 {
@@ -807,6 +814,51 @@
     mRenderer->applyUniforms(this, &mUniforms);
 }
 
+bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
+{
+    const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
+    const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
+
+    const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
+    const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
+
+    ASSERT(boundBuffers.size() == mUniformBlocks.size());
+
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
+    {
+        gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
+        gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
+
+        ASSERT(uniformBlock && uniformBuffer);
+
+        if (uniformBuffer->size() < uniformBlock->dataSize)
+        {
+            // undefined behaviour
+            return false;
+        }
+
+        ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
+
+        if (uniformBlock->isReferencedByVertexShader())
+        {
+            unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
+            ASSERT(vertexUniformBuffers[registerIndex] == NULL);
+            ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
+            vertexUniformBuffers[registerIndex] = uniformBuffer;
+        }
+
+        if (uniformBlock->isReferencedByFragmentShader())
+        {
+            unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
+            ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
+            ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
+            fragmentUniformBuffers[registerIndex] = uniformBuffer;
+        }
+    }
+
+    return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
+}
+
 // Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
 // Returns the number of used varying registers, or -1 if unsuccesful
 int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)