Remove several compile-time constants in favor of limits

Bug: dawn:685
Change-Id: Ifac25116c741fdab7b6a8093b4230065beca4773
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65483
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/examples/Animometer.cpp b/examples/Animometer.cpp
index fb113f6..badca6b 100644
--- a/examples/Animometer.cpp
+++ b/examples/Animometer.cpp
@@ -37,7 +37,8 @@
 
 constexpr size_t kNumTriangles = 10000;
 
-struct alignas(kMinUniformBufferOffsetAlignment) ShaderData {
+// Aligned as minUniformBufferOffsetAlignment
+struct alignas(256) ShaderData {
     float scale;
     float time;
     float offsetX;
diff --git a/src/common/Constants.h b/src/common/Constants.h
index e34aaed..f5a521e 100644
--- a/src/common/Constants.h
+++ b/src/common/Constants.h
@@ -27,14 +27,6 @@
 static constexpr uint32_t kMaxInterStageShaderComponents = 60u;
 static constexpr uint32_t kMaxInterStageShaderVariables = kMaxInterStageShaderComponents / 4;
 
-// Compute constants
-static constexpr uint32_t kMaxComputeWorkgroupStorageSize = 16352u;
-static constexpr uint32_t kMaxComputeWorkgroupInvocations = 256u;
-static constexpr uint32_t kMaxComputePerDimensionDispatchSize = 65535u;
-static constexpr uint32_t kMaxComputeWorkgroupSizeX = 256;
-static constexpr uint32_t kMaxComputeWorkgroupSizeY = 256;
-static constexpr uint32_t kMaxComputeWorkgroupSizeZ = 64;
-
 // Per stage limits
 static constexpr uint32_t kMaxSampledTexturesPerShaderStage = 16;
 static constexpr uint32_t kMaxSamplersPerShaderStage = 16;
@@ -46,12 +38,6 @@
 static constexpr uint32_t kMaxDynamicUniformBuffersPerPipelineLayout = 8u;
 static constexpr uint32_t kMaxDynamicStorageBuffersPerPipelineLayout = 4u;
 
-// Buffer binding constraints
-static constexpr uint64_t kMaxUniformBufferBindingSize = 16384u;
-static constexpr uint64_t kMaxStorageBufferBindingSize = 134217728u;
-static constexpr uint64_t kMinUniformBufferOffsetAlignment = 256u;
-static constexpr uint64_t kMinStorageBufferOffsetAlignment = 256u;
-
 // Indirect command sizes
 static constexpr uint64_t kDispatchIndirectSize = 3 * sizeof(uint32_t);
 static constexpr uint64_t kDrawIndirectSize = 4 * sizeof(uint32_t);
@@ -61,15 +47,6 @@
 static constexpr float kLodMin = 0.0;
 static constexpr float kLodMax = 1000.0;
 
-// Max texture size constants
-static constexpr uint32_t kMaxTextureDimension1D = 8192u;
-static constexpr uint32_t kMaxTextureDimension2D = 8192u;
-static constexpr uint32_t kMaxTextureDimension3D = 2048u;
-static constexpr uint32_t kMaxTextureArrayLayers = 256u;
-static constexpr uint32_t kMaxTexture2DMipLevels = 14u;
-static_assert(1 << (kMaxTexture2DMipLevels - 1) == kMaxTextureDimension2D,
-              "kMaxTexture2DMipLevels and kMaxTextureDimension2D size mismatch");
-
 // Offset alignment for CopyB2B. Strictly speaking this alignment is required only
 // on macOS, but we decide to do it on all platforms.
 static constexpr uint64_t kCopyBufferToBufferOffsetAlignment = 4u;
diff --git a/src/dawn_native/BindGroup.cpp b/src/dawn_native/BindGroup.cpp
index 0a8beaf..9d248ea 100644
--- a/src/dawn_native/BindGroup.cpp
+++ b/src/dawn_native/BindGroup.cpp
@@ -50,19 +50,22 @@
             switch (bindingInfo.buffer.type) {
                 case wgpu::BufferBindingType::Uniform:
                     requiredUsage = wgpu::BufferUsage::Uniform;
-                    maxBindingSize = kMaxUniformBufferBindingSize;
-                    requiredBindingAlignment = kMinUniformBufferOffsetAlignment;
+                    maxBindingSize = device->GetLimits().v1.maxUniformBufferBindingSize;
+                    requiredBindingAlignment =
+                        device->GetLimits().v1.minUniformBufferOffsetAlignment;
                     break;
                 case wgpu::BufferBindingType::Storage:
                 case wgpu::BufferBindingType::ReadOnlyStorage:
                     requiredUsage = wgpu::BufferUsage::Storage;
-                    maxBindingSize = kMaxStorageBufferBindingSize;
-                    requiredBindingAlignment = kMinStorageBufferOffsetAlignment;
+                    maxBindingSize = device->GetLimits().v1.maxStorageBufferBindingSize;
+                    requiredBindingAlignment =
+                        device->GetLimits().v1.minStorageBufferOffsetAlignment;
                     break;
                 case kInternalStorageBufferBinding:
                     requiredUsage = kInternalStorageBuffer;
-                    maxBindingSize = kMaxStorageBufferBindingSize;
-                    requiredBindingAlignment = kMinStorageBufferOffsetAlignment;
+                    maxBindingSize = device->GetLimits().v1.maxStorageBufferBindingSize;
+                    requiredBindingAlignment =
+                        device->GetLimits().v1.minStorageBufferOffsetAlignment;
                     break;
                 case wgpu::BufferBindingType::Undefined:
                     UNREACHABLE();
diff --git a/src/dawn_native/ComputePassEncoder.cpp b/src/dawn_native/ComputePassEncoder.cpp
index 517429a..46277b1 100644
--- a/src/dawn_native/ComputePassEncoder.cpp
+++ b/src/dawn_native/ComputePassEncoder.cpp
@@ -28,8 +28,8 @@
 
     namespace {
 
-        MaybeError ValidatePerDimensionDispatchSizeLimit(uint32_t size) {
-            if (size > kMaxComputePerDimensionDispatchSize) {
+        MaybeError ValidatePerDimensionDispatchSizeLimit(const DeviceBase* device, uint32_t size) {
+            if (size > device->GetLimits().v1.maxComputeWorkgroupsPerDimension) {
                 return DAWN_VALIDATION_ERROR("Dispatch size exceeds defined limits");
             }
 
@@ -85,9 +85,9 @@
             [&](CommandAllocator* allocator) -> MaybeError {
                 if (IsValidationEnabled()) {
                     DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
-                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(x));
-                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(y));
-                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(z));
+                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(GetDevice(), x));
+                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(GetDevice(), y));
+                    DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(GetDevice(), z));
                 }
 
                 // Record the synchronization scope for Dispatch, which is just the current
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index fef1331..71e92e2 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -1560,6 +1560,10 @@
         }
     }
 
+    const CombinedLimits& DeviceBase::GetLimits() const {
+        return mLimits;
+    }
+
     AsyncTaskManager* DeviceBase::GetAsyncTaskManager() const {
         return mAsyncTaskManager.get();
     }
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 1fc37f0..7852c6a 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -336,6 +336,8 @@
 
         virtual float GetTimestampPeriodInNS() const = 0;
 
+        const CombinedLimits& GetLimits() const;
+
         AsyncTaskManager* GetAsyncTaskManager() const;
         CallbackTaskManager* GetCallbackTaskManager() const;
         dawn_platform::WorkerTaskPool* GetWorkerTaskPool() const;
diff --git a/src/dawn_native/IndirectDrawMetadata.cpp b/src/dawn_native/IndirectDrawMetadata.cpp
index 235935f..e150d78 100644
--- a/src/dawn_native/IndirectDrawMetadata.cpp
+++ b/src/dawn_native/IndirectDrawMetadata.cpp
@@ -17,6 +17,7 @@
 #include "common/Constants.h"
 #include "common/RefCounted.h"
 #include "dawn_native/IndirectDrawValidationEncoder.h"
+#include "dawn_native/Limits.h"
 #include "dawn_native/RenderBundle.h"
 
 #include <algorithm>
