Translate/lift vertex attributes when input stride or offset is not a multiple of 4.

TRAC #11847

Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch

Author:    Andrew Lewycky

git-svn-id: https://angleproject.googlecode.com/svn/trunk@149 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/geometry/VertexDataManager.cpp b/src/libGLESv2/geometry/VertexDataManager.cpp
index 54e894c..a8766ce 100644
--- a/src/libGLESv2/geometry/VertexDataManager.cpp
+++ b/src/libGLESv2/geometry/VertexDataManager.cpp
@@ -128,12 +128,22 @@
         {
             if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
             {
-                translated[i].type = attribs[i].mType;
-                translated[i].size = attribs[i].mSize;
-                translated[i].normalized = attribs[i].mNormalized;
-                translated[i].stride = interpretGlStride(attribs[i]);
-                translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;
-                translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
+                std::size_t stride = interpretGlStride(attribs[i]);
+                std::size_t offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;
+
+                if (mBackend->validateStream(attribs[i].mType, attribs[i].mSize, stride, offset))
+                {
+                    translated[i].type = attribs[i].mType;
+                    translated[i].size = attribs[i].mSize;
+                    translated[i].normalized = attribs[i].mNormalized;
+                    translated[i].stride = stride;
+                    translated[i].offset = offset;
+                    translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
+                }
+                else
+                {
+                    translateOrLift[i] = true;
+                }
             }
             else
             {
diff --git a/src/libGLESv2/geometry/backend.h b/src/libGLESv2/geometry/backend.h
index 8c3cd04..16afbdc 100644
--- a/src/libGLESv2/geometry/backend.h
+++ b/src/libGLESv2/geometry/backend.h
@@ -57,6 +57,9 @@
     virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size) = 0;
     virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize) = 0;
 
+    // For an identity-mappable stream, verify that the stride and offset are okay.
+    virtual bool validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const = 0;
+
     virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo) = 0;
     virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes) = 0;
 };
diff --git a/src/libGLESv2/geometry/dx9.cpp b/src/libGLESv2/geometry/dx9.cpp
index c6681e9..0e90a7d 100644
--- a/src/libGLESv2/geometry/dx9.cpp
+++ b/src/libGLESv2/geometry/dx9.cpp
@@ -170,6 +170,12 @@
     }
 }
 
+bool Dx9BackEnd::validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const
+{
+    // D3D9 requires the stream offset and stride to be a multiple of DWORD.
+    return (stride % sizeof(DWORD) == 0 && offset % sizeof(DWORD) == 0);
+}
+
 IDirect3DVertexBuffer9 *Dx9BackEnd::getDxBuffer(TranslatedVertexBuffer *vb) const
 {
     return vb ? static_cast<Dx9VertexBuffer*>(vb)->getBuffer() : NULL;
diff --git a/src/libGLESv2/geometry/dx9.h b/src/libGLESv2/geometry/dx9.h
index 3e49672..27afd68 100644
--- a/src/libGLESv2/geometry/dx9.h
+++ b/src/libGLESv2/geometry/dx9.h
@@ -27,6 +27,8 @@
     virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size);
     virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize);
 
+    virtual bool validateStream(GLenum type, std::size_t size, std::size_t stride, std::size_t offset) const;
+
     virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo);
     virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes);