D3D11: Work around Intel uniform buffers bug.

When copying from a staging buffer to a uniform buffer, the first
upload would be incorrect. Work around this by trying to upload
directly to a uniform buffer on the first BufferSubData call.

BUG=chromium:593024

Change-Id: I0df3a1422b962bf3ece5d445f435df01e3544b67
Reviewed-on: https://chromium-review.googlesource.com/368774
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index 609385f..2775fe9 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -3325,6 +3325,111 @@
             context->handleError(Error(GL_INVALID_ENUM));
             return false;
     }
+
+    return true;
+}
+
+bool ValidateBufferData(ValidationContext *context,
+                        GLenum target,
+                        GLsizeiptr size,
+                        const GLvoid *data,
+                        GLenum usage)
+{
+    if (size < 0)
+    {
+        context->handleError(Error(GL_INVALID_VALUE));
+        return false;
+    }
+
+    switch (usage)
+    {
+        case GL_STREAM_DRAW:
+        case GL_STATIC_DRAW:
+        case GL_DYNAMIC_DRAW:
+            break;
+
+        case GL_STREAM_READ:
+        case GL_STREAM_COPY:
+        case GL_STATIC_READ:
+        case GL_STATIC_COPY:
+        case GL_DYNAMIC_READ:
+        case GL_DYNAMIC_COPY:
+            if (context->getClientMajorVersion() < 3)
+            {
+                context->handleError(Error(GL_INVALID_ENUM));
+                return false;
+            }
+            break;
+
+        default:
+            context->handleError(Error(GL_INVALID_ENUM));
+            return false;
+    }
+
+    if (!ValidBufferTarget(context, target))
+    {
+        context->handleError(Error(GL_INVALID_ENUM));
+        return false;
+    }
+
+    Buffer *buffer = context->getGLState().getTargetBuffer(target);
+
+    if (!buffer)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    return true;
+}
+
+bool ValidateBufferSubData(ValidationContext *context,
+                           GLenum target,
+                           GLintptr offset,
+                           GLsizeiptr size,
+                           const GLvoid *data)
+{
+    if (size < 0 || offset < 0)
+    {
+        context->handleError(Error(GL_INVALID_VALUE));
+        return false;
+    }
+
+    if (!ValidBufferTarget(context, target))
+    {
+        context->handleError(Error(GL_INVALID_ENUM));
+        return false;
+    }
+
+    Buffer *buffer = context->getGLState().getTargetBuffer(target);
+
+    if (!buffer)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    if (buffer->isMapped())
+    {
+        context->handleError(Error(GL_INVALID_OPERATION));
+        return false;
+    }
+
+    // Check for possible overflow of size + offset
+    angle::CheckedNumeric<size_t> checkedSize(size);
+    checkedSize += offset;
+    if (!checkedSize.IsValid())
+    {
+        context->handleError(Error(GL_OUT_OF_MEMORY));
+        return false;
+    }
+
+    if (size + offset > buffer->getSize())
+    {
+        context->handleError(Error(GL_INVALID_VALUE));
+        return false;
+    }
+
     return true;
 }