@@ -24,15 +25,10 @@
 
 namespace dawn_native {
 
-    namespace {
-
-        // In the unlikely scenario that indirect offsets used over a single buffer span more than
-        // this length of the buffer, we split the validation work into multiple batches.
-        constexpr uint64_t kMaxBatchOffsetRange = kMaxStorageBufferBindingSize -
-                                                  kMinStorageBufferOffsetAlignment -
-                                                  kDrawIndexedIndirectSize;
-
-    }  // namespace
+    uint32_t ComputeMaxIndirectValidationBatchOffsetRange(const CombinedLimits& limits) {
+        return limits.v1.maxStorageBufferBindingSize - limits.v1.minStorageBufferOffsetAlignment -
+               kDrawIndexedIndirectSize;
+    }
 
     IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::IndexedIndirectBufferValidationInfo(
         BufferBase* indirectBuffer)
@@ -40,12 +36,14 @@
     }
 
     void IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::AddIndexedIndirectDraw(
+        uint32_t maxDrawCallsPerIndirectValidationBatch,
+        uint32_t maxBatchOffsetRange,
         IndexedIndirectDraw draw) {
         const uint64_t newOffset = draw.clientBufferOffset;
         auto it = mBatches.begin();
         while (it != mBatches.end()) {
             IndexedIndirectValidationBatch& batch = *it;
-            if (batch.draws.size() >= kMaxDrawCallsPerIndirectValidationBatch) {
+            if (batch.draws.size() >= maxDrawCallsPerIndirectValidationBatch) {
                 // This batch is full. If its minOffset is to the right of the new offset, we can
                 // just insert a new batch here.
                 if (newOffset < batch.minOffset) {
@@ -62,16 +60,14 @@
                 return;
             }
 
-            if (newOffset < batch.minOffset &&
-                batch.maxOffset - newOffset <= kMaxBatchOffsetRange) {
+            if (newOffset < batch.minOffset && batch.maxOffset - newOffset <= maxBatchOffsetRange) {
                 // We can extend this batch to the left in order to fit the new offset.
                 batch.minOffset = newOffset;
                 batch.draws.push_back(std::move(draw));
                 return;
             }
 
-            if (newOffset > batch.maxOffset &&
-                newOffset - batch.minOffset <= kMaxBatchOffsetRange) {
+            if (newOffset > batch.maxOffset && newOffset - batch.minOffset <= maxBatchOffsetRange) {
                 // We can extend this batch to the right in order to fit the new offset.
                 batch.maxOffset = newOffset;
                 batch.draws.push_back(std::move(draw));
@@ -95,14 +91,16 @@
     }
 
     void IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::AddBatch(
+        uint32_t maxDrawCallsPerIndirectValidationBatch,
+        uint32_t maxBatchOffsetRange,
         const IndexedIndirectValidationBatch& newBatch) {
         auto it = mBatches.begin();
         while (it != mBatches.end()) {
             IndexedIndirectValidationBatch& batch = *it;
             uint64_t min = std::min(newBatch.minOffset, batch.minOffset);
             uint64_t max = std::max(newBatch.maxOffset, batch.maxOffset);
-            if (max - min <= kMaxBatchOffsetRange && batch.draws.size() + newBatch.draws.size() <=
-                                                         kMaxDrawCallsPerIndirectValidationBatch) {
+            if (max - min <= maxBatchOffsetRange && batch.draws.size() + newBatch.draws.size() <=
+                                                        maxDrawCallsPerIndirectValidationBatch) {
                 // This batch fits within the limits of an existing batch. Merge it.
                 batch.minOffset = min;
                 batch.maxOffset = max;
@@ -124,7 +122,10 @@
         return mBatches;
     }
 
-    IndirectDrawMetadata::IndirectDrawMetadata() = default;
+    IndirectDrawMetadata::IndirectDrawMetadata(const CombinedLimits& limits)
+        : mMaxDrawCallsPerBatch(ComputeMaxDrawCallsPerIndirectValidationBatch(limits)),
+          mMaxBatchOffsetRange(ComputeMaxIndirectValidationBatchOffsetRange(limits)) {
+    }
 
     IndirectDrawMetadata::~IndirectDrawMetadata() = default;
 
@@ -150,7 +151,7 @@
             if (it != mIndexedIndirectBufferValidationInfo.end() && it->first == config) {
                 // We already have batches for the same config. Merge the new ones in.
                 for (const IndexedIndirectValidationBatch& batch : entry.second.GetBatches()) {
-                    it->second.AddBatch(batch);
+                    it->second.AddBatch(mMaxDrawCallsPerBatch, mMaxBatchOffsetRange, batch);
                 }
             } else {
                 mIndexedIndirectBufferValidationInfo.emplace_hint(it, config, entry.second);
@@ -187,7 +188,8 @@
         IndexedIndirectDraw draw;
         draw.clientBufferOffset = indirectOffset;
         draw.bufferLocation = drawCmdIndirectBufferLocation;
-        it->second.AddIndexedIndirectDraw(std::move(draw));
+        it->second.AddIndexedIndirectDraw(mMaxDrawCallsPerBatch, mMaxBatchOffsetRange,
+                                          std::move(draw));
     }
 
 }  // namespace dawn_native
diff --git a/src/dawn_native/IndirectDrawMetadata.h b/src/dawn_native/IndirectDrawMetadata.h
index 04c38e3..f55f3d3 100644
--- a/src/dawn_native/IndirectDrawMetadata.h
+++ b/src/dawn_native/IndirectDrawMetadata.h
@@ -31,6 +31,11 @@
 namespace dawn_native {
 
     class RenderBundleBase;
+    struct CombinedLimits;
+
+    // In the unlikely scenario that indirect offsets used over a single buffer span more than
+    // this length of the buffer, we split the validation work into multiple batches.
+    uint32_t ComputeMaxIndirectValidationBatchOffsetRange(const CombinedLimits& limits);
 
     // Metadata corresponding to the validation requirements of a single render pass. This metadata
     // is accumulated while its corresponding render pass is encoded, and is later used to encode
@@ -58,12 +63,16 @@
 
             // Logs a new drawIndexedIndirect call for the render pass. `cmd` is updated with an
             // assigned (and deferred) buffer ref and relative offset before returning.
-            void AddIndexedIndirectDraw(IndexedIndirectDraw draw);
+            void AddIndexedIndirectDraw(uint32_t maxDrawCallsPerIndirectValidationBatch,
+                                        uint32_t maxBatchOffsetRange,
+                                        IndexedIndirectDraw draw);
 
             // Adds draw calls from an already-computed batch, e.g. from a previously encoded
             // RenderBundle. The added batch is merged into an existing batch if possible, otherwise
             // it's added to mBatch.
-            void AddBatch(const IndexedIndirectValidationBatch& batch);
+            void AddBatch(uint32_t maxDrawCallsPerIndirectValidationBatch,
+                          uint32_t maxBatchOffsetRange,
+                          const IndexedIndirectValidationBatch& batch);
 
             const std::vector<IndexedIndirectValidationBatch>& GetBatches() const;
 
@@ -87,7 +96,7 @@
         using IndexedIndirectBufferValidationInfoMap =
             std::map<IndexedIndirectConfig, IndexedIndirectBufferValidationInfo>;
 
-        IndirectDrawMetadata();
+        explicit IndirectDrawMetadata(const CombinedLimits& limits);
         ~IndirectDrawMetadata();
 
         IndirectDrawMetadata(IndirectDrawMetadata&&);
@@ -105,6 +114,9 @@
       private:
         IndexedIndirectBufferValidationInfoMap mIndexedIndirectBufferValidationInfo;
         std::set<RenderBundleBase*> mAddedBundles;
+
+        uint32_t mMaxDrawCallsPerBatch;
+        uint32_t mMaxBatchOffsetRange;
     };
 
 }  // namespace dawn_native
diff --git a/src/dawn_native/IndirectDrawValidationEncoder.cpp b/src/dawn_native/IndirectDrawValidationEncoder.cpp
index c3c2a04..1eba1ba 100644
--- a/src/dawn_native/IndirectDrawValidationEncoder.cpp
+++ b/src/dawn_native/IndirectDrawValidationEncoder.cpp
@@ -188,12 +188,15 @@
 
     }  // namespace
 
-    const uint32_t kBatchDrawCallLimitByDispatchSize =
-        kMaxComputePerDimensionDispatchSize * kWorkgroupSize;
-    const uint32_t kBatchDrawCallLimitByStorageBindingSize =
-        (kMaxStorageBufferBindingSize - sizeof(BatchInfo)) / sizeof(uint32_t);
-    const uint32_t kMaxDrawCallsPerIndirectValidationBatch =
-        std::min(kBatchDrawCallLimitByDispatchSize, kBatchDrawCallLimitByStorageBindingSize);
+    uint32_t ComputeMaxDrawCallsPerIndirectValidationBatch(const CombinedLimits& limits) {
+        const uint64_t batchDrawCallLimitByDispatchSize =
+            static_cast<uint64_t>(limits.v1.maxComputeWorkgroupsPerDimension) * kWorkgroupSize;
+        const uint64_t batchDrawCallLimitByStorageBindingSize =
+            (limits.v1.maxStorageBufferBindingSize - sizeof(BatchInfo)) / sizeof(uint32_t);
+        return static_cast<uint32_t>(
+            std::min({batchDrawCallLimitByDispatchSize, batchDrawCallLimitByStorageBindingSize,
+                      uint64_t(std::numeric_limits<uint32_t>::max())}));
+    }
 
     MaybeError EncodeIndirectDrawValidationCommands(DeviceBase* device,
                                                     CommandEncoder* commandEncoder,
@@ -232,13 +235,18 @@
             return {};
         }
 
+        const uint32_t maxStorageBufferBindingSize =
+            device->GetLimits().v1.maxStorageBufferBindingSize;
+        const uint32_t minStorageBufferOffsetAlignment =
+            device->GetLimits().v1.minStorageBufferOffsetAlignment;
+
         for (auto& entry : bufferInfoMap) {
             const IndirectDrawMetadata::IndexedIndirectConfig& config = entry.first;
             BufferBase* clientIndirectBuffer = config.first;
             for (const IndirectDrawMetadata::IndexedIndirectValidationBatch& batch :
                  entry.second.GetBatches()) {
                 const uint64_t minOffsetFromAlignedBoundary =
-                    batch.minOffset % kMinStorageBufferOffsetAlignment;
+                    batch.minOffset % minStorageBufferOffsetAlignment;
                 const uint64_t minOffsetAlignedDown =
                     batch.minOffset - minOffsetFromAlignedBoundary;
 
@@ -253,18 +261,18 @@
 
                 newBatch.validatedParamsSize = batch.draws.size() * kDrawIndexedIndirectSize;
                 newBatch.validatedParamsOffset =
-                    Align(validatedParamsSize, kMinStorageBufferOffsetAlignment);
+                    Align(validatedParamsSize, minStorageBufferOffsetAlignment);
                 validatedParamsSize = newBatch.validatedParamsOffset + newBatch.validatedParamsSize;
-                if (validatedParamsSize > kMaxStorageBufferBindingSize) {
+                if (validatedParamsSize > maxStorageBufferBindingSize) {
                     return DAWN_INTERNAL_ERROR("Too many drawIndexedIndirect calls to validate");
                 }
 
                 Pass* currentPass = passes.empty() ? nullptr : &passes.back();
                 if (currentPass && currentPass->clientIndirectBuffer == clientIndirectBuffer) {
                     uint64_t nextBatchDataOffset =
-                        Align(currentPass->batchDataSize, kMinStorageBufferOffsetAlignment);
+                        Align(currentPass->batchDataSize, minStorageBufferOffsetAlignment);
                     uint64_t newPassBatchDataSize = nextBatchDataOffset + newBatch.dataSize;
-                    if (newPassBatchDataSize <= kMaxStorageBufferBindingSize) {
+                    if (newPassBatchDataSize <= maxStorageBufferBindingSize) {
                         // We can fit this batch in the current pass.
                         newBatch.dataBufferOffset = nextBatchDataOffset;
                         currentPass->batchDataSize = newPassBatchDataSize;
diff --git a/src/dawn_native/IndirectDrawValidationEncoder.h b/src/dawn_native/IndirectDrawValidationEncoder.h
index bc62bf0..aa56b099 100644
--- a/src/dawn_native/IndirectDrawValidationEncoder.h
+++ b/src/dawn_native/IndirectDrawValidationEncoder.h
@@ -21,13 +21,14 @@
 namespace dawn_native {
 
     class CommandEncoder;
+    struct CombinedLimits;
     class DeviceBase;
     class RenderPassResourceUsageTracker;
 
     // The maximum number of draws call we can fit into a single validation batch. This is
     // essentially limited by the number of indirect parameter blocks that can fit into the maximum
-    // allowed storage binding size (about 6.7M).
-    extern const uint32_t kMaxDrawCallsPerIndirectValidationBatch;
+    // allowed storage binding size (with the base limits, it is about 6.7M).
+    uint32_t ComputeMaxDrawCallsPerIndirectValidationBatch(const CombinedLimits& limits);
 
     MaybeError EncodeIndirectDrawValidationCommands(DeviceBase* device,
                                                     CommandEncoder* commandEncoder,
diff --git a/src/dawn_native/ProgrammablePassEncoder.cpp b/src/dawn_native/ProgrammablePassEncoder.cpp
index 5f7ed77..c6e2e28 100644
--- a/src/dawn_native/ProgrammablePassEncoder.cpp
+++ b/src/dawn_native/ProgrammablePassEncoder.cpp
@@ -139,13 +139,12 @@
             uint64_t requiredAlignment;
             switch (bindingInfo.buffer.type) {
                 case wgpu::BufferBindingType::Uniform:
-                    requiredAlignment = kMinUniformBufferOffsetAlignment;
+                    requiredAlignment = GetDevice()->GetLimits().v1.minUniformBufferOffsetAlignment;
                     break;
                 case wgpu::BufferBindingType::Storage:
                 case wgpu::BufferBindingType::ReadOnlyStorage:
                 case kInternalStorageBufferBinding:
-                    requiredAlignment = kMinStorageBufferOffsetAlignment;
-                    requiredAlignment = kMinStorageBufferOffsetAlignment;
+                    requiredAlignment = GetDevice()->GetLimits().v1.minStorageBufferOffsetAlignment;
                     break;
                 case wgpu::BufferBindingType::Undefined:
                     UNREACHABLE();
diff --git a/src/dawn_native/RenderBundle.cpp b/src/dawn_native/RenderBundle.cpp
index cb81dab..8a7fe73 100644
--- a/src/dawn_native/RenderBundle.cpp
+++ b/src/dawn_native/RenderBundle.cpp
@@ -44,7 +44,7 @@
     }
 
     RenderBundleBase::RenderBundleBase(DeviceBase* device, ErrorTag errorTag)
-        : ApiObjectBase(device, errorTag) {
+        : ApiObjectBase(device, errorTag), mIndirectDrawMetadata(device->GetLimits()) {
     }
 
     ObjectType RenderBundleBase::GetType() const {
diff --git a/src/dawn_native/RenderEncoderBase.cpp b/src/dawn_native/RenderEncoderBase.cpp
index 240fc29..a2e99a8 100644
--- a/src/dawn_native/RenderEncoderBase.cpp
+++ b/src/dawn_native/RenderEncoderBase.cpp
@@ -34,6 +34,7 @@
                                          EncodingContext* encodingContext,
                                          Ref<AttachmentState> attachmentState)
         : ProgrammablePassEncoder(device, encodingContext),
+          mIndirectDrawMetadata(device->GetLimits()),
           mAttachmentState(std::move(attachmentState)),
           mDisableBaseVertex(device->IsToggleEnabled(Toggle::DisableBaseVertex)),
           mDisableBaseInstance(device->IsToggleEnabled(Toggle::DisableBaseInstance)) {
@@ -43,6 +44,7 @@
                                          EncodingContext* encodingContext,
                                          ErrorTag errorTag)
         : ProgrammablePassEncoder(device, encodingContext, errorTag),
+          mIndirectDrawMetadata(device->GetLimits()),
           mDisableBaseVertex(device->IsToggleEnabled(Toggle::DisableBaseVertex)),
           mDisableBaseInstance(device->IsToggleEnabled(Toggle::DisableBaseInstance)) {
     }
diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp
index 4132d3c..bd3989b 100644
--- a/src/dawn_native/ShaderModule.cpp
+++ b/src/dawn_native/ShaderModule.cpp
@@ -609,10 +609,12 @@
         }
 
         ResultOrError<EntryPointMetadataTable> ReflectShaderUsingTint(
-            DeviceBase*,
+            const DeviceBase* device,
             const tint::Program* program) {
             ASSERT(program->IsValid());
 
+            const CombinedLimits& limits = device->GetLimits();
+
             EntryPointMetadataTable result;
 
             tint::inspector::Inspector inspector(program);
@@ -645,36 +647,32 @@
                 DAWN_TRY_ASSIGN(metadata->stage, TintPipelineStageToShaderStage(entryPoint.stage));
 
                 if (metadata->stage == SingleShaderStage::Compute) {
-                    DAWN_INVALID_IF(entryPoint.workgroup_size_x > kMaxComputeWorkgroupSizeX ||
-                                        entryPoint.workgroup_size_y > kMaxComputeWorkgroupSizeY ||
-                                        entryPoint.workgroup_size_z > kMaxComputeWorkgroupSizeZ,
-                                    "Entry-point uses workgroup_size(%u, %u, %u) that exceeds the "
-                                    "maximum allowed (%u, %u, %u).",
-                                    entryPoint.workgroup_size_x, entryPoint.workgroup_size_y,
-                                    entryPoint.workgroup_size_z, kMaxComputeWorkgroupSizeX,
-                                    kMaxComputeWorkgroupSizeY, kMaxComputeWorkgroupSizeZ);
+                    DAWN_INVALID_IF(
+                        entryPoint.workgroup_size_x > limits.v1.maxComputeWorkgroupSizeX ||
+                            entryPoint.workgroup_size_y > limits.v1.maxComputeWorkgroupSizeY ||
+                            entryPoint.workgroup_size_z > limits.v1.maxComputeWorkgroupSizeZ,
+                        "Entry-point uses workgroup_size(%u, %u, %u) that exceeds the "
+                        "maximum allowed (%u, %u, %u).",
+                        entryPoint.workgroup_size_x, entryPoint.workgroup_size_y,
+                        entryPoint.workgroup_size_z, limits.v1.maxComputeWorkgroupSizeX,
+                        limits.v1.maxComputeWorkgroupSizeY, limits.v1.maxComputeWorkgroupSizeZ);
 
                     // Dimensions have already been validated against their individual limits above.
-                    // This assertion ensures that the product of such limited dimensions cannot
-                    // possibly overflow a uint32_t.
-                    static_assert(static_cast<uint64_t>(kMaxComputeWorkgroupSizeX) *
-                                          kMaxComputeWorkgroupSizeY * kMaxComputeWorkgroupSizeZ <=
-                                      std::numeric_limits<uint32_t>::max(),
-                                  "Per-dimension workgroup size limits are too high");
-                    uint32_t numInvocations = entryPoint.workgroup_size_x *
+                    // Cast to uint64_t to avoid overflow in this multiplication.
+                    uint64_t numInvocations = static_cast<uint64_t>(entryPoint.workgroup_size_x) *
                                               entryPoint.workgroup_size_y *
                                               entryPoint.workgroup_size_z;
-                    DAWN_INVALID_IF(numInvocations > kMaxComputeWorkgroupInvocations,
+                    DAWN_INVALID_IF(numInvocations > limits.v1.maxComputeInvocationsPerWorkgroup,
                                     "The total number of workgroup invocations (%u) exceeds the "
                                     "maximum allowed (%u).",
-                                    numInvocations, kMaxComputeWorkgroupInvocations);
+                                    numInvocations, limits.v1.maxComputeInvocationsPerWorkgroup);
 
                     const size_t workgroupStorageSize =
                         inspector.GetWorkgroupStorageSize(entryPoint.name);
-                    DAWN_INVALID_IF(workgroupStorageSize > kMaxComputeWorkgroupStorageSize,
+                    DAWN_INVALID_IF(workgroupStorageSize > limits.v1.maxComputeWorkgroupStorageSize,
                                     "The total use of workgroup storage (%u bytes) is larger than "
                                     "the maximum allowed (%u bytes).",
-                                    workgroupStorageSize, kMaxComputeWorkgroupStorageSize);
+                                    workgroupStorageSize, limits.v1.maxComputeWorkgroupStorageSize);
 
                     metadata->localWorkgroupSize.x = entryPoint.workgroup_size_x;
                     metadata->localWorkgroupSize.y = entryPoint.workgroup_size_y;
diff --git a/src/dawn_native/SwapChain.cpp b/src/dawn_native/SwapChain.cpp
index 2634cd8..5c9ee0f 100644
--- a/src/dawn_native/SwapChain.cpp
+++ b/src/dawn_native/SwapChain.cpp
@@ -90,8 +90,8 @@
                 return DAWN_VALIDATION_ERROR("Swapchain size can't be empty");
             }
 
-            if (descriptor->width > kMaxTextureDimension2D ||
-                descriptor->height > kMaxTextureDimension2D) {
+            if (descriptor->width > device->GetLimits().v1.maxTextureDimension2D ||
+                descriptor->height > device->GetLimits().v1.maxTextureDimension2D) {
                 return DAWN_VALIDATION_ERROR("Swapchain size too big");
             }
         }
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 508beaa..e770ece 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -173,19 +173,21 @@
             return {};
         }
 
-        MaybeError ValidateTextureSize(const TextureDescriptor* descriptor, const Format* format) {
+        MaybeError ValidateTextureSize(const DeviceBase* device,
+                                       const TextureDescriptor* descriptor,
+                                       const Format* format) {
             ASSERT(descriptor->size.width != 0 && descriptor->size.height != 0 &&
                    descriptor->size.depthOrArrayLayers != 0);
-
+            const CombinedLimits& limits = device->GetLimits();
             Extent3D maxExtent;
             switch (descriptor->dimension) {
                 case wgpu::TextureDimension::e2D:
-                    maxExtent = {kMaxTextureDimension2D, kMaxTextureDimension2D,
-                                 kMaxTextureArrayLayers};
+                    maxExtent = {limits.v1.maxTextureDimension2D, limits.v1.maxTextureDimension2D,
+                                 limits.v1.maxTextureArrayLayers};
                     break;
                 case wgpu::TextureDimension::e3D:
-                    maxExtent = {kMaxTextureDimension3D, kMaxTextureDimension3D,
-                                 kMaxTextureDimension3D};
+                    maxExtent = {limits.v1.maxTextureDimension3D, limits.v1.maxTextureDimension3D,
+                                 limits.v1.maxTextureDimension3D};
                     break;
                 case wgpu::TextureDimension::e1D:
                 default:
@@ -210,8 +212,6 @@
                 "Texture mip level count (%u) exceeds the maximum (%u) for its size (%s).",
                 descriptor->mipLevelCount, Log2(maxMippedDimension) + 1, &descriptor->size);
 
-            ASSERT(descriptor->mipLevelCount <= kMaxTexture2DMipLevels);
-
             if (format->isCompressed) {
                 const TexelBlockInfo& blockInfo =
                     format->GetAspectInfo(wgpu::TextureAspect::All).block;
@@ -308,7 +308,7 @@
             "The dimension (%s) of a texture with a depth/stencil format (%s) is not 2D.",
             descriptor->dimension, format->format);
 
-        DAWN_TRY(ValidateTextureSize(descriptor, format));
+        DAWN_TRY(ValidateTextureSize(device, descriptor, format));
 
         // TODO(crbug.com/dawn/838): Implement a workaround for this issue.
         // Readbacks from the non-zero mip of a stencil texture may contain garbage data.
@@ -555,12 +555,7 @@
     uint32_t TextureBase::GetSubresourceIndex(uint32_t mipLevel,
                                               uint32_t arraySlice,
                                               Aspect aspect) const {
-        ASSERT(arraySlice <= kMaxTextureArrayLayers);
-        ASSERT(mipLevel <= kMaxTexture2DMipLevels);
         ASSERT(HasOneBit(aspect));
-        static_assert(
-            kMaxTexture2DMipLevels <= std::numeric_limits<uint32_t>::max() / kMaxTextureArrayLayers,
-            "texture size overflows uint32_t");
         return mipLevel +
                GetNumMipLevels() * (arraySlice + GetArrayLayers() * GetAspectIndex(aspect));
     }
diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp
index 55a2473..df488b3 100644
--- a/src/dawn_native/vulkan/AdapterVk.cpp
+++ b/src/dawn_native/vulkan/AdapterVk.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn_native/vulkan/AdapterVk.h"
 
+#include "dawn_native/Limits.h"
 #include "dawn_native/vulkan/BackendVk.h"
 #include "dawn_native/vulkan/DeviceVk.h"
 
@@ -78,6 +79,9 @@
     }
 
     MaybeError Adapter::CheckCoreWebGPUSupport() {
+        Limits baseLimits;
+        GetDefaultLimits(&baseLimits);
+
         // Needed for viewport Y-flip.
         if (!mDeviceInfo.HasExt(DeviceExt::Maintenance1)) {
             return DAWN_INTERNAL_ERROR("Vulkan 1.1 or Vulkan 1.0 with KHR_Maintenance1 required.");
@@ -118,106 +122,110 @@
 
         // Check base WebGPU limits are supported.
         const VkPhysicalDeviceLimits& limits = mDeviceInfo.properties.limits;
-        if (limits.maxImageDimension1D < kMaxTextureDimension1D) {
+        if (limits.maxImageDimension1D < baseLimits.maxTextureDimension1D) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension1D");
         }
-        if (limits.maxImageDimension2D < kMaxTextureDimension2D ||
-            limits.maxImageDimensionCube < kMaxTextureDimension2D ||
-            limits.maxFramebufferWidth < kMaxTextureDimension2D ||
-            limits.maxFramebufferHeight < kMaxTextureDimension2D ||
-            limits.maxViewportDimensions[0] < kMaxTextureDimension2D ||
-            limits.maxViewportDimensions[1] < kMaxTextureDimension2D ||
-            limits.viewportBoundsRange[1] < kMaxTextureDimension2D) {
+        if (limits.maxImageDimension2D < baseLimits.maxTextureDimension2D ||
+            limits.maxImageDimensionCube < baseLimits.maxTextureDimension2D ||
+            limits.maxFramebufferWidth < baseLimits.maxTextureDimension2D ||
+            limits.maxFramebufferHeight < baseLimits.maxTextureDimension2D ||
+            limits.maxViewportDimensions[0] < baseLimits.maxTextureDimension2D ||
+            limits.maxViewportDimensions[1] < baseLimits.maxTextureDimension2D ||
+            limits.viewportBoundsRange[1] < baseLimits.maxTextureDimension2D) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension2D");
         }
-        if (limits.maxImageDimension3D < kMaxTextureDimension3D) {
+        if (limits.maxImageDimension3D < baseLimits.maxTextureDimension3D) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension3D");
         }
-        if (limits.maxImageArrayLayers < kMaxTextureArrayLayers) {
+        if (limits.maxImageArrayLayers < baseLimits.maxTextureArrayLayers) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureArrayLayers");
         }
-        if (limits.maxBoundDescriptorSets < kMaxBindGroups) {
+        if (limits.maxBoundDescriptorSets < baseLimits.maxBindGroups) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxBindGroups");
         }
         if (limits.maxDescriptorSetUniformBuffersDynamic <
-            kMaxDynamicUniformBuffersPerPipelineLayout) {
+            baseLimits.maxDynamicUniformBuffersPerPipelineLayout) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxDynamicUniformBuffersPerPipelineLayout");
         }
         if (limits.maxDescriptorSetStorageBuffersDynamic <
-            kMaxDynamicStorageBuffersPerPipelineLayout) {
+            baseLimits.maxDynamicStorageBuffersPerPipelineLayout) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxDynamicStorageBuffersPerPipelineLayout");
         }
-        if (limits.maxPerStageDescriptorSampledImages < kMaxSampledTexturesPerShaderStage) {
+        if (limits.maxPerStageDescriptorSampledImages <
+            baseLimits.maxSampledTexturesPerShaderStage) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxSampledTexturesPerShaderStage");
         }
-        if (limits.maxPerStageDescriptorSamplers < kMaxSamplersPerShaderStage) {
+        if (limits.maxPerStageDescriptorSamplers < baseLimits.maxSamplersPerShaderStage) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxSamplersPerShaderStage");
         }
-        if (limits.maxPerStageDescriptorStorageBuffers < kMaxStorageBuffersPerShaderStage) {
+        if (limits.maxPerStageDescriptorStorageBuffers <
+            baseLimits.maxStorageBuffersPerShaderStage) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxStorageBuffersPerShaderStage");
         }
-        if (limits.maxPerStageDescriptorStorageImages < kMaxStorageTexturesPerShaderStage) {
+        if (limits.maxPerStageDescriptorStorageImages <
+            baseLimits.maxStorageTexturesPerShaderStage) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxStorageTexturesPerShaderStage");
         }
-        if (limits.maxPerStageDescriptorUniformBuffers < kMaxUniformBuffersPerShaderStage) {
+        if (limits.maxPerStageDescriptorUniformBuffers <
+            baseLimits.maxUniformBuffersPerShaderStage) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxUniformBuffersPerShaderStage");
         }
-        if (limits.maxUniformBufferRange < kMaxUniformBufferBindingSize) {
+        if (limits.maxUniformBufferRange < baseLimits.maxUniformBufferBindingSize) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxUniformBufferBindingSize");
         }
-        if (limits.maxStorageBufferRange < kMaxStorageBufferBindingSize) {
+        if (limits.maxStorageBufferRange < baseLimits.maxStorageBufferBindingSize) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxStorageBufferBindingSize");
         }
-        if (limits.minUniformBufferOffsetAlignment > kMinUniformBufferOffsetAlignment) {
+        if (limits.minUniformBufferOffsetAlignment > baseLimits.minUniformBufferOffsetAlignment) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for minUniformBufferOffsetAlignment");
         }
-        if (limits.minStorageBufferOffsetAlignment > kMinStorageBufferOffsetAlignment) {
+        if (limits.minStorageBufferOffsetAlignment > baseLimits.minStorageBufferOffsetAlignment) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for minStorageBufferOffsetAlignment");
         }
-        if (limits.maxVertexInputBindings < kMaxVertexBuffers) {
+        if (limits.maxVertexInputBindings < baseLimits.maxVertexBuffers) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBuffers");
         }
-        if (limits.maxVertexInputAttributes < kMaxVertexAttributes) {
+        if (limits.maxVertexInputAttributes < baseLimits.maxVertexAttributes) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexAttributes");
         }
-        if (limits.maxVertexInputBindingStride < kMaxVertexBufferArrayStride ||
-            limits.maxVertexInputAttributeOffset < kMaxVertexBufferArrayStride - 1) {
+        if (limits.maxVertexInputBindingStride < baseLimits.maxVertexBufferArrayStride ||
+            limits.maxVertexInputAttributeOffset < baseLimits.maxVertexBufferArrayStride - 1) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBufferArrayStride");
         }
-        if (limits.maxVertexOutputComponents < kMaxInterStageShaderComponents ||
-            limits.maxFragmentInputComponents < kMaxInterStageShaderComponents) {
+        if (limits.maxVertexOutputComponents < baseLimits.maxInterStageShaderComponents ||
+            limits.maxFragmentInputComponents < baseLimits.maxInterStageShaderComponents) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxInterStageShaderComponents");
         }
-        if (limits.maxComputeSharedMemorySize < kMaxComputeWorkgroupStorageSize) {
+        if (limits.maxComputeSharedMemorySize < baseLimits.maxComputeWorkgroupStorageSize) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxComputeWorkgroupStorageSize");
         }
-        if (limits.maxComputeWorkGroupInvocations < kMaxComputeWorkgroupInvocations) {
+        if (limits.maxComputeWorkGroupInvocations < baseLimits.maxComputeInvocationsPerWorkgroup) {
             return DAWN_INTERNAL_ERROR(
-                "Insufficient Vulkan limits for maxComputeWorkgroupInvocations");
+                "Insufficient Vulkan limits for maxComputeInvocationsPerWorkgroup");
         }
-        if (limits.maxComputeWorkGroupSize[0] < kMaxComputeWorkgroupSizeX ||
-            limits.maxComputeWorkGroupSize[1] < kMaxComputeWorkgroupSizeY ||
-            limits.maxComputeWorkGroupSize[2] < kMaxComputeWorkgroupSizeZ) {
+        if (limits.maxComputeWorkGroupSize[0] < baseLimits.maxComputeWorkgroupSizeX ||
+            limits.maxComputeWorkGroupSize[1] < baseLimits.maxComputeWorkgroupSizeY ||
+            limits.maxComputeWorkGroupSize[2] < baseLimits.maxComputeWorkgroupSizeZ) {
             return DAWN_INTERNAL_ERROR(
                 "Insufficient Vulkan limits for maxComputeWorkgroupSize");
         }
-        if (limits.maxComputeWorkGroupCount[0] < kMaxComputePerDimensionDispatchSize ||
-            limits.maxComputeWorkGroupCount[1] < kMaxComputePerDimensionDispatchSize ||
-            limits.maxComputeWorkGroupCount[2] < kMaxComputePerDimensionDispatchSize) {
+        if (limits.maxComputeWorkGroupCount[0] < baseLimits.maxComputeWorkgroupsPerDimension ||
+            limits.maxComputeWorkGroupCount[1] < baseLimits.maxComputeWorkgroupsPerDimension ||
+            limits.maxComputeWorkGroupCount[2] < baseLimits.maxComputeWorkgroupsPerDimension) {
             return DAWN_INTERNAL_ERROR(
-                "Insufficient Vulkan limits for maxComputePerDimensionDispatchSize");
+                "Insufficient Vulkan limits for maxComputeWorkgroupsPerDimension");
         }
         if (limits.maxColorAttachments < kMaxColorAttachments) {
             return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxColorAttachments");
@@ -239,9 +247,9 @@
         uint32_t vendorId = mDeviceInfo.properties.vendorID;
         if (!gpu_info::IsAMD(vendorId) && !gpu_info::IsIntel(vendorId) &&
             !gpu_info::IsNvidia(vendorId)) {
-            if (limits.maxFragmentCombinedOutputResources < kMaxColorAttachments +
-                                                                kMaxStorageTexturesPerShaderStage +
-                                                                kMaxStorageBuffersPerShaderStage) {
+            if (limits.maxFragmentCombinedOutputResources <
+                kMaxColorAttachments + baseLimits.maxStorageTexturesPerShaderStage +
+                    baseLimits.maxStorageBuffersPerShaderStage) {
                 return DAWN_INTERNAL_ERROR(
                     "Insufficient Vulkan maxFragmentCombinedOutputResources limit");
             }
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 56e8279..9548857 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -862,6 +862,13 @@
     return mParam.adapterProperties;
 }
 
+wgpu::SupportedLimits DawnTestBase::GetSupportedLimits() {
+    WGPUSupportedLimits supportedLimits;
+    supportedLimits.nextInChain = nullptr;
+    dawn_native::GetProcs().deviceGetLimits(backendDevice, &supportedLimits);
+    return *reinterpret_cast<wgpu::SupportedLimits*>(&supportedLimits);
+}
+
 bool DawnTestBase::SupportsFeatures(const std::vector<const char*>& features) {
     ASSERT(mBackendAdapter);
     std::set<std::string> supportedFeaturesSet;
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index a8be5ce..2d96e1f 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -485,6 +485,11 @@
 
     const wgpu::AdapterProperties& GetAdapterProperties() const;
 
+    // TODO(crbug.com/dawn/689): Use limits returned from the wire
+    // This is implemented here because tests need to always query
+    // the |backendDevice| since limits are not implemented in the wire.
+    wgpu::SupportedLimits GetSupportedLimits();
+
   private:
     utils::ScopedAutoreleasePool mObjCAutoreleasePool;
     AdapterTestParam mParam;
diff --git a/src/tests/end2end/BindGroupTests.cpp b/src/tests/end2end/BindGroupTests.cpp
index 50982857..cac7a8c 100644
--- a/src/tests/end2end/BindGroupTests.cpp
+++ b/src/tests/end2end/BindGroupTests.cpp
@@ -23,6 +23,11 @@
 
 class BindGroupTests : public DawnTest {
   protected:
+    void SetUp() override {
+        DawnTest::SetUp();
+        mMinUniformBufferOffsetAlignment =
+            GetSupportedLimits().limits.minUniformBufferOffsetAlignment;
+    }
     wgpu::CommandBuffer CreateSimpleComputeCommandBuffer(const wgpu::ComputePipeline& pipeline,
                                                          const wgpu::BindGroup& bindGroup) {
         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@@ -116,6 +121,8 @@
 
         return device.CreateRenderPipeline(&pipelineDescriptor);
     }
+
+    uint32_t mMinUniformBufferOffsetAlignment;
 };
 
 // Test a bindgroup reused in two command buffers in the same call to queue.Submit().
@@ -649,7 +656,7 @@
     std::array<float, 4> color0 = {1, 0, 0, 0.501};
     std::array<float, 4> color1 = {0, 1, 0, 0.501};
 
-    size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment);
+    size_t color1Offset = Align(sizeof(color0), mMinUniformBufferOffsetAlignment);
 
     std::vector<uint8_t> data(color1Offset + sizeof(color1));
     memcpy(data.data(), color0.data(), sizeof(color0));
@@ -719,7 +726,7 @@
     std::array<float, 4> color0 = {1, 0, 0, 0.5};
     std::array<float, 4> color1 = {0, 1, 0, 0.5};
 
-    size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment);
+    size_t color1Offset = Align(sizeof(color0), mMinUniformBufferOffsetAlignment);
 
     std::vector<uint8_t> data(color1Offset + sizeof(color1));
     memcpy(data.data(), color0.data(), sizeof(color0));
@@ -806,9 +813,9 @@
     std::array<float, 4> color2 = {0, 0, 0, 0.501};
     std::array<float, 4> color3 = {0, 0, 1, 0};
 
-    size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment);
-    size_t color2Offset = Align(color1Offset + sizeof(color1), kMinUniformBufferOffsetAlignment);
-    size_t color3Offset = Align(color2Offset + sizeof(color2), kMinUniformBufferOffsetAlignment);
+    size_t color1Offset = Align(sizeof(color0), mMinUniformBufferOffsetAlignment);
+    size_t color2Offset = Align(color1Offset + sizeof(color1), mMinUniformBufferOffsetAlignment);
+    size_t color3Offset = Align(color2Offset + sizeof(color2), mMinUniformBufferOffsetAlignment);
 
     std::vector<uint8_t> data(color3Offset + sizeof(color3), 0);
     memcpy(data.data(), color0.data(), sizeof(color0));
@@ -906,9 +913,9 @@
     std::array<float, 4> color3 = {0, 0, 0, 1};
 
     size_t color0Offset = 0;
-    size_t color1Offset = Align(color0Offset + sizeof(color0), kMinUniformBufferOffsetAlignment);
-    size_t color2Offset = Align(color1Offset + sizeof(color1), kMinUniformBufferOffsetAlignment);
-    size_t color3Offset = Align(color2Offset + sizeof(color2), kMinUniformBufferOffsetAlignment);
+    size_t color1Offset = Align(color0Offset + sizeof(color0), mMinUniformBufferOffsetAlignment);
+    size_t color2Offset = Align(color1Offset + sizeof(color1), mMinUniformBufferOffsetAlignment);
+    size_t color3Offset = Align(color2Offset + sizeof(color2), mMinUniformBufferOffsetAlignment);
 
     std::vector<uint8_t> data(color3Offset + sizeof(color3), 0);
     memcpy(data.data(), color0.data(), sizeof(color0));
@@ -985,14 +992,14 @@
     // We will put the following values and the respective offsets into a buffer.
     // The test will ensure that the correct dynamic offset is applied to each buffer by reading the
     // value from an offset binding.
-    std::array<uint32_t, 3> offsets = {3 * kMinUniformBufferOffsetAlignment,
-                                       1 * kMinUniformBufferOffsetAlignment,
-                                       2 * kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 3> offsets = {3 * mMinUniformBufferOffsetAlignment,
+                                       1 * mMinUniformBufferOffsetAlignment,
+                                       2 * mMinUniformBufferOffsetAlignment};
     std::array<uint32_t, 3> values = {21, 67, 32};
 
     // Create three buffers large enough to by offset by the largest offset.
     wgpu::BufferDescriptor bufferDescriptor;
-    bufferDescriptor.size = 3 * kMinUniformBufferOffsetAlignment + sizeof(uint32_t);
+    bufferDescriptor.size = 3 * mMinUniformBufferOffsetAlignment + sizeof(uint32_t);
     bufferDescriptor.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst;
 
     wgpu::Buffer buffer0 = device.CreateBuffer(&bufferDescriptor);
@@ -1075,19 +1082,19 @@
         uint32_t dynamicBufferBindingNumber = dynamicBufferFirst ? 0 : 1;
         uint32_t bufferBindingNumber = dynamicBufferFirst ? 1 : 0;
 
-        std::array<uint32_t, 1> offsets{kMinUniformBufferOffsetAlignment};
+        std::array<uint32_t, 1> offsets{mMinUniformBufferOffsetAlignment};
         std::array<uint32_t, 2> values = {21, 67};
 
         // Create three buffers large enough to by offset by the largest offset.
         wgpu::BufferDescriptor bufferDescriptor;
-        bufferDescriptor.size = 2 * kMinUniformBufferOffsetAlignment + sizeof(uint32_t);
+        bufferDescriptor.size = 2 * mMinUniformBufferOffsetAlignment + sizeof(uint32_t);
         bufferDescriptor.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
 
         wgpu::Buffer dynamicBuffer = device.CreateBuffer(&bufferDescriptor);
         wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
 
         // Populate the values
-        queue.WriteBuffer(dynamicBuffer, kMinUniformBufferOffsetAlignment,
+        queue.WriteBuffer(dynamicBuffer, mMinUniformBufferOffsetAlignment,
                           &values[dynamicBufferBindingNumber], sizeof(uint32_t));
         queue.WriteBuffer(buffer, 0, &values[bufferBindingNumber], sizeof(uint32_t));
 
diff --git a/src/tests/end2end/DynamicBufferOffsetTests.cpp b/src/tests/end2end/DynamicBufferOffsetTests.cpp
index fe4ea5a..6cb17c8 100644
--- a/src/tests/end2end/DynamicBufferOffsetTests.cpp
+++ b/src/tests/end2end/DynamicBufferOffsetTests.cpp
@@ -18,8 +18,6 @@
 #include "utils/WGPUHelpers.h"
 
 constexpr uint32_t kRTSize = 400;
-constexpr uint32_t kBufferElementsCount = kMinUniformBufferOffsetAlignment / sizeof(uint32_t) + 2;
-constexpr uint32_t kBufferSize = kBufferElementsCount * sizeof(uint32_t);
 constexpr uint32_t kBindingSize = 8;
 
 class DynamicBufferOffsetTests : public DawnTest {
@@ -27,24 +25,29 @@
     void SetUp() override {
         DawnTest::SetUp();
 
+        mMinUniformBufferOffsetAlignment =
+            GetSupportedLimits().limits.minUniformBufferOffsetAlignment;
+
         // Mix up dynamic and non dynamic resources in one bind group and using not continuous
         // binding number to cover more cases.
-        std::array<uint32_t, kBufferElementsCount> uniformData = {0};
+        std::vector<uint32_t> uniformData(mMinUniformBufferOffsetAlignment / sizeof(uint32_t) + 2);
         uniformData[0] = 1;
         uniformData[1] = 2;
 
-        mUniformBuffers[0] = utils::CreateBufferFromData(device, uniformData.data(), kBufferSize,
+        mUniformBuffers[0] = utils::CreateBufferFromData(device, uniformData.data(),
+                                                         sizeof(uint32_t) * uniformData.size(),
                                                          wgpu::BufferUsage::Uniform);
 
         uniformData[uniformData.size() - 2] = 5;
         uniformData[uniformData.size() - 1] = 6;
 
         // Dynamic uniform buffer
-        mUniformBuffers[1] = utils::CreateBufferFromData(device, uniformData.data(), kBufferSize,
+        mUniformBuffers[1] = utils::CreateBufferFromData(device, uniformData.data(),
+                                                         sizeof(uint32_t) * uniformData.size(),
                                                          wgpu::BufferUsage::Uniform);
 
         wgpu::BufferDescriptor storageBufferDescriptor;
-        storageBufferDescriptor.size = kBufferSize;
+        storageBufferDescriptor.size = sizeof(uint32_t) * uniformData.size();
         storageBufferDescriptor.usage =
             wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
 
@@ -72,7 +75,8 @@
                                                {4, mStorageBuffers[1], 0, kBindingSize}});
 
         // Extra uniform buffer for inheriting test
-        mUniformBuffers[2] = utils::CreateBufferFromData(device, uniformData.data(), kBufferSize,
+        mUniformBuffers[2] = utils::CreateBufferFromData(device, uniformData.data(),
+                                                         sizeof(uint32_t) * uniformData.size(),
                                                          wgpu::BufferUsage::Uniform);
 
         // Bind group layout for inheriting test
@@ -86,6 +90,7 @@
     }
     // Create objects to use as resources inside test bind groups.
 
+    uint32_t mMinUniformBufferOffsetAlignment;
     wgpu::BindGroup mBindGroups[2];
     wgpu::BindGroupLayout mBindGroupLayouts[2];
     wgpu::Buffer mUniformBuffers[3];
@@ -227,8 +232,8 @@
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
     wgpu::RenderPassEncoder renderPassEncoder =
         commandEncoder.BeginRenderPass(&renderPass.renderPassInfo);
     renderPassEncoder.SetPipeline(pipeline);
@@ -241,7 +246,7 @@
     std::vector<uint32_t> expectedData = {6, 8};
     EXPECT_PIXEL_RGBA8_EQ(RGBA8(5, 6, 255, 255), renderPass.color, 0, 0);
     EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
-                               kMinUniformBufferOffsetAlignment, expectedData.size());
+                               mMinUniformBufferOffsetAlignment, expectedData.size());
 }
 
 // Dynamic offsets are all zero and no effect to result.
@@ -267,8 +272,8 @@
 TEST_P(DynamicBufferOffsetTests, SetDynamicOffsetsComputePipeline) {
     wgpu::ComputePipeline pipeline = CreateComputePipeline();
 
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
     wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass();
@@ -281,7 +286,7 @@
 
     std::vector<uint32_t> expectedData = {6, 8};
     EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
-                               kMinUniformBufferOffsetAlignment, expectedData.size());
+                               mMinUniformBufferOffsetAlignment, expectedData.size());
 }
 
 // Test inherit dynamic offsets on render pipeline
@@ -293,8 +298,8 @@
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
     wgpu::RenderPassEncoder renderPassEncoder =
         commandEncoder.BeginRenderPass(&renderPass.renderPassInfo);
     renderPassEncoder.SetPipeline(pipeline);
@@ -310,7 +315,7 @@
     std::vector<uint32_t> expectedData = {12, 16};
     EXPECT_PIXEL_RGBA8_EQ(RGBA8(5, 6, 255, 255), renderPass.color, 0, 0);
     EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
-                               kMinUniformBufferOffsetAlignment, expectedData.size());
+                               mMinUniformBufferOffsetAlignment, expectedData.size());
 }
 
 // Test inherit dynamic offsets on compute pipeline
@@ -322,8 +327,8 @@
     wgpu::ComputePipeline pipeline = CreateComputePipeline();
     wgpu::ComputePipeline testPipeline = CreateComputePipeline(true);
 
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
     wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass();
@@ -339,7 +344,7 @@
 
     std::vector<uint32_t> expectedData = {12, 16};
     EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
-                               kMinUniformBufferOffsetAlignment, expectedData.size());
+                               mMinUniformBufferOffsetAlignment, expectedData.size());
 }
 
 // Setting multiple dynamic offsets for the same bindgroup in one render pass.
@@ -350,8 +355,8 @@
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
     std::array<uint32_t, 2> testOffsets = {0, 0};
 
     wgpu::RenderPassEncoder renderPassEncoder =
@@ -374,8 +379,8 @@
 TEST_P(DynamicBufferOffsetTests, UpdateDynamicOffsetsMultipleTimesComputePipeline) {
     wgpu::ComputePipeline pipeline = CreateComputePipeline();
 
-    std::array<uint32_t, 2> offsets = {kMinUniformBufferOffsetAlignment,
-                                       kMinUniformBufferOffsetAlignment};
+    std::array<uint32_t, 2> offsets = {mMinUniformBufferOffsetAlignment,
+                                       mMinUniformBufferOffsetAlignment};
     std::array<uint32_t, 2> testOffsets = {0, 0};
 
     wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
diff --git a/src/tests/end2end/SwapChainValidationTests.cpp b/src/tests/end2end/SwapChainValidationTests.cpp
index 1926f62..96e675c 100644
--- a/src/tests/end2end/SwapChainValidationTests.cpp
+++ b/src/tests/end2end/SwapChainValidationTests.cpp
@@ -115,6 +115,7 @@
 
 // Checks that the creation size must be a valid 2D texture size.
 TEST_P(SwapChainValidationTests, InvalidCreationSize) {
+    wgpu::Limits supportedLimits = GetSupportedLimits().limits;
     // A width of 0 is invalid.
     {
         wgpu::SwapChainDescriptor desc = goodDescriptor;
@@ -128,23 +129,23 @@
         ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
     }
 
-    // A width of kMaxTextureDimension2D is valid but kMaxTextureDimension2D + 1 isn't.
+    // A width of maxTextureDimension2D is valid but maxTextureDimension2D + 1 isn't.
     {
         wgpu::SwapChainDescriptor desc = goodDescriptor;
-        desc.width = kMaxTextureDimension2D;
+        desc.width = supportedLimits.maxTextureDimension2D;
         device.CreateSwapChain(surface, &desc);
 
-        desc.width = kMaxTextureDimension2D + 1;
+        desc.width = supportedLimits.maxTextureDimension2D + 1;
         ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
     }
 
-    // A height of kMaxTextureDimension2D is valid but kMaxTextureDimension2D + 1 isn't.
+    // A height of maxTextureDimension2D is valid but maxTextureDimension2D + 1 isn't.
     {
         wgpu::SwapChainDescriptor desc = goodDescriptor;
-        desc.height = kMaxTextureDimension2D;
+        desc.height = supportedLimits.maxTextureDimension2D;
         device.CreateSwapChain(surface, &desc);
 
-        desc.height = kMaxTextureDimension2D + 1;
+        desc.height = supportedLimits.maxTextureDimension2D + 1;
         ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
     }
 }
diff --git a/src/tests/perf_tests/DrawCallPerf.cpp b/src/tests/perf_tests/DrawCallPerf.cpp
index 97991a0..7999a5a 100644
--- a/src/tests/perf_tests/DrawCallPerf.cpp
+++ b/src/tests/perf_tests/DrawCallPerf.cpp
@@ -270,7 +270,8 @@
     DawnPerfTestWithParams::SetUp();
 
     // Compute aligned uniform / vertex data sizes.
-    mAlignedUniformSize = Align(kUniformSize, kMinUniformBufferOffsetAlignment);
+    mAlignedUniformSize =
+        Align(kUniformSize, GetSupportedLimits().limits.minUniformBufferOffsetAlignment);
     mAlignedVertexDataSize = Align(sizeof(kVertexData), 4);
 
     // Initialize uniform buffer data.
diff --git a/src/tests/unittests/validation/BindGroupValidationTests.cpp b/src/tests/unittests/validation/BindGroupValidationTests.cpp
index 109b93c..ab54791 100644
--- a/src/tests/unittests/validation/BindGroupValidationTests.cpp
+++ b/src/tests/unittests/validation/BindGroupValidationTests.cpp
@@ -708,8 +708,10 @@
 
 // Tests constraints to be sure the uniform buffer binding isn't too large
 TEST_F(BindGroupValidationTest, MaxUniformBufferBindingSize) {
+    wgpu::Limits supportedLimits = GetSupportedLimits().limits;
+
     wgpu::BufferDescriptor descriptor;
-    descriptor.size = 2 * kMaxUniformBufferBindingSize;
+    descriptor.size = 2 * supportedLimits.maxUniformBufferBindingSize;
     descriptor.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage;
     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
 
@@ -717,7 +719,8 @@
         device, {{0, wgpu::ShaderStage::Vertex, wgpu::BufferBindingType::Uniform}});
 
     // Success case, this is exactly the limit
-    utils::MakeBindGroup(device, uniformLayout, {{0, buffer, 0, kMaxUniformBufferBindingSize}});
+    utils::MakeBindGroup(device, uniformLayout,
+                         {{0, buffer, 0, supportedLimits.maxUniformBufferBindingSize}});
 
     wgpu::BindGroupLayout doubleUniformLayout = utils::MakeBindGroupLayout(
         device, {{0, wgpu::ShaderStage::Vertex, wgpu::BufferBindingType::Uniform},
@@ -725,12 +728,13 @@
 
     // Success case, individual bindings don't exceed the limit
     utils::MakeBindGroup(device, doubleUniformLayout,
-                         {{0, buffer, 0, kMaxUniformBufferBindingSize},
-                          {1, buffer, kMaxUniformBufferBindingSize, kMaxUniformBufferBindingSize}});
+                         {{0, buffer, 0, supportedLimits.maxUniformBufferBindingSize},
+                          {1, buffer, supportedLimits.maxUniformBufferBindingSize,
+                           supportedLimits.maxUniformBufferBindingSize}});
 
     // Error case, this is above the limit
-    ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, uniformLayout,
-                                             {{0, buffer, 0, kMaxUniformBufferBindingSize + 1}}));
+    ASSERT_DEVICE_ERROR(utils::MakeBindGroup(
+        device, uniformLayout, {{0, buffer, 0, supportedLimits.maxUniformBufferBindingSize + 1}}));
 
     // Making sure the constraint doesn't apply to storage buffers
     wgpu::BindGroupLayout readonlyStorageLayout = utils::MakeBindGroupLayout(
@@ -740,14 +744,17 @@
 
     // Success case, storage buffer can still be created.
     utils::MakeBindGroup(device, readonlyStorageLayout,
-                         {{0, buffer, 0, 2 * kMaxUniformBufferBindingSize}});
-    utils::MakeBindGroup(device, storageLayout, {{0, buffer, 0, 2 * kMaxUniformBufferBindingSize}});
+                         {{0, buffer, 0, 2 * supportedLimits.maxUniformBufferBindingSize}});
+    utils::MakeBindGroup(device, storageLayout,
+                         {{0, buffer, 0, 2 * supportedLimits.maxUniformBufferBindingSize}});
 }
 
 // Tests constraints to be sure the storage buffer binding isn't too large
 TEST_F(BindGroupValidationTest, MaxStorageBufferBindingSize) {
+    wgpu::Limits supportedLimits = GetSupportedLimits().limits;
+
     wgpu::BufferDescriptor descriptor;
-    descriptor.size = 2 * kMaxStorageBufferBindingSize;
+    descriptor.size = 2 * supportedLimits.maxStorageBufferBindingSize;
     descriptor.usage = wgpu::BufferUsage::Storage;
     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
 
@@ -755,10 +762,12 @@
         device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}});
 
     // Success case, this is exactly the limit
-    utils::MakeBindGroup(device, uniformLayout, {{0, buffer, 0, kMaxStorageBufferBindingSize}});
+    utils::MakeBindGroup(device, uniformLayout,
+                         {{0, buffer, 0, supportedLimits.maxStorageBufferBindingSize}});
 
     // Success case, this is one less than the limit (check it is not an alignment constraint)
-    utils::MakeBindGroup(device, uniformLayout, {{0, buffer, 0, kMaxStorageBufferBindingSize - 1}});
+    utils::MakeBindGroup(device, uniformLayout,
+                         {{0, buffer, 0, supportedLimits.maxStorageBufferBindingSize - 1}});
 
     wgpu::BindGroupLayout doubleUniformLayout = utils::MakeBindGroupLayout(
         device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage},
@@ -766,12 +775,13 @@
 
     // Success case, individual bindings don't exceed the limit
     utils::MakeBindGroup(device, doubleUniformLayout,
-                         {{0, buffer, 0, kMaxStorageBufferBindingSize},
-                          {1, buffer, kMaxStorageBufferBindingSize, kMaxStorageBufferBindingSize}});
+                         {{0, buffer, 0, supportedLimits.maxStorageBufferBindingSize},
+                          {1, buffer, supportedLimits.maxStorageBufferBindingSize,
+                           supportedLimits.maxStorageBufferBindingSize}});
 
     // Error case, this is above the limit
-    ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, uniformLayout,
-                                             {{0, buffer, 0, kMaxStorageBufferBindingSize + 1}}));
+    ASSERT_DEVICE_ERROR(utils::MakeBindGroup(
+        device, uniformLayout, {{0, buffer, 0, supportedLimits.maxStorageBufferBindingSize + 1}}));
 }
 
 // Test what happens when the layout is an error.
@@ -1306,7 +1316,6 @@
                                });
 }
 
