blob: 7c05e961c4225e980b5b876edb4daf975f96a56e [file] [log] [blame]
Corentin Wallezc244f532020-04-24 09:42:03 +00001// Copyright 2020 The Dawn Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "tests/unittests/validation/ValidationTest.h"
16
17#include "utils/ComboRenderBundleEncoderDescriptor.h"
Brandon Jonesccda6a02020-09-01 18:32:49 +000018#include "utils/ComboRenderPipelineDescriptor.h"
19#include "utils/WGPUHelpers.h"
Corentin Wallezc244f532020-04-24 09:42:03 +000020
Brandon Jonesccda6a02020-09-01 18:32:49 +000021class IndexBufferValidationTest : public ValidationTest {
22 protected:
23 wgpu::RenderPipeline MakeTestPipeline(wgpu::IndexFormat format,
24 wgpu::PrimitiveTopology primitiveTopology) {
Corentin Wallez7aec4ae2021-03-24 15:55:32 +000025 wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
Corentin Wallez78d27e82021-04-13 10:42:44 +000026 [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
27 return vec4<f32>(0.0, 0.0, 0.0, 1.0);
Corentin Wallez8fc755b2020-11-26 12:22:35 +000028 })");
Brandon Jonesccda6a02020-09-01 18:32:49 +000029
Corentin Wallez7aec4ae2021-03-24 15:55:32 +000030 wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
Corentin Wallez78d27e82021-04-13 10:42:44 +000031 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
32 return vec4<f32>(0.0, 1.0, 0.0, 1.0);
Corentin Wallez8fc755b2020-11-26 12:22:35 +000033 })");
Brandon Jonesccda6a02020-09-01 18:32:49 +000034
Brandon Jones41c87d92021-05-21 05:01:38 +000035 utils::ComboRenderPipelineDescriptor descriptor;
Brandon Jones6e5d47a2021-03-17 17:48:59 +000036 descriptor.vertex.module = vsModule;
37 descriptor.cFragment.module = fsModule;
38 descriptor.primitive.topology = primitiveTopology;
39 descriptor.primitive.stripIndexFormat = format;
40 descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
Brandon Jonesccda6a02020-09-01 18:32:49 +000041
Brandon Jones41c87d92021-05-21 05:01:38 +000042 return device.CreateRenderPipeline(&descriptor);
Brandon Jonesccda6a02020-09-01 18:32:49 +000043 }
44};
Corentin Wallezc244f532020-04-24 09:42:03 +000045
Corentin Wallez5fad85b2020-11-25 08:54:14 +000046// Test that IndexFormat::Undefined is disallowed.
47TEST_F(IndexBufferValidationTest, UndefinedIndexFormat) {
48 wgpu::BufferDescriptor bufferDesc;
49 bufferDesc.usage = wgpu::BufferUsage::Index;
50 bufferDesc.size = 256;
51 wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
52
53 DummyRenderPass renderPass(device);
54 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
55 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
56 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Undefined);
57 pass.EndPass();
58 ASSERT_DEVICE_ERROR(encoder.Finish());
59}
60
Brandon Jonesbb417ac2021-10-02 01:54:31 +000061// Test that an invalid index format is disallowed.
62TEST_F(IndexBufferValidationTest, InvalidIndexFormat) {
63 wgpu::BufferDescriptor bufferDesc;
64 bufferDesc.usage = wgpu::BufferUsage::Index;
65 bufferDesc.size = 256;
66 wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
67
68 DummyRenderPass renderPass(device);
69 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
70 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
71 pass.SetIndexBuffer(buffer, static_cast<wgpu::IndexFormat>(404));
72 pass.EndPass();
73 ASSERT_DEVICE_ERROR(encoder.Finish());
74}
75
Corentin Wallezc244f532020-04-24 09:42:03 +000076// Test that for OOB validation of index buffer offset and size.
77TEST_F(IndexBufferValidationTest, IndexBufferOffsetOOBValidation) {
Felix Maierf70db582020-04-27 20:29:01 +000078 wgpu::BufferDescriptor bufferDesc;
79 bufferDesc.usage = wgpu::BufferUsage::Index;
80 bufferDesc.size = 256;
Corentin Wallezc244f532020-04-24 09:42:03 +000081 wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
82
83 DummyRenderPass renderPass(device);
84 // Control case, using the full buffer, with or without an explicit size is valid.
85 {
86 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
87 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
88 // Explicit size
Corentin Wallez5fad85b2020-11-25 08:54:14 +000089 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 0, 256);
Corentin Wallezc244f532020-04-24 09:42:03 +000090 // Implicit size
Zhaoming Jiang2be4b842021-09-28 02:05:00 +000091 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 0, wgpu::kWholeSize);
92 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256 - 4, wgpu::kWholeSize);
93 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 4, wgpu::kWholeSize);
Corentin Wallezc244f532020-04-24 09:42:03 +000094 // Implicit size of zero
Zhaoming Jiang2be4b842021-09-28 02:05:00 +000095 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256, wgpu::kWholeSize);
Corentin Wallezc244f532020-04-24 09:42:03 +000096 pass.EndPass();
97 encoder.Finish();
98 }
99
100 // Bad case, offset + size is larger than the buffer
101 {
102 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
103 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000104 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 4, 256);
Corentin Wallezc244f532020-04-24 09:42:03 +0000105 pass.EndPass();
106 ASSERT_DEVICE_ERROR(encoder.Finish());
107 }
108
109 // Bad case, size is 0 but the offset is larger than the buffer
110 {
111 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
112 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000113 pass.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256 + 4, 0);
Corentin Wallezc244f532020-04-24 09:42:03 +0000114 pass.EndPass();
115 ASSERT_DEVICE_ERROR(encoder.Finish());
116 }
117
118 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
119 renderBundleDesc.colorFormatsCount = 1;
120 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
121
122 // Control case, using the full buffer, with or without an explicit size is valid.
123 {
124 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
125 // Explicit size
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000126 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 0, 256);
Corentin Wallezc244f532020-04-24 09:42:03 +0000127 // Implicit size
Zhaoming Jiang2be4b842021-09-28 02:05:00 +0000128 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 0, wgpu::kWholeSize);
129 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256 - 4, wgpu::kWholeSize);
130 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 4, wgpu::kWholeSize);
Corentin Wallezc244f532020-04-24 09:42:03 +0000131 // Implicit size of zero
Zhaoming Jiang2be4b842021-09-28 02:05:00 +0000132 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256, wgpu::kWholeSize);
Corentin Wallezc244f532020-04-24 09:42:03 +0000133 encoder.Finish();
134 }
135
136 // Bad case, offset + size is larger than the buffer
137 {
138 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000139 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 4, 256);
Corentin Wallezc244f532020-04-24 09:42:03 +0000140 ASSERT_DEVICE_ERROR(encoder.Finish());
141 }
142
143 // Bad case, size is 0 but the offset is larger than the buffer
144 {
145 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000146 encoder.SetIndexBuffer(buffer, wgpu::IndexFormat::Uint32, 256 + 4, 0);
Corentin Wallezc244f532020-04-24 09:42:03 +0000147 ASSERT_DEVICE_ERROR(encoder.Finish());
148 }
149}
Brandon Jonesccda6a02020-09-01 18:32:49 +0000150
151// Test that formats given when setting an index buffers must match the format specified on the
152// pipeline for strip primitive topologies.
153TEST_F(IndexBufferValidationTest, IndexBufferFormatMatchesPipelineStripFormat) {
154 wgpu::RenderPipeline pipeline32 = MakeTestPipeline(wgpu::IndexFormat::Uint32,
155 wgpu::PrimitiveTopology::TriangleStrip);
156 wgpu::RenderPipeline pipeline16 = MakeTestPipeline(wgpu::IndexFormat::Uint16,
157 wgpu::PrimitiveTopology::LineStrip);
Brandon Jones370e6bd2021-12-08 17:24:37 +0000158 wgpu::RenderPipeline pipelineUndef =
159 MakeTestPipeline(wgpu::IndexFormat::Undefined, wgpu::PrimitiveTopology::LineStrip);
Brandon Jonesccda6a02020-09-01 18:32:49 +0000160
161 wgpu::Buffer indexBuffer =
162 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index, {0, 1, 2});
163
164 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
165 renderBundleDesc.colorFormatsCount = 1;
166 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
167
168 // Expected to fail because pipeline and index formats don't match.
169 {
170 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000171 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
Brandon Jonesccda6a02020-09-01 18:32:49 +0000172 encoder.SetPipeline(pipeline32);
173 encoder.DrawIndexed(3);
174 ASSERT_DEVICE_ERROR(encoder.Finish());
175 }
176
177 {
178 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000179 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
Brandon Jonesccda6a02020-09-01 18:32:49 +0000180 encoder.SetPipeline(pipeline16);
181 encoder.DrawIndexed(3);
182 ASSERT_DEVICE_ERROR(encoder.Finish());
183 }
184
185 // Expected to succeed because pipeline and index formats match.
186 {
187 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000188 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
Brandon Jonesccda6a02020-09-01 18:32:49 +0000189 encoder.SetPipeline(pipeline16);
190 encoder.DrawIndexed(3);
191 encoder.Finish();
192 }
193
194 {
195 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
Corentin Wallez5fad85b2020-11-25 08:54:14 +0000196 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
Brandon Jonesccda6a02020-09-01 18:32:49 +0000197 encoder.SetPipeline(pipeline32);
198 encoder.DrawIndexed(3);
199 encoder.Finish();
200 }
Brandon Jones370e6bd2021-12-08 17:24:37 +0000201
202 // Expected to fail because pipeline doesn't specify an index format.
203 {
204 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
205 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
206 encoder.SetPipeline(pipelineUndef);
207 encoder.DrawIndexed(3);
208 ASSERT_DEVICE_ERROR(encoder.Finish());
209 }
210
211 {
212 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
213 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
214 encoder.SetPipeline(pipelineUndef);
215 encoder.DrawIndexed(3);
216 ASSERT_DEVICE_ERROR(encoder.Finish());
217 }
218
219 // Expected to succeed because non-indexed draw calls don't require a pipeline index format.
220 {
221 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
222 encoder.SetPipeline(pipelineUndef);
223 encoder.Draw(3);
224 encoder.Finish();
225 }
Brandon Jonesccda6a02020-09-01 18:32:49 +0000226}
Corentin Wallez310d86f2021-01-22 09:57:38 +0000227
228// Check that the index buffer must have the Index usage.
229TEST_F(IndexBufferValidationTest, InvalidUsage) {
230 wgpu::Buffer indexBuffer =
231 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index, {0, 1, 2});
232 wgpu::Buffer copyBuffer =
233 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::CopySrc, {0, 1, 2});
234
235 DummyRenderPass renderPass(device);
236 // Control case: using the index buffer is valid.
237 {
238 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
239 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
240 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
241 pass.EndPass();
242 encoder.Finish();
243 }
244 // Error case: using the copy buffer is an error.
245 {
246 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
247 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
248 pass.SetIndexBuffer(copyBuffer, wgpu::IndexFormat::Uint32);
249 pass.EndPass();
250 ASSERT_DEVICE_ERROR(encoder.Finish());
251 }
252
253 utils::ComboRenderBundleEncoderDescriptor renderBundleDesc = {};
254 renderBundleDesc.colorFormatsCount = 1;
255 renderBundleDesc.cColorFormats[0] = wgpu::TextureFormat::RGBA8Unorm;
256 // Control case: using the index buffer is valid.
257 {
258 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
259 encoder.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
260 encoder.Finish();
261 }
262 // Error case: using the copy buffer is an error.
263 {
264 wgpu::RenderBundleEncoder encoder = device.CreateRenderBundleEncoder(&renderBundleDesc);
265 encoder.SetIndexBuffer(copyBuffer, wgpu::IndexFormat::Uint32);
266 ASSERT_DEVICE_ERROR(encoder.Finish());
267 }
268}
Corentin Wallez95aa7c52021-06-17 17:48:45 +0000269
270// Check the alignment constraint on the index buffer offset.
271TEST_F(IndexBufferValidationTest, OffsetAlignment) {
272 wgpu::Buffer indexBuffer =
273 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index, {0, 1, 2});
274
275 DummyRenderPass renderPass(device);
276 // Control cases: index buffer offset is a multiple of the index format size
277 {
278 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
279 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
280 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 0);
281 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 4);
282 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 0);
283 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 2);
284 pass.EndPass();
285 encoder.Finish();
286 }
287
288 // Error case: index buffer offset isn't a multiple of 4 for IndexFormat::Uint32
289 {
290 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
291 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
292 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 2);
293 pass.EndPass();
294 ASSERT_DEVICE_ERROR(encoder.Finish());
295 }
296 // Error case: index buffer offset isn't a multiple of 2 for IndexFormat::Uint16
297 {
298 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
299 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
300 pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 1);
301 pass.EndPass();
302 ASSERT_DEVICE_ERROR(encoder.Finish());
303 }
304}