• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/unittests/wire/WireTest.h"
16 
17 #include "common/Constants.h"
18 
19 #include <array>
20 
21 using namespace testing;
22 using namespace dawn_wire;
23 
24 class WireArgumentTests : public WireTest {
25   public:
WireArgumentTests()26     WireArgumentTests() {
27     }
28     ~WireArgumentTests() override = default;
29 };
30 
31 // Test that the wire is able to send numerical values
TEST_F(WireArgumentTests,ValueArgument)32 TEST_F(WireArgumentTests, ValueArgument) {
33     WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
34     WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr);
35     wgpuComputePassEncoderDispatch(pass, 1, 2, 3);
36 
37     WGPUCommandEncoder apiEncoder = api.GetNewCommandEncoder();
38     EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr)).WillOnce(Return(apiEncoder));
39 
40     WGPUComputePassEncoder apiPass = api.GetNewComputePassEncoder();
41     EXPECT_CALL(api, CommandEncoderBeginComputePass(apiEncoder, nullptr)).WillOnce(Return(apiPass));
42 
43     EXPECT_CALL(api, ComputePassEncoderDispatch(apiPass, 1, 2, 3)).Times(1);
44 
45     FlushClient();
46 }
47 
48 // Test that the wire is able to send arrays of numerical values
TEST_F(WireArgumentTests,ValueArrayArgument)49 TEST_F(WireArgumentTests, ValueArrayArgument) {
50     // Create a bindgroup.
51     WGPUBindGroupLayoutDescriptor bglDescriptor = {};
52     bglDescriptor.entryCount = 0;
53     bglDescriptor.entries = nullptr;
54 
55     WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device, &bglDescriptor);
56     WGPUBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
57     EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
58 
59     WGPUBindGroupDescriptor bindGroupDescriptor = {};
60     bindGroupDescriptor.layout = bgl;
61     bindGroupDescriptor.entryCount = 0;
62     bindGroupDescriptor.entries = nullptr;
63 
64     WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescriptor);
65     WGPUBindGroup apiBindGroup = api.GetNewBindGroup();
66     EXPECT_CALL(api, DeviceCreateBindGroup(apiDevice, _)).WillOnce(Return(apiBindGroup));
67 
68     // Use the bindgroup in SetBindGroup that takes an array of value offsets.
69     WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
70     WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr);
71 
72     std::array<uint32_t, 4> testOffsets = {0, 42, 0xDEAD'BEEFu, 0xFFFF'FFFFu};
73     wgpuComputePassEncoderSetBindGroup(pass, 0, bindGroup, testOffsets.size(), testOffsets.data());
74 
75     WGPUCommandEncoder apiEncoder = api.GetNewCommandEncoder();
76     EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr)).WillOnce(Return(apiEncoder));
77 
78     WGPUComputePassEncoder apiPass = api.GetNewComputePassEncoder();
79     EXPECT_CALL(api, CommandEncoderBeginComputePass(apiEncoder, nullptr)).WillOnce(Return(apiPass));
80 
81     EXPECT_CALL(api, ComputePassEncoderSetBindGroup(
82                          apiPass, 0, apiBindGroup, testOffsets.size(),
83                          MatchesLambda([testOffsets](const uint32_t* offsets) -> bool {
84                              for (size_t i = 0; i < testOffsets.size(); i++) {
85                                  if (offsets[i] != testOffsets[i]) {
86                                      return false;
87                                  }
88                              }
89                              return true;
90                          })));
91 
92     FlushClient();
93 }
94 
95 // Test that the wire is able to send C strings
TEST_F(WireArgumentTests,CStringArgument)96 TEST_F(WireArgumentTests, CStringArgument) {
97     // Create shader module
98     WGPUShaderModuleDescriptor vertexDescriptor = {};
99     WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
100     WGPUShaderModule apiVsModule = api.GetNewShaderModule();
101     EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule));
102 
103     // Create the color state descriptor
104     WGPUBlendComponent blendComponent = {};
105     blendComponent.operation = WGPUBlendOperation_Add;
106     blendComponent.srcFactor = WGPUBlendFactor_One;
107     blendComponent.dstFactor = WGPUBlendFactor_One;
108     WGPUBlendState blendState = {};
109     blendState.alpha = blendComponent;
110     blendState.color = blendComponent;
111     WGPUColorTargetState colorTargetState = {};
112     colorTargetState.format = WGPUTextureFormat_RGBA8Unorm;
113     colorTargetState.blend = &blendState;
114     colorTargetState.writeMask = WGPUColorWriteMask_All;
115 
116     // Create the depth-stencil state
117     WGPUStencilFaceState stencilFace = {};
118     stencilFace.compare = WGPUCompareFunction_Always;
119     stencilFace.failOp = WGPUStencilOperation_Keep;
120     stencilFace.depthFailOp = WGPUStencilOperation_Keep;
121     stencilFace.passOp = WGPUStencilOperation_Keep;
122 
123     WGPUDepthStencilState depthStencilState = {};
124     depthStencilState.format = WGPUTextureFormat_Depth24PlusStencil8;
125     depthStencilState.depthWriteEnabled = false;
126     depthStencilState.depthCompare = WGPUCompareFunction_Always;
127     depthStencilState.stencilBack = stencilFace;
128     depthStencilState.stencilFront = stencilFace;
129     depthStencilState.stencilReadMask = 0xff;
130     depthStencilState.stencilWriteMask = 0xff;
131     depthStencilState.depthBias = 0;
132     depthStencilState.depthBiasSlopeScale = 0.0;
133     depthStencilState.depthBiasClamp = 0.0;
134 
135     // Create the pipeline layout
136     WGPUPipelineLayoutDescriptor layoutDescriptor = {};
137     layoutDescriptor.bindGroupLayoutCount = 0;
138     layoutDescriptor.bindGroupLayouts = nullptr;
139     WGPUPipelineLayout layout = wgpuDeviceCreatePipelineLayout(device, &layoutDescriptor);
140     WGPUPipelineLayout apiLayout = api.GetNewPipelineLayout();
141     EXPECT_CALL(api, DeviceCreatePipelineLayout(apiDevice, _)).WillOnce(Return(apiLayout));
142 
143     // Create pipeline
144     WGPURenderPipelineDescriptor pipelineDescriptor = {};
145 
146     pipelineDescriptor.vertex.module = vsModule;
147     pipelineDescriptor.vertex.entryPoint = "main";
148     pipelineDescriptor.vertex.bufferCount = 0;
149     pipelineDescriptor.vertex.buffers = nullptr;
150 
151     WGPUFragmentState fragment = {};
152     fragment.module = vsModule;
153     fragment.entryPoint = "main";
154     fragment.targetCount = 1;
155     fragment.targets = &colorTargetState;
156     pipelineDescriptor.fragment = &fragment;
157 
158     pipelineDescriptor.multisample.count = 1;
159     pipelineDescriptor.multisample.mask = 0xFFFFFFFF;
160     pipelineDescriptor.multisample.alphaToCoverageEnabled = false;
161     pipelineDescriptor.layout = layout;
162     pipelineDescriptor.primitive.topology = WGPUPrimitiveTopology_TriangleList;
163     pipelineDescriptor.primitive.frontFace = WGPUFrontFace_CCW;
164     pipelineDescriptor.primitive.cullMode = WGPUCullMode_None;
165     pipelineDescriptor.depthStencil = &depthStencilState;
166 
167     wgpuDeviceCreateRenderPipeline(device, &pipelineDescriptor);
168 
169     WGPURenderPipeline apiDummyPipeline = api.GetNewRenderPipeline();
170     EXPECT_CALL(api,
171                 DeviceCreateRenderPipeline(
172                     apiDevice, MatchesLambda([](const WGPURenderPipelineDescriptor* desc) -> bool {
173                         return desc->vertex.entryPoint == std::string("main");
174                     })))
175         .WillOnce(Return(apiDummyPipeline));
176 
177     FlushClient();
178 }
179 
180 // Test that the wire is able to send objects as value arguments
TEST_F(WireArgumentTests,ObjectAsValueArgument)181 TEST_F(WireArgumentTests, ObjectAsValueArgument) {
182     WGPUCommandEncoder cmdBufEncoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
183     WGPUCommandEncoder apiEncoder = api.GetNewCommandEncoder();
184     EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr)).WillOnce(Return(apiEncoder));
185 
186     WGPUBufferDescriptor descriptor = {};
187     descriptor.size = 8;
188     descriptor.usage =
189         static_cast<WGPUBufferUsage>(WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst);
190 
191     WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
192     WGPUBuffer apiBuffer = api.GetNewBuffer();
193     EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _))
194         .WillOnce(Return(apiBuffer))
195         .RetiresOnSaturation();
196 
197     wgpuCommandEncoderCopyBufferToBuffer(cmdBufEncoder, buffer, 0, buffer, 4, 4);
198     EXPECT_CALL(api, CommandEncoderCopyBufferToBuffer(apiEncoder, apiBuffer, 0, apiBuffer, 4, 4));
199 
200     FlushClient();
201 }
202 
203 // Test that the wire is able to send array of objects
TEST_F(WireArgumentTests,ObjectsAsPointerArgument)204 TEST_F(WireArgumentTests, ObjectsAsPointerArgument) {
205     WGPUCommandBuffer cmdBufs[2];
206     WGPUCommandBuffer apiCmdBufs[2];
207 
208     // Create two command buffers we need to use a GMock sequence otherwise the order of the
209     // CreateCommandEncoder might be swapped since they are equivalent in term of matchers
210     Sequence s;
211     for (int i = 0; i < 2; ++i) {
212         WGPUCommandEncoder cmdBufEncoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
213         cmdBufs[i] = wgpuCommandEncoderFinish(cmdBufEncoder, nullptr);
214 
215         WGPUCommandEncoder apiCmdBufEncoder = api.GetNewCommandEncoder();
216         EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr))
217             .InSequence(s)
218             .WillOnce(Return(apiCmdBufEncoder));
219 
220         apiCmdBufs[i] = api.GetNewCommandBuffer();
221         EXPECT_CALL(api, CommandEncoderFinish(apiCmdBufEncoder, nullptr))
222             .WillOnce(Return(apiCmdBufs[i]));
223     }
224 
225     // Submit command buffer and check we got a call with both API-side command buffers
226     wgpuQueueSubmit(queue, 2, cmdBufs);
227 
228     EXPECT_CALL(
229         api, QueueSubmit(apiQueue, 2, MatchesLambda([=](const WGPUCommandBuffer* cmdBufs) -> bool {
230                              return cmdBufs[0] == apiCmdBufs[0] && cmdBufs[1] == apiCmdBufs[1];
231                          })));
232 
233     FlushClient();
234 }
235 
236 // Test that the wire is able to send structures that contain pure values (non-objects)
TEST_F(WireArgumentTests,StructureOfValuesArgument)237 TEST_F(WireArgumentTests, StructureOfValuesArgument) {
238     WGPUSamplerDescriptor descriptor = {};
239     descriptor.magFilter = WGPUFilterMode_Linear;
240     descriptor.minFilter = WGPUFilterMode_Nearest;
241     descriptor.mipmapFilter = WGPUFilterMode_Linear;
242     descriptor.addressModeU = WGPUAddressMode_ClampToEdge;
243     descriptor.addressModeV = WGPUAddressMode_Repeat;
244     descriptor.addressModeW = WGPUAddressMode_MirrorRepeat;
245     descriptor.lodMinClamp = kLodMin;
246     descriptor.lodMaxClamp = kLodMax;
247     descriptor.compare = WGPUCompareFunction_Never;
248 
249     wgpuDeviceCreateSampler(device, &descriptor);
250 
251     WGPUSampler apiDummySampler = api.GetNewSampler();
252     EXPECT_CALL(api, DeviceCreateSampler(
253                          apiDevice, MatchesLambda([](const WGPUSamplerDescriptor* desc) -> bool {
254                              return desc->nextInChain == nullptr &&
255                                     desc->magFilter == WGPUFilterMode_Linear &&
256                                     desc->minFilter == WGPUFilterMode_Nearest &&
257                                     desc->mipmapFilter == WGPUFilterMode_Linear &&
258                                     desc->addressModeU == WGPUAddressMode_ClampToEdge &&
259                                     desc->addressModeV == WGPUAddressMode_Repeat &&
260                                     desc->addressModeW == WGPUAddressMode_MirrorRepeat &&
261                                     desc->compare == WGPUCompareFunction_Never &&
262                                     desc->lodMinClamp == kLodMin && desc->lodMaxClamp == kLodMax;
263                          })))
264         .WillOnce(Return(apiDummySampler));
265 
266     FlushClient();
267 }
268 
269 // Test that the wire is able to send structures that contain objects
TEST_F(WireArgumentTests,StructureOfObjectArrayArgument)270 TEST_F(WireArgumentTests, StructureOfObjectArrayArgument) {
271     WGPUBindGroupLayoutDescriptor bglDescriptor = {};
272     bglDescriptor.entryCount = 0;
273     bglDescriptor.entries = nullptr;
274 
275     WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device, &bglDescriptor);
276     WGPUBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
277     EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
278 
279     WGPUPipelineLayoutDescriptor descriptor = {};
280     descriptor.bindGroupLayoutCount = 1;
281     descriptor.bindGroupLayouts = &bgl;
282 
283     wgpuDeviceCreatePipelineLayout(device, &descriptor);
284 
285     WGPUPipelineLayout apiDummyLayout = api.GetNewPipelineLayout();
286     EXPECT_CALL(api, DeviceCreatePipelineLayout(
287                          apiDevice,
288                          MatchesLambda([apiBgl](const WGPUPipelineLayoutDescriptor* desc) -> bool {
289                              return desc->nextInChain == nullptr &&
290                                     desc->bindGroupLayoutCount == 1 &&
291                                     desc->bindGroupLayouts[0] == apiBgl;
292                          })))
293         .WillOnce(Return(apiDummyLayout));
294 
295     FlushClient();
296 }
297 
298 // Test that the wire is able to send structures that contain objects
TEST_F(WireArgumentTests,StructureOfStructureArrayArgument)299 TEST_F(WireArgumentTests, StructureOfStructureArrayArgument) {
300     static constexpr int NUM_BINDINGS = 3;
301     WGPUBindGroupLayoutEntry entries[NUM_BINDINGS]{
302         {nullptr,
303          0,
304          WGPUShaderStage_Vertex,
305          {},
306          {nullptr, WGPUSamplerBindingType_Filtering},
307          {},
308          {}},
309         {nullptr,
310          1,
311          WGPUShaderStage_Vertex,
312          {},
313          {},
314          {nullptr, WGPUTextureSampleType_Float, WGPUTextureViewDimension_2D, false},
315          {}},
316         {nullptr,
317          2,
318          static_cast<WGPUShaderStage>(WGPUShaderStage_Vertex | WGPUShaderStage_Fragment),
319          {nullptr, WGPUBufferBindingType_Uniform, false, 0},
320          {},
321          {},
322          {}},
323     };
324     WGPUBindGroupLayoutDescriptor bglDescriptor = {};
325     bglDescriptor.entryCount = NUM_BINDINGS;
326     bglDescriptor.entries = entries;
327 
328     wgpuDeviceCreateBindGroupLayout(device, &bglDescriptor);
329     WGPUBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
330     EXPECT_CALL(
331         api,
332         DeviceCreateBindGroupLayout(
333             apiDevice, MatchesLambda([entries](const WGPUBindGroupLayoutDescriptor* desc) -> bool {
334                 for (int i = 0; i < NUM_BINDINGS; ++i) {
335                     const auto& a = desc->entries[i];
336                     const auto& b = entries[i];
337                     if (a.binding != b.binding || a.visibility != b.visibility ||
338                         a.buffer.type != b.buffer.type || a.sampler.type != b.sampler.type ||
339                         a.texture.sampleType != b.texture.sampleType) {
340                         return false;
341                     }
342                 }
343                 return desc->nextInChain == nullptr && desc->entryCount == 3;
344             })))
345         .WillOnce(Return(apiBgl));
346 
347     FlushClient();
348 }
349 
350 // Test passing nullptr instead of objects - array of objects version
TEST_F(WireArgumentTests,DISABLED_NullptrInArray)351 TEST_F(WireArgumentTests, DISABLED_NullptrInArray) {
352     WGPUBindGroupLayout nullBGL = nullptr;
353 
354     WGPUPipelineLayoutDescriptor descriptor = {};
355     descriptor.bindGroupLayoutCount = 1;
356     descriptor.bindGroupLayouts = &nullBGL;
357 
358     wgpuDeviceCreatePipelineLayout(device, &descriptor);
359     EXPECT_CALL(api,
360                 DeviceCreatePipelineLayout(
361                     apiDevice, MatchesLambda([](const WGPUPipelineLayoutDescriptor* desc) -> bool {
362                         return desc->nextInChain == nullptr && desc->bindGroupLayoutCount == 1 &&
363                                desc->bindGroupLayouts[0] == nullptr;
364                     })))
365         .WillOnce(Return(nullptr));
366 
367     FlushClient();
368 }
369