-constexpr uint64_t kBufferSize = 3 * kMinUniformBufferOffsetAlignment + 8;
 constexpr uint32_t kBindingSize = 9;
 
 class SetBindGroupValidationTest : public ValidationTest {
@@ -1323,6 +1332,9 @@
                       wgpu::BufferBindingType::Storage, true},
                      {3, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
                       wgpu::BufferBindingType::ReadOnlyStorage, true}});
+        mMinUniformBufferOffsetAlignment =
+            GetSupportedLimits().limits.minUniformBufferOffsetAlignment;
+        mBufferSize = 3 * mMinUniformBufferOffsetAlignment + 8;
     }
 
     wgpu::Buffer CreateBuffer(uint64_t bufferSize, wgpu::BufferUsage usage) {
@@ -1431,14 +1443,18 @@
             commandEncoder.Finish();
         }
     }
+
+  protected:
+    uint32_t mMinUniformBufferOffsetAlignment;
+    uint64_t mBufferSize;
 };
 
 // This is the test case that should work.
 TEST_F(SetBindGroupValidationTest, Basic) {
     // Set up the bind group.
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1461,9 +1477,9 @@
 // Setting bind group after a draw / dispatch should re-verify the layout is compatible
 TEST_F(SetBindGroupValidationTest, VerifyGroupIfChangedAfterAction) {
     // Set up the bind group
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1510,9 +1526,9 @@
 // Test cases that test dynamic offsets count mismatch with bind group layout.
 TEST_F(SetBindGroupValidationTest, DynamicOffsetsMismatch) {
     // Set up bind group.
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1534,9 +1550,9 @@
 // Test cases that test dynamic offsets not aligned
 TEST_F(SetBindGroupValidationTest, DynamicOffsetsNotAligned) {
     // Set up bind group.
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1554,9 +1570,9 @@
 // Test cases that test dynamic uniform buffer out of bound situation.
 TEST_F(SetBindGroupValidationTest, OffsetOutOfBoundDynamicUniformBuffer) {
     // Set up bind group.
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1574,9 +1590,9 @@
 // Test cases that test dynamic storage buffer out of bound situation.
 TEST_F(SetBindGroupValidationTest, OffsetOutOfBoundDynamicStorageBuffer) {
     // Set up bind group.
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1594,9 +1610,9 @@
 // Test cases that test dynamic uniform buffer out of bound situation because of binding size.
 TEST_F(SetBindGroupValidationTest, BindingSizeOutOfBoundDynamicUniformBuffer) {
     // Set up bind group, but binding size is larger than
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1614,9 +1630,9 @@
 
 // Test cases that test dynamic storage buffer out of bound situation because of binding size.
 TEST_F(SetBindGroupValidationTest, BindingSizeOutOfBoundDynamicStorageBuffer) {
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
-    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer readonlyStorageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, mBindGroupLayout,
                                                      {{0, uniformBuffer, 0, kBindingSize},
                                                       {1, uniformBuffer, 0, kBindingSize},
@@ -1650,11 +1666,11 @@
     // end of the buffer. Any mismatch applying too-large of an offset to a smaller buffer will hit
     // the out-of-bounds condition during validation.
     wgpu::Buffer buffer3x =
-        CreateBuffer(3 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage);
+        CreateBuffer(3 * mMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage);
     wgpu::Buffer buffer2x =
-        CreateBuffer(2 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage);
+        CreateBuffer(2 * mMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage);
     wgpu::Buffer buffer1x =
-        CreateBuffer(1 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Uniform);
+        CreateBuffer(1 * mMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Uniform);
     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl,
                                                      {
                                                          {0, buffer3x, 0, 4},
@@ -1678,7 +1694,7 @@
         // Offset the first binding to touch the end of the buffer. Should succeed.
         // Will fail if the offset is applied to the first or second bindings since their buffers
         // are too small.
-        offsets = {/* binding 0 */ 3 * kMinUniformBufferOffsetAlignment,
+        offsets = {/* binding 0 */ 3 * mMinUniformBufferOffsetAlignment,
                    /* binding 2 */ 0,
                    /* binding 3 */ 0};
         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
@@ -1690,7 +1706,7 @@
     {
         // Offset the second binding to touch the end of the buffer. Should succeed.
         offsets = {/* binding 0 */ 0,
-                   /* binding 2 */ 1 * kMinUniformBufferOffsetAlignment,
+                   /* binding 2 */ 1 * mMinUniformBufferOffsetAlignment,
                    /* binding 3 */ 0};
         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
         wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass();
@@ -1704,7 +1720,7 @@
         // is too small.
         offsets = {/* binding 0 */ 0,
                    /* binding 2 */ 0,
-                   /* binding 3 */ 2 * kMinUniformBufferOffsetAlignment};
+                   /* binding 3 */ 2 * mMinUniformBufferOffsetAlignment};
         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
         wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass();
         computePassEncoder.SetBindGroup(0, bindGroup, offsets.size(), offsets.data());
@@ -1713,9 +1729,9 @@
     }
     {
         // Offset each binding to touch the end of their buffer. Should succeed.
-        offsets = {/* binding 0 */ 3 * kMinUniformBufferOffsetAlignment,
-                   /* binding 2 */ 1 * kMinUniformBufferOffsetAlignment,
-                   /* binding 3 */ 2 * kMinUniformBufferOffsetAlignment};
+        offsets = {/* binding 0 */ 3 * mMinUniformBufferOffsetAlignment,
+                   /* binding 2 */ 1 * mMinUniformBufferOffsetAlignment,
+                   /* binding 3 */ 2 * mMinUniformBufferOffsetAlignment};
         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
         wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass();
         computePassEncoder.SetBindGroup(0, bindGroup, offsets.size(), offsets.data());
@@ -1745,6 +1761,8 @@
                 [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
                     return vec4<f32>();
                 })");
+
+        mBufferSize = 3 * GetSupportedLimits().limits.minUniformBufferOffsetAlignment + 8;
     }
 
     wgpu::Buffer CreateBuffer(uint64_t bufferSize, wgpu::BufferUsage usage) {
@@ -1824,6 +1842,9 @@
         return std::make_tuple(bindGroupLayouts, pipeline);
     }
 
+  protected:
+    uint32_t mBufferSize;
+
   private:
     wgpu::ShaderModule mVsModule;
 };
@@ -1843,8 +1864,8 @@
         }},
     }});
 
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
 
     wgpu::BindGroup bindGroup0 = utils::MakeBindGroup(
         device, bindGroupLayouts[0],
@@ -1897,8 +1918,8 @@
         }},
     }});
 
