1 // Copyright 2019 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/DawnTest.h"
16
17 #include "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19
20 constexpr uint32_t kRTSize = 4;
21
22 class DrawIndirectTest : public DawnTest {
23 protected:
SetUp()24 void SetUp() override {
25 DawnTest::SetUp();
26
27 renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
28
29 wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
30 [[stage(vertex)]]
31 fn main([[location(0)]] pos : vec4<f32>) -> [[builtin(position)]] vec4<f32> {
32 return pos;
33 })");
34
35 wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
36 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
37 return vec4<f32>(0.0, 1.0, 0.0, 1.0);
38 })");
39
40 utils::ComboRenderPipelineDescriptor descriptor;
41 descriptor.vertex.module = vsModule;
42 descriptor.cFragment.module = fsModule;
43 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleStrip;
44 descriptor.primitive.stripIndexFormat = wgpu::IndexFormat::Uint32;
45 descriptor.vertex.bufferCount = 1;
46 descriptor.cBuffers[0].arrayStride = 4 * sizeof(float);
47 descriptor.cBuffers[0].attributeCount = 1;
48 descriptor.cAttributes[0].format = wgpu::VertexFormat::Float32x4;
49 descriptor.cTargets[0].format = renderPass.colorFormat;
50
51 pipeline = device.CreateRenderPipeline(&descriptor);
52
53 vertexBuffer = utils::CreateBufferFromData<float>(
54 device, wgpu::BufferUsage::Vertex,
55 {// The bottom left triangle
56 -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
57
58 // The top right triangle
59 -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f});
60 }
61
62 utils::BasicRenderPass renderPass;
63 wgpu::RenderPipeline pipeline;
64 wgpu::Buffer vertexBuffer;
65
Test(std::initializer_list<uint32_t> bufferList,uint64_t indirectOffset,RGBA8 bottomLeftExpected,RGBA8 topRightExpected)66 void Test(std::initializer_list<uint32_t> bufferList,
67 uint64_t indirectOffset,
68 RGBA8 bottomLeftExpected,
69 RGBA8 topRightExpected) {
70 wgpu::Buffer indirectBuffer =
71 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Indirect, bufferList);
72
73 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
74 {
75 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
76 pass.SetPipeline(pipeline);
77 pass.SetVertexBuffer(0, vertexBuffer);
78 pass.DrawIndirect(indirectBuffer, indirectOffset);
79 pass.EndPass();
80 }
81
82 wgpu::CommandBuffer commands = encoder.Finish();
83 queue.Submit(1, &commands);
84
85 EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderPass.color, 1, 3);
86 EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderPass.color, 3, 1);
87 }
88 };
89
90 // The basic triangle draw.
TEST_P(DrawIndirectTest,Uint32)91 TEST_P(DrawIndirectTest, Uint32) {
92 RGBA8 filled(0, 255, 0, 255);
93 RGBA8 notFilled(0, 0, 0, 0);
94
95 // Test a draw with no indices.
96 Test({0, 0, 0, 0}, 0, notFilled, notFilled);
97
98 // Test a draw with only the first 3 indices (bottom left triangle)
99 Test({3, 1, 0, 0}, 0, filled, notFilled);
100
101 // Test a draw with only the last 3 indices (top right triangle)
102 Test({3, 1, 3, 0}, 0, notFilled, filled);
103
104 // Test a draw with all 6 indices (both triangles).
105 Test({6, 1, 0, 0}, 0, filled, filled);
106 }
107
TEST_P(DrawIndirectTest,IndirectOffset)108 TEST_P(DrawIndirectTest, IndirectOffset) {
109 RGBA8 filled(0, 255, 0, 255);
110 RGBA8 notFilled(0, 0, 0, 0);
111
112 // Test an offset draw call, with indirect buffer containing 2 calls:
113 // 1) only the first 3 indices (bottom left triangle)
114 // 2) only the last 3 indices (top right triangle)
115
116 // Test #1 (no offset)
117 Test({3, 1, 0, 0, 3, 1, 3, 0}, 0, filled, notFilled);
118
119 // Offset to draw #2
120 Test({3, 1, 0, 0, 3, 1, 3, 0}, 4 * sizeof(uint32_t), notFilled, filled);
121 }
122
123 DAWN_INSTANTIATE_TEST(DrawIndirectTest,
124 D3D12Backend(),
125 MetalBackend(),
126 OpenGLBackend(),
127 OpenGLESBackend(),
128 VulkanBackend());
129