1 // 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/wire/WireTest.h"
16
17 using namespace testing;
18 using namespace dawn_wire;
19
20 class WireExtensionTests : public WireTest {
21 public:
WireExtensionTests()22 WireExtensionTests() {
23 }
24 ~WireExtensionTests() override = default;
25 };
26
27 // Serialize/Deserializes a chained struct correctly.
TEST_F(WireExtensionTests,ChainedStruct)28 TEST_F(WireExtensionTests, ChainedStruct) {
29 WGPUShaderModuleDescriptor shaderModuleDesc = {};
30 WGPUShaderModule apiShaderModule = api.GetNewShaderModule();
31 WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
32 EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiShaderModule));
33 FlushClient();
34
35 WGPUPrimitiveDepthClampingState clientExt = {};
36 clientExt.chain.sType = WGPUSType_PrimitiveDepthClampingState;
37 clientExt.chain.next = nullptr;
38 clientExt.clampDepth = true;
39
40 WGPURenderPipelineDescriptor renderPipelineDesc = {};
41 renderPipelineDesc.vertex.module = shaderModule;
42 renderPipelineDesc.vertex.entryPoint = "main";
43 renderPipelineDesc.primitive.nextInChain = &clientExt.chain;
44
45 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
46 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
47 .WillOnce(Invoke([&](Unused,
48 const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
49 const auto* ext = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
50 serverDesc->primitive.nextInChain);
51 EXPECT_EQ(ext->chain.sType, clientExt.chain.sType);
52 EXPECT_EQ(ext->clampDepth, true);
53 EXPECT_EQ(ext->chain.next, nullptr);
54
55 return api.GetNewRenderPipeline();
56 }));
57 FlushClient();
58 }
59
60 // Serialize/Deserializes multiple chained structs correctly.
TEST_F(WireExtensionTests,MutlipleChainedStructs)61 TEST_F(WireExtensionTests, MutlipleChainedStructs) {
62 WGPUShaderModuleDescriptor shaderModuleDesc = {};
63 WGPUShaderModule apiShaderModule = api.GetNewShaderModule();
64 WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
65 EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiShaderModule));
66 FlushClient();
67
68 WGPUPrimitiveDepthClampingState clientExt2 = {};
69 clientExt2.chain.sType = WGPUSType_PrimitiveDepthClampingState;
70 clientExt2.chain.next = nullptr;
71 clientExt2.clampDepth = false;
72
73 WGPUPrimitiveDepthClampingState clientExt1 = {};
74 clientExt1.chain.sType = WGPUSType_PrimitiveDepthClampingState;
75 clientExt1.chain.next = &clientExt2.chain;
76 clientExt1.clampDepth = true;
77
78 WGPURenderPipelineDescriptor renderPipelineDesc = {};
79 renderPipelineDesc.vertex.module = shaderModule;
80 renderPipelineDesc.vertex.entryPoint = "main";
81 renderPipelineDesc.primitive.nextInChain = &clientExt1.chain;
82
83 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
84 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
85 .WillOnce(Invoke([&](Unused,
86 const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
87 const auto* ext1 = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
88 serverDesc->primitive.nextInChain);
89 EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType);
90 EXPECT_EQ(ext1->clampDepth, true);
91
92 const auto* ext2 = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
93 ext1->chain.next);
94 EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType);
95 EXPECT_EQ(ext2->clampDepth, false);
96 EXPECT_EQ(ext2->chain.next, nullptr);
97
98 return api.GetNewRenderPipeline();
99 }));
100 FlushClient();
101
102 // Swap the order of the chained structs.
103 renderPipelineDesc.primitive.nextInChain = &clientExt2.chain;
104 clientExt2.chain.next = &clientExt1.chain;
105 clientExt1.chain.next = nullptr;
106
107 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
108 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
109 .WillOnce(Invoke([&](Unused,
110 const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
111 const auto* ext2 = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
112 serverDesc->primitive.nextInChain);
113 EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType);
114 EXPECT_EQ(ext2->clampDepth, false);
115
116 const auto* ext1 = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
117 ext2->chain.next);
118 EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType);
119 EXPECT_EQ(ext1->clampDepth, true);
120 EXPECT_EQ(ext1->chain.next, nullptr);
121
122 return api.GetNewRenderPipeline();
123 }));
124 FlushClient();
125 }
126
127 // Test that a chained struct with Invalid sType passes through as Invalid.
TEST_F(WireExtensionTests,InvalidSType)128 TEST_F(WireExtensionTests, InvalidSType) {
129 WGPUShaderModuleDescriptor shaderModuleDesc = {};
130 WGPUShaderModule apiShaderModule = api.GetNewShaderModule();
131 WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
132 EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiShaderModule));
133 FlushClient();
134
135 WGPUPrimitiveDepthClampingState clientExt = {};
136 clientExt.chain.sType = WGPUSType_Invalid;
137 clientExt.chain.next = nullptr;
138
139 WGPURenderPipelineDescriptor renderPipelineDesc = {};
140 renderPipelineDesc.vertex.module = shaderModule;
141 renderPipelineDesc.vertex.entryPoint = "main";
142 renderPipelineDesc.primitive.nextInChain = &clientExt.chain;
143
144 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
145 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
146 .WillOnce(Invoke(
147 [&](Unused, const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
148 EXPECT_EQ(serverDesc->primitive.nextInChain->sType, WGPUSType_Invalid);
149 EXPECT_EQ(serverDesc->primitive.nextInChain->next, nullptr);
150 return api.GetNewRenderPipeline();
151 }));
152 FlushClient();
153 }
154
155 // Test that a chained struct with unknown sType passes through as Invalid.
TEST_F(WireExtensionTests,UnknownSType)156 TEST_F(WireExtensionTests, UnknownSType) {
157 WGPUShaderModuleDescriptor shaderModuleDesc = {};
158 WGPUShaderModule apiShaderModule = api.GetNewShaderModule();
159 WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
160 EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiShaderModule));
161 FlushClient();
162
163 WGPUPrimitiveDepthClampingState clientExt = {};
164 clientExt.chain.sType = static_cast<WGPUSType>(-1);
165 clientExt.chain.next = nullptr;
166
167 WGPURenderPipelineDescriptor renderPipelineDesc = {};
168 renderPipelineDesc.vertex.module = shaderModule;
169 renderPipelineDesc.vertex.entryPoint = "main";
170 renderPipelineDesc.primitive.nextInChain = &clientExt.chain;
171
172 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
173 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
174 .WillOnce(Invoke(
175 [&](Unused, const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
176 EXPECT_EQ(serverDesc->primitive.nextInChain->sType, WGPUSType_Invalid);
177 EXPECT_EQ(serverDesc->primitive.nextInChain->next, nullptr);
178 return api.GetNewRenderPipeline();
179 }));
180 FlushClient();
181 }
182
183 // Test that if both an invalid and valid stype are passed on the chain, only the invalid
184 // sType passes through as Invalid.
TEST_F(WireExtensionTests,ValidAndInvalidSTypeInChain)185 TEST_F(WireExtensionTests, ValidAndInvalidSTypeInChain) {
186 WGPUShaderModuleDescriptor shaderModuleDesc = {};
187 WGPUShaderModule apiShaderModule = api.GetNewShaderModule();
188 WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
189 EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiShaderModule));
190 FlushClient();
191
192 WGPUPrimitiveDepthClampingState clientExt2 = {};
193 clientExt2.chain.sType = WGPUSType_Invalid;
194 clientExt2.chain.next = nullptr;
195
196 WGPUPrimitiveDepthClampingState clientExt1 = {};
197 clientExt1.chain.sType = WGPUSType_PrimitiveDepthClampingState;
198 clientExt1.chain.next = &clientExt2.chain;
199 clientExt1.clampDepth = true;
200
201 WGPURenderPipelineDescriptor renderPipelineDesc = {};
202 renderPipelineDesc.vertex.module = shaderModule;
203 renderPipelineDesc.vertex.entryPoint = "main";
204 renderPipelineDesc.primitive.nextInChain = &clientExt1.chain;
205
206 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
207 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
208 .WillOnce(Invoke([&](Unused,
209 const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
210 const auto* ext = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
211 serverDesc->primitive.nextInChain);
212 EXPECT_EQ(ext->chain.sType, clientExt1.chain.sType);
213 EXPECT_EQ(ext->clampDepth, true);
214
215 EXPECT_EQ(ext->chain.next->sType, WGPUSType_Invalid);
216 EXPECT_EQ(ext->chain.next->next, nullptr);
217 return api.GetNewRenderPipeline();
218 }));
219 FlushClient();
220
221 // Swap the order of the chained structs.
222 renderPipelineDesc.primitive.nextInChain = &clientExt2.chain;
223 clientExt2.chain.next = &clientExt1.chain;
224 clientExt1.chain.next = nullptr;
225
226 wgpuDeviceCreateRenderPipeline(device, &renderPipelineDesc);
227 EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, NotNull()))
228 .WillOnce(Invoke([&](Unused,
229 const WGPURenderPipelineDescriptor* serverDesc) -> WGPURenderPipeline {
230 EXPECT_EQ(serverDesc->primitive.nextInChain->sType, WGPUSType_Invalid);
231
232 const auto* ext = reinterpret_cast<const WGPUPrimitiveDepthClampingState*>(
233 serverDesc->primitive.nextInChain->next);
234 EXPECT_EQ(ext->chain.sType, clientExt1.chain.sType);
235 EXPECT_EQ(ext->clampDepth, true);
236 EXPECT_EQ(ext->chain.next, nullptr);
237
238 return api.GetNewRenderPipeline();
239 }));
240 FlushClient();
241 }
242