-    wgpu::Buffer uniformBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
-    wgpu::Buffer storageBuffer = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+    wgpu::Buffer uniformBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
+    wgpu::Buffer storageBuffer = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
 
     wgpu::BindGroup bindGroupA0 = utils::MakeBindGroup(
         device, bindGroupLayoutsA[0],
@@ -2152,6 +2173,11 @@
 
 class BindingsValidationTest : public BindGroupLayoutCompatibilityTest {
   public:
+    void SetUp() override {
+        BindGroupLayoutCompatibilityTest::SetUp();
+        mBufferSize = 3 * GetSupportedLimits().limits.minUniformBufferOffsetAlignment + 8;
+    }
+
     void TestRenderPassBindings(const wgpu::BindGroup* bg,
                                 uint32_t count,
                                 wgpu::RenderPipeline pipeline,
@@ -2191,6 +2217,7 @@
         }
     }
 
+    uint32_t mBufferSize;
     static constexpr uint32_t kBindingNum = 3;
 };
 
@@ -2263,7 +2290,7 @@
         bgl[i] = utils::MakeBindGroupLayout(
             device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
                       wgpu::BufferBindingType::Storage}});
-        buffer[i] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+        buffer[i] = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
         bg[i] = utils::MakeBindGroup(device, bgl[i], {{0, buffer[i]}});
     }
 
