From 4086effec00505cd6d7244e63e47dd4ff61126f4 Mon Sep 17 00:00:00 2001
From: Austin Eng <enga@google.com>
Date: Thu, 17 Aug 2017 14:03:14 -0400
Subject: [PATCH] Validate buffer view offset on bind groups

---
 src/backend/BindGroup.cpp                     |   6 +
 src/tests/CMakeLists.txt                      |   1 +
 .../validation/BindGroupValidationTests.cpp   | 105 ++++++++++++++++++
 3 files changed, 112 insertions(+)
 create mode 100644 src/tests/unittests/validation/BindGroupValidationTests.cpp

diff --git a/src/backend/BindGroup.cpp b/src/backend/BindGroup.cpp
index 0946c14d01..63c5c33484 100644
--- a/src/backend/BindGroup.cpp
+++ b/src/backend/BindGroup.cpp
@@ -19,6 +19,7 @@
 #include "backend/Device.h"
 #include "backend/Texture.h"
 #include "common/Assert.h"
+#include "common/Math.h"
 
 namespace backend {
 
@@ -130,6 +131,11 @@ namespace backend {
                 HandleError("Buffer needs to allow the correct usage bit");
                 return;
             }
+
+            if (!IsAligned(bufferViews[i]->GetOffset(), 256)) {
+                HandleError("Buffer view offset for bind group needs to be 256-byte aligned");
+                return;
+            }
         }
 
         SetBindingsBase(start, count, reinterpret_cast<RefCounted* const *>(bufferViews));
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index f81d1609dd..81522c6efe 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -40,6 +40,7 @@ list(APPEND UNITTEST_SOURCES
     ${UNITTESTS_DIR}/SerialQueueTests.cpp
     ${UNITTESTS_DIR}/ToBackendTests.cpp
     ${UNITTESTS_DIR}/WireTests.cpp
+    ${VALIDATION_TESTS_DIR}/BindGroupValidationTests.cpp
     ${VALIDATION_TESTS_DIR}/BlendStateValidationTests.cpp
     ${VALIDATION_TESTS_DIR}/BufferValidationTests.cpp
     ${VALIDATION_TESTS_DIR}/CommandBufferValidationTests.cpp
diff --git a/src/tests/unittests/validation/BindGroupValidationTests.cpp b/src/tests/unittests/validation/BindGroupValidationTests.cpp
new file mode 100644
index 0000000000..defa564fa0
--- /dev/null
+++ b/src/tests/unittests/validation/BindGroupValidationTests.cpp
@@ -0,0 +1,105 @@
+// Copyright 2017 The NXT Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/unittests/validation/ValidationTest.h"
+
+class BindGroupValidationTest : public ValidationTest {
+};
+
+TEST_F(BindGroupValidationTest, BufferViewOffset) {
+    auto layout = device.CreateBindGroupLayoutBuilder()
+        .SetBindingsType(nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer, 0, 1)
+        .GetResult();
+
+    auto buffer = device.CreateBufferBuilder()
+        .SetAllowedUsage(nxt::BufferUsageBit::Uniform)
+        .SetInitialUsage(nxt::BufferUsageBit::Uniform)
+        .SetSize(512)
+        .GetResult();
+    
+    // Check that offset 0 is valid
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(0, 512)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeSuccess(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+
+    // Check that offset 256 (aligned) is valid
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(256, 256)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeSuccess(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+
+    // Check cases where unaligned buffer view offset is invalid
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(1, 256)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeError(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(64, 256)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeError(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(128, 256)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeError(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+
+    {
+        auto bufferView = buffer.CreateBufferViewBuilder()
+            .SetExtent(255, 256)
+            .GetResult();
+
+        auto bindGroup = AssertWillBeError(device.CreateBindGroupBuilder())
+            .SetLayout(layout)
+            .SetUsage(nxt::BindGroupUsage::Frozen)
+            .SetBufferViews(0, 1, &bufferView)
+            .GetResult();
+    }
+}