@@ -2284,7 +2311,7 @@
                   wgpu::BufferBindingType::ReadOnlyStorage},
                  {1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
                   wgpu::BufferBindingType::Uniform}});
-    buffer[1] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Uniform);
+    buffer[1] = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Uniform);
     bg[1] = utils::MakeBindGroup(device, bgl[1], {{0, buffer[1]}, {1, buffer[1]}});
 
     TestRenderPassBindings(bg.data(), kBindingNum, renderPipeline, false);
@@ -2304,7 +2331,7 @@
         bgl[i] = utils::MakeBindGroupLayout(
             device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
                       wgpu::BufferBindingType::Storage}});
-        buffer[i] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
+        buffer[i] = CreateBuffer(mBufferSize, wgpu::BufferUsage::Storage);
         bg[i] = utils::MakeBindGroup(device, bgl[i], {{0, buffer[i]}});
     }
 
@@ -2329,7 +2356,7 @@
     bgl[2] = utils::MakeBindGroupLayout(
         device, {{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
                   wgpu::BufferBindingType::Uniform}});
-    buffer[2] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
+    buffer[2] = CreateBuffer(mBufferSize, wgpu::BufferUsage::Uniform);
     bg[2] = utils::MakeBindGroup(device, bgl[2], {{1, buffer[2]}});
 
     TestRenderPassBindings(bg.data(), kBindingNum, renderPipeline, false);
diff --git a/src/tests/unittests/validation/ComputeValidationTests.cpp b/src/tests/unittests/validation/ComputeValidationTests.cpp
index 6d66b87..0e9c68e 100644
--- a/src/tests/unittests/validation/ComputeValidationTests.cpp
+++ b/src/tests/unittests/validation/ComputeValidationTests.cpp
@@ -57,27 +57,30 @@
 
 // Check that the largest allowed dispatch is OK.
 TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_LargestValid) {
-    constexpr uint32_t kMax = kMaxComputePerDimensionDispatchSize;
-    TestDispatch(kMax, kMax, kMax);
+    const uint32_t max = GetSupportedLimits().limits.maxComputeWorkgroupsPerDimension;
+    TestDispatch(max, max, max);
 }
 
 // Check that exceeding the maximum on the X dimension results in validation failure.
 TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidX) {
-    ASSERT_DEVICE_ERROR(TestDispatch(kMaxComputePerDimensionDispatchSize + 1, 1, 1));
+    const uint32_t max = GetSupportedLimits().limits.maxComputeWorkgroupsPerDimension;
+    ASSERT_DEVICE_ERROR(TestDispatch(max + 1, 1, 1));
 }
 
 // Check that exceeding the maximum on the Y dimension results in validation failure.
 TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidY) {
-    ASSERT_DEVICE_ERROR(TestDispatch(1, kMaxComputePerDimensionDispatchSize + 1, 1));
+    const uint32_t max = GetSupportedLimits().limits.maxComputeWorkgroupsPerDimension;
+    ASSERT_DEVICE_ERROR(TestDispatch(1, max + 1, 1));
 }
 
 // Check that exceeding the maximum on the Z dimension results in validation failure.
 TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidZ) {
-    ASSERT_DEVICE_ERROR(TestDispatch(1, 1, kMaxComputePerDimensionDispatchSize + 1));
+    const uint32_t max = GetSupportedLimits().limits.maxComputeWorkgroupsPerDimension;
+    ASSERT_DEVICE_ERROR(TestDispatch(1, 1, max + 1));
 }
 
 // Check that exceeding the maximum on all dimensions results in validation failure.
 TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidAll) {
-    constexpr uint32_t kMax = kMaxComputePerDimensionDispatchSize;
-    ASSERT_DEVICE_ERROR(TestDispatch(kMax + 1, kMax + 1, kMax + 1));
+    const uint32_t max = GetSupportedLimits().limits.maxComputeWorkgroupsPerDimension;
+    ASSERT_DEVICE_ERROR(TestDispatch(max + 1, max + 1, max + 1));
 }
diff --git a/src/tests/unittests/validation/ShaderModuleValidationTests.cpp b/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
index da78826..36eb4b5 100644
--- a/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
+++ b/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
@@ -444,29 +444,37 @@
         utils::CreateShaderModule(device, ss.str().c_str());
     };
 
-    MakeShaderWithWorkgroupSize(1, 1, 1);
-    MakeShaderWithWorkgroupSize(kMaxComputeWorkgroupSizeX, 1, 1);
-    MakeShaderWithWorkgroupSize(1, kMaxComputeWorkgroupSizeY, 1);
-    MakeShaderWithWorkgroupSize(1, 1, kMaxComputeWorkgroupSizeZ);
+    wgpu::Limits supportedLimits = GetSupportedLimits().limits;
 
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupSize(kMaxComputeWorkgroupSizeX + 1, 1, 1));
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupSize(1, kMaxComputeWorkgroupSizeY + 1, 1));
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupSize(1, 1, kMaxComputeWorkgroupSizeZ + 1));
+    MakeShaderWithWorkgroupSize(1, 1, 1);
+    MakeShaderWithWorkgroupSize(supportedLimits.maxComputeWorkgroupSizeX, 1, 1);
+    MakeShaderWithWorkgroupSize(1, supportedLimits.maxComputeWorkgroupSizeY, 1);
+    MakeShaderWithWorkgroupSize(1, 1, supportedLimits.maxComputeWorkgroupSizeZ);
+
+    ASSERT_DEVICE_ERROR(
+        MakeShaderWithWorkgroupSize(supportedLimits.maxComputeWorkgroupSizeX + 1, 1, 1));
+    ASSERT_DEVICE_ERROR(
+        MakeShaderWithWorkgroupSize(1, supportedLimits.maxComputeWorkgroupSizeY + 1, 1));
+    ASSERT_DEVICE_ERROR(
+        MakeShaderWithWorkgroupSize(1, 1, supportedLimits.maxComputeWorkgroupSizeZ + 1));
 
     // No individual dimension exceeds its limit, but the combined size should definitely exceed the
     // total invocation limit.
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupSize(
-        kMaxComputeWorkgroupSizeX, kMaxComputeWorkgroupSizeY, kMaxComputeWorkgroupSizeZ));
+    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupSize(supportedLimits.maxComputeWorkgroupSizeX,
+                                                    supportedLimits.maxComputeWorkgroupSizeY,
+                                                    supportedLimits.maxComputeWorkgroupSizeZ));
 }
 
 // Tests that we validate workgroup storage size limits.
 TEST_F(ShaderModuleValidationTest, ComputeWorkgroupStorageSizeLimits) {
     DAWN_SKIP_TEST_IF(!HasToggleEnabled("use_tint_generator"));
 
+    wgpu::Limits supportedLimits = GetSupportedLimits().limits;
+
     constexpr uint32_t kVec4Size = 16;
-    constexpr uint32_t kMaxVec4Count = kMaxComputeWorkgroupStorageSize / kVec4Size;
+    const uint32_t maxVec4Count = supportedLimits.maxComputeWorkgroupStorageSize / kVec4Size;
     constexpr uint32_t kMat4Size = 64;
-    constexpr uint32_t kMaxMat4Count = kMaxComputeWorkgroupStorageSize / kMat4Size;
+    const uint32_t maxMat4Count = supportedLimits.maxComputeWorkgroupStorageSize / kMat4Size;
 
     auto MakeShaderWithWorkgroupStorage = [this](uint32_t vec4_count, uint32_t mat4_count) {
         std::ostringstream ss;
@@ -484,14 +492,14 @@
     };
 
     MakeShaderWithWorkgroupStorage(1, 1);
-    MakeShaderWithWorkgroupStorage(kMaxVec4Count, 0);
-    MakeShaderWithWorkgroupStorage(0, kMaxMat4Count);
-    MakeShaderWithWorkgroupStorage(kMaxVec4Count - 4, 1);
-    MakeShaderWithWorkgroupStorage(4, kMaxMat4Count - 1);
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(kMaxVec4Count + 1, 0));
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(kMaxVec4Count - 3, 1));
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(0, kMaxMat4Count + 1));
-    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(4, kMaxMat4Count));
+    MakeShaderWithWorkgroupStorage(maxVec4Count, 0);
+    MakeShaderWithWorkgroupStorage(0, maxMat4Count);
+    MakeShaderWithWorkgroupStorage(maxVec4Count - 4, 1);
+    MakeShaderWithWorkgroupStorage(4, maxMat4Count - 1);
+    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(maxVec4Count + 1, 0));
+    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(maxVec4Count - 3, 1));
+    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(0, maxMat4Count + 1));
+    ASSERT_DEVICE_ERROR(MakeShaderWithWorkgroupStorage(4, maxMat4Count));
 }
 
 // Test that numeric ID must be unique
diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp
index e9180a9..6a430a4 100644
--- a/src/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureValidationTests.cpp
@@ -15,6 +15,7 @@
 #include "tests/unittests/validation/ValidationTest.h"
 
 #include "common/Constants.h"
+#include "common/Math.h"
 #include "utils/ComboRenderPipelineDescriptor.h"
 #include "utils/TextureUtils.h"
 #include "utils/WGPUHelpers.h"
@@ -264,12 +265,24 @@
             device.CreateTexture(&descriptor);
         }
 
-        // Mip level exceeding kMaxTexture2DMipLevels not allowed
+        // Mip level equal to the maximum for a 2D texture is allowed
         {
+            uint32_t maxTextureDimension2D = GetSupportedLimits().limits.maxTextureDimension2D;
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.width = 1 >> kMaxTexture2DMipLevels;
-            descriptor.size.height = 1 >> kMaxTexture2DMipLevels;
-            descriptor.mipLevelCount = kMaxTexture2DMipLevels + 1u;
+            descriptor.size.width = maxTextureDimension2D;
+            descriptor.size.height = maxTextureDimension2D;
+            descriptor.mipLevelCount = Log2(maxTextureDimension2D) + 1u;
+
+            device.CreateTexture(&descriptor);
+        }
+
+        // Mip level exceeding the maximum for a 2D texture not allowed
+        {
+            uint32_t maxTextureDimension2D = GetSupportedLimits().limits.maxTextureDimension2D;
+            wgpu::TextureDescriptor descriptor = defaultDescriptor;
+            descriptor.size.width = maxTextureDimension2D;
+            descriptor.size.height = maxTextureDimension2D;
+            descriptor.mipLevelCount = Log2(maxTextureDimension2D) + 2u;
 
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
         }
@@ -278,26 +291,27 @@
     // Test the validation of array layer count
     TEST_F(TextureValidationTest, ArrayLayerCount) {
         wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
+        wgpu::Limits supportedLimits = GetSupportedLimits().limits;
 
-        // Array layer count exceeding kMaxTextureArrayLayers is not allowed for 2D texture
+        // Array layer count exceeding maxTextureArrayLayers is not allowed for 2D texture
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
 
-            descriptor.size.depthOrArrayLayers = kMaxTextureArrayLayers + 1u;
+            descriptor.size.depthOrArrayLayers = supportedLimits.maxTextureArrayLayers + 1u;
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
         }
 
-        // Array layer count less than kMaxTextureArrayLayers is allowed
+        // Array layer count less than maxTextureArrayLayers is allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.depthOrArrayLayers = kMaxTextureArrayLayers >> 1;
+            descriptor.size.depthOrArrayLayers = supportedLimits.maxTextureArrayLayers >> 1;
             device.CreateTexture(&descriptor);
         }
 
-        // Array layer count equal to kMaxTextureArrayLayers is allowed
+        // Array layer count equal to maxTextureArrayLayers is allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.depthOrArrayLayers = kMaxTextureArrayLayers;
+            descriptor.size.depthOrArrayLayers = supportedLimits.maxTextureArrayLayers;
             device.CreateTexture(&descriptor);
         }
     }
@@ -305,15 +319,16 @@
     // Test the validation of 2D texture size
     TEST_F(TextureValidationTest, 2DTextureSize) {
         wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
+        wgpu::Limits supportedLimits = GetSupportedLimits().limits;
 
         // Out-of-bound texture dimension is not allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.width = kMaxTextureDimension2D + 1u;
+            descriptor.size.width = supportedLimits.maxTextureDimension2D + 1u;
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
 
             descriptor.size.width = 1;
-            descriptor.size.height = kMaxTextureDimension2D + 1u;
+            descriptor.size.height = supportedLimits.maxTextureDimension2D + 1u;
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
         }
 
@@ -334,16 +349,16 @@
         // Texture size less than max dimension is allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.width = kMaxTextureDimension2D >> 1;
-            descriptor.size.height = kMaxTextureDimension2D >> 1;
+            descriptor.size.width = supportedLimits.maxTextureDimension2D >> 1;
+            descriptor.size.height = supportedLimits.maxTextureDimension2D >> 1;
             device.CreateTexture(&descriptor);
         }
 
         // Texture size equal to max dimension is allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
-            descriptor.size.width = kMaxTextureDimension2D;
-            descriptor.size.height = kMaxTextureDimension2D;
+            descriptor.size.width = supportedLimits.maxTextureDimension2D;
+            descriptor.size.height = supportedLimits.maxTextureDimension2D;
             descriptor.dimension = wgpu::TextureDimension::e2D;
             device.CreateTexture(&descriptor);
         }
@@ -352,19 +367,20 @@
     // Test the validation of 3D texture size
     TEST_F(TextureValidationTest, 3DTextureSize) {
         wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
+        wgpu::Limits supportedLimits = GetSupportedLimits().limits;
 
         // Out-of-bound texture dimension is not allowed
         {
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
             descriptor.dimension = wgpu::TextureDimension::e3D;
 
-            descriptor.size = {kMaxTextureDimension3D + 1u, 1, 1};
+            descriptor.size = {supportedLimits.maxTextureDimension3D + 1u, 1, 1};
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
 
-            descriptor.size = {1, kMaxTextureDimension3D + 1u, 1};
+            descriptor.size = {1, supportedLimits.maxTextureDimension3D + 1u, 1};
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
 
-            descriptor.size = {1, 1, kMaxTextureDimension3D + 1u};
+            descriptor.size = {1, 1, supportedLimits.maxTextureDimension3D + 1u};
             ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
         }
 
@@ -388,8 +404,9 @@
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
             descriptor.dimension = wgpu::TextureDimension::e3D;
 
-            descriptor.size = {kMaxTextureDimension3D >> 1, kMaxTextureDimension3D >> 1,
-                               kMaxTextureDimension3D >> 1};
+            descriptor.size = {supportedLimits.maxTextureDimension3D >> 1,
+                               supportedLimits.maxTextureDimension3D >> 1,
+                               supportedLimits.maxTextureDimension3D >> 1};
             device.CreateTexture(&descriptor);
         }
 
@@ -398,8 +415,9 @@
             wgpu::TextureDescriptor descriptor = defaultDescriptor;
             descriptor.dimension = wgpu::TextureDimension::e3D;
 
-            descriptor.size = {kMaxTextureDimension3D, kMaxTextureDimension3D,
-                               kMaxTextureDimension3D};
+            descriptor.size = {supportedLimits.maxTextureDimension3D,
+                               supportedLimits.maxTextureDimension3D,
+                               supportedLimits.maxTextureDimension3D};
             device.CreateTexture(&descriptor);
         }
     }
diff --git a/src/tests/unittests/validation/ValidationTest.cpp b/src/tests/unittests/validation/ValidationTest.cpp
index 339e32e..1cf834d 100644
--- a/src/tests/unittests/validation/ValidationTest.cpp
+++ b/src/tests/unittests/validation/ValidationTest.cpp
@@ -179,6 +179,13 @@
            }) != toggles.end();
 }
 
+wgpu::SupportedLimits ValidationTest::GetSupportedLimits() {
+    WGPUSupportedLimits supportedLimits;
+    supportedLimits.nextInChain = nullptr;
+    dawn_native::GetProcs().deviceGetLimits(backendDevice, &supportedLimits);
+    return *reinterpret_cast<wgpu::SupportedLimits*>(&supportedLimits);
+}
+
 WGPUDevice ValidationTest::CreateTestDevice() {
     // Disabled disallowing unsafe APIs so we can test them.
     dawn_native::DeviceDescriptor deviceDescriptor;
diff --git a/src/tests/unittests/validation/ValidationTest.h b/src/tests/unittests/validation/ValidationTest.h
index ce2f4c1..fb6bde0 100644
--- a/src/tests/unittests/validation/ValidationTest.h
+++ b/src/tests/unittests/validation/ValidationTest.h
@@ -96,6 +96,11 @@
 
     bool HasToggleEnabled(const char* toggle) const;
 
+    // TODO(crbug.com/dawn/689): Use limits returned from the wire
+    // This is implemented here because tests need to always query
+    // the |backendDevice| since limits are not implemented in the wire.
+    wgpu::SupportedLimits GetSupportedLimits();
+
   protected:
     virtual WGPUDevice CreateTestDevice();