1 // Copyright 2017 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 #ifndef TESTS_DAWNTEST_H_
16 #define TESTS_DAWNTEST_H_
17
18 #include "common/Log.h"
19 #include "common/Platform.h"
20 #include "common/Preprocessor.h"
21 #include "dawn/dawn_proc_table.h"
22 #include "dawn/webgpu_cpp.h"
23 #include "dawn/webgpu_cpp_print.h"
24 #include "dawn_native/DawnNative.h"
25 #include "tests/ParamGenerator.h"
26 #include "tests/ToggleParser.h"
27 #include "utils/ScopedAutoreleasePool.h"
28
29 #include <dawn_platform/DawnPlatform.h>
30 #include <gmock/gmock.h>
31 #include <gtest/gtest.h>
32
33 #include <memory>
34 #include <unordered_map>
35 #include <vector>
36
37 // Getting data back from Dawn is done in an async manners so all expectations are "deferred"
38 // until the end of the test. Also expectations use a copy to a MapRead buffer to get the data
39 // so resources should have the CopySrc allowed usage bit if you want to add expectations on
40 // them.
41
42 // AddBufferExpectation is defined in DawnTestBase as protected function. This ensures the macro can
43 // only be used in derivd class of DawnTestBase. Use "this" pointer to ensure the macro works with
44 // CRTP.
45 #define EXPECT_BUFFER(buffer, offset, size, expectation) \
46 this->AddBufferExpectation(__FILE__, __LINE__, buffer, offset, size, expectation)
47
48 #define EXPECT_BUFFER_U8_EQ(expected, buffer, offset) \
49 EXPECT_BUFFER(buffer, offset, sizeof(uint8_t), new ::detail::ExpectEq<uint8_t>(expected))
50
51 #define EXPECT_BUFFER_U8_RANGE_EQ(expected, buffer, offset, count) \
52 EXPECT_BUFFER(buffer, offset, sizeof(uint8_t) * (count), \
53 new ::detail::ExpectEq<uint8_t>(expected, count))
54
55 #define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) \
56 EXPECT_BUFFER(buffer, offset, sizeof(uint16_t), new ::detail::ExpectEq<uint16_t>(expected))
57
58 #define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) \
59 EXPECT_BUFFER(buffer, offset, sizeof(uint16_t) * (count), \
60 new ::detail::ExpectEq<uint16_t>(expected, count))
61
62 #define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \
63 EXPECT_BUFFER(buffer, offset, sizeof(uint32_t), new ::detail::ExpectEq<uint32_t>(expected))
64
65 #define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \
66 EXPECT_BUFFER(buffer, offset, sizeof(uint32_t) * (count), \
67 new ::detail::ExpectEq<uint32_t>(expected, count))
68
69 #define EXPECT_BUFFER_U64_EQ(expected, buffer, offset) \
70 EXPECT_BUFFER(buffer, offset, sizeof(uint64_t), new ::detail::ExpectEq<uint64_t>(expected))
71
72 #define EXPECT_BUFFER_U64_RANGE_EQ(expected, buffer, offset, count) \
73 EXPECT_BUFFER(buffer, offset, sizeof(uint64_t) * (count), \
74 new ::detail::ExpectEq<uint64_t>(expected, count))
75
76 #define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) \
77 EXPECT_BUFFER(buffer, offset, sizeof(float), new ::detail::ExpectEq<float>(expected))
78
79 #define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) \
80 EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
81 new ::detail::ExpectEq<float>(expected, count))
82
83 // Test a pixel of the mip level 0 of a 2D texture.
84 #define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
85 AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
86
87 #define EXPECT_PIXEL_FLOAT_EQ(expected, texture, x, y) \
88 AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
89
90 #define EXPECT_PIXEL_FLOAT16_EQ(expected, texture, x, y) \
91 AddTextureExpectation<float, uint16_t>(__FILE__, __LINE__, expected, texture, {x, y})
92
93 #define EXPECT_PIXEL_RGBA8_BETWEEN(color0, color1, texture, x, y) \
94 AddTextureBetweenColorsExpectation(__FILE__, __LINE__, color0, color1, texture, x, y)
95
96 #define EXPECT_TEXTURE_EQ(...) AddTextureExpectation(__FILE__, __LINE__, __VA_ARGS__)
97
98 #define ASSERT_DEVICE_ERROR_MSG(statement, matcher) \
99 StartExpectDeviceError(matcher); \
100 statement; \
101 FlushWire(); \
102 if (!EndExpectDeviceError()) { \
103 FAIL() << "Expected device error in:\n " << #statement; \
104 } \
105 do { \
106 } while (0)
107
108 #define ASSERT_DEVICE_ERROR(statement) ASSERT_DEVICE_ERROR_MSG(statement, testing::_)
109
110 struct RGBA8 {
RGBA8RGBA8111 constexpr RGBA8() : RGBA8(0, 0, 0, 0) {
112 }
RGBA8RGBA8113 constexpr RGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {
114 }
115 bool operator==(const RGBA8& other) const;
116 bool operator!=(const RGBA8& other) const;
117 bool operator<=(const RGBA8& other) const;
118 bool operator>=(const RGBA8& other) const;
119
120 uint8_t r, g, b, a;
121
122 static const RGBA8 kZero;
123 static const RGBA8 kBlack;
124 static const RGBA8 kRed;
125 static const RGBA8 kGreen;
126 static const RGBA8 kBlue;
127 static const RGBA8 kYellow;
128 static const RGBA8 kWhite;
129 };
130 std::ostream& operator<<(std::ostream& stream, const RGBA8& color);
131
132 struct BackendTestConfig {
133 BackendTestConfig(wgpu::BackendType backendType,
134 std::initializer_list<const char*> forceEnabledWorkarounds = {},
135 std::initializer_list<const char*> forceDisabledWorkarounds = {});
136
137 wgpu::BackendType backendType;
138
139 std::vector<const char*> forceEnabledWorkarounds;
140 std::vector<const char*> forceDisabledWorkarounds;
141 };
142
143 struct TestAdapterProperties : wgpu::AdapterProperties {
144 TestAdapterProperties(const wgpu::AdapterProperties& properties, bool selected);
145 std::string adapterName;
146 bool selected;
147
148 private:
149 // This may be temporary, so it is copied into |adapterName| and made private.
150 using wgpu::AdapterProperties::name;
151 };
152
153 struct AdapterTestParam {
154 AdapterTestParam(const BackendTestConfig& config,
155 const TestAdapterProperties& adapterProperties);
156
157 TestAdapterProperties adapterProperties;
158 std::vector<const char*> forceEnabledWorkarounds;
159 std::vector<const char*> forceDisabledWorkarounds;
160 };
161
162 std::ostream& operator<<(std::ostream& os, const AdapterTestParam& param);
163
164 BackendTestConfig D3D12Backend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
165 std::initializer_list<const char*> forceDisabledWorkarounds = {});
166
167 BackendTestConfig MetalBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
168 std::initializer_list<const char*> forceDisabledWorkarounds = {});
169
170 BackendTestConfig NullBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
171 std::initializer_list<const char*> forceDisabledWorkarounds = {});
172
173 BackendTestConfig OpenGLBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
174 std::initializer_list<const char*> forceDisabledWorkarounds = {});
175
176 BackendTestConfig OpenGLESBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
177 std::initializer_list<const char*> forceDisabledWorkarounds = {});
178
179 BackendTestConfig VulkanBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
180 std::initializer_list<const char*> forceDisabledWorkarounds = {});
181
182 struct GLFWwindow;
183
184 namespace utils {
185 class PlatformDebugLogger;
186 class TerribleCommandBuffer;
187 class WireHelper;
188 } // namespace utils
189
190 namespace detail {
191 class Expectation;
192 class CustomTextureExpectation;
193
194 template <typename T, typename U = T>
195 class ExpectEq;
196 template <typename T>
197 class ExpectBetweenColors;
198 } // namespace detail
199
200 namespace dawn_wire {
201 class CommandHandler;
202 class WireClient;
203 class WireServer;
204 } // namespace dawn_wire
205
206 void InitDawnEnd2EndTestEnvironment(int argc, char** argv);
207
208 class DawnTestEnvironment : public testing::Environment {
209 public:
210 DawnTestEnvironment(int argc, char** argv);
211 ~DawnTestEnvironment() override;
212
213 static void SetEnvironment(DawnTestEnvironment* env);
214
215 std::vector<AdapterTestParam> GetAvailableAdapterTestParamsForBackends(
216 const BackendTestConfig* params,
217 size_t numParams);
218
219 void SetUp() override;
220 void TearDown() override;
221
222 bool UsesWire() const;
223 dawn_native::BackendValidationLevel GetBackendValidationLevel() const;
224 dawn_native::Instance* GetInstance() const;
225 bool HasVendorIdFilter() const;
226 uint32_t GetVendorIdFilter() const;
227 bool HasBackendTypeFilter() const;
228 wgpu::BackendType GetBackendTypeFilter() const;
229 const char* GetWireTraceDir() const;
230 GLFWwindow* GetOpenGLWindow() const;
231 GLFWwindow* GetOpenGLESWindow() const;
232
233 const std::vector<std::string>& GetEnabledToggles() const;
234 const std::vector<std::string>& GetDisabledToggles() const;
235
236 bool RunSuppressedTests() const;
237
238 protected:
239 std::unique_ptr<dawn_native::Instance> mInstance;
240
241 private:
242 void ParseArgs(int argc, char** argv);
243 std::unique_ptr<dawn_native::Instance> CreateInstanceAndDiscoverAdapters();
244 void SelectPreferredAdapterProperties(const dawn_native::Instance* instance);
245 void PrintTestConfigurationAndAdapterInfo(dawn_native::Instance* instance) const;
246
247 bool mUseWire = false;
248 dawn_native::BackendValidationLevel mBackendValidationLevel =
249 dawn_native::BackendValidationLevel::Disabled;
250 bool mBeginCaptureOnStartup = false;
251 bool mHasVendorIdFilter = false;
252 uint32_t mVendorIdFilter = 0;
253 bool mHasBackendTypeFilter = false;
254 wgpu::BackendType mBackendTypeFilter;
255 std::string mWireTraceDir;
256 bool mRunSuppressedTests = false;
257
258 ToggleParser mToggleParser;
259
260 std::vector<dawn_native::DeviceType> mDevicePreferences;
261 std::vector<TestAdapterProperties> mAdapterProperties;
262
263 std::unique_ptr<utils::PlatformDebugLogger> mPlatformDebugLogger;
264 GLFWwindow* mOpenGLWindow;
265 GLFWwindow* mOpenGLESWindow;
266 };
267
268 class DawnTestBase {
269 friend class DawnPerfTestBase;
270
271 public:
272 DawnTestBase(const AdapterTestParam& param);
273 virtual ~DawnTestBase();
274
275 void SetUp();
276 void TearDown();
277
278 bool IsD3D12() const;
279 bool IsMetal() const;
280 bool IsNull() const;
281 bool IsOpenGL() const;
282 bool IsOpenGLES() const;
283 bool IsVulkan() const;
284
285 bool IsAMD() const;
286 bool IsARM() const;
287 bool IsImgTec() const;
288 bool IsIntel() const;
289 bool IsNvidia() const;
290 bool IsQualcomm() const;
291 bool IsSwiftshader() const;
292 bool IsANGLE() const;
293 bool IsWARP() const;
294
295 bool IsWindows() const;
296 bool IsLinux() const;
297 bool IsMacOS(int32_t majorVersion = -1, int32_t minorVersion = -1) const;
298
299 bool UsesWire() const;
300 bool IsBackendValidationEnabled() const;
301 bool RunSuppressedTests() const;
302
303 bool IsDXC() const;
304
305 bool IsAsan() const;
306
307 bool HasToggleEnabled(const char* workaround) const;
308
309 void StartExpectDeviceError(testing::Matcher<std::string> errorMatcher = testing::_);
310 bool EndExpectDeviceError();
311
312 void ExpectDeviceDestruction();
313
314 bool HasVendorIdFilter() const;
315 uint32_t GetVendorIdFilter() const;
316
317 bool HasBackendTypeFilter() const;
318 wgpu::BackendType GetBackendTypeFilter() const;
319
320 wgpu::Instance GetInstance() const;
321 dawn_native::Adapter GetAdapter() const;
322
323 virtual std::unique_ptr<dawn_platform::Platform> CreateTestPlatform();
324
325 struct PrintToStringParamName {
326 PrintToStringParamName(const char* test);
327 std::string SanitizeParamName(std::string paramName, size_t index) const;
328
329 template <class ParamType>
operatorPrintToStringParamName330 std::string operator()(const ::testing::TestParamInfo<ParamType>& info) const {
331 return SanitizeParamName(::testing::PrintToStringParamName()(info), info.index);
332 }
333
334 std::string mTest;
335 };
336
337 protected:
338 wgpu::Device device;
339 wgpu::Queue queue;
340
341 DawnProcTable backendProcs = {};
342 WGPUDevice backendDevice = nullptr;
343
344 size_t mLastWarningCount = 0;
345
346 // Helper methods to implement the EXPECT_ macros
347 std::ostringstream& AddBufferExpectation(const char* file,
348 int line,
349 const wgpu::Buffer& buffer,
350 uint64_t offset,
351 uint64_t size,
352 detail::Expectation* expectation);
353
354 // T - expected value Type
355 // U - actual value Type (defaults = T)
356 template <typename T, typename U = T>
357 std::ostringstream& AddTextureExpectation(const char* file,
358 int line,
359 const T* expectedData,
360 const wgpu::Texture& texture,
361 wgpu::Origin3D origin,
362 wgpu::Extent3D extent,
363 uint32_t level = 0,
364 wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
365 uint32_t bytesPerRow = 0) {
366 return AddTextureExpectationImpl(
367 file, line,
368 new detail::ExpectEq<T, U>(expectedData,
369 extent.width * extent.height * extent.depthOrArrayLayers),
370 texture, origin, extent, level, aspect, sizeof(U), bytesPerRow);
371 }
372
373 template <typename T, typename U = T>
374 std::ostringstream& AddTextureExpectation(const char* file,
375 int line,
376 const T& expectedData,
377 const wgpu::Texture& texture,
378 wgpu::Origin3D origin,
379 uint32_t level = 0,
380 wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
381 uint32_t bytesPerRow = 0) {
382 return AddTextureExpectationImpl(file, line, new detail::ExpectEq<T, U>(expectedData),
383 texture, origin, {1, 1}, level, aspect, sizeof(U),
384 bytesPerRow);
385 }
386
387 template <typename E,
388 typename = typename std::enable_if<
389 std::is_base_of<detail::CustomTextureExpectation, E>::value>::type>
390 std::ostringstream& AddTextureExpectation(const char* file,
391 int line,
392 E* expectation,
393 const wgpu::Texture& texture,
394 wgpu::Origin3D origin,
395 wgpu::Extent3D extent,
396 uint32_t level = 0,
397 wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
398 uint32_t bytesPerRow = 0) {
399 return AddTextureExpectationImpl(file, line, expectation, texture, origin, extent, level,
400 aspect, expectation->DataSize(), bytesPerRow);
401 }
402
403 template <typename T>
404 std::ostringstream& AddTextureBetweenColorsExpectation(
405 const char* file,
406 int line,
407 const T& color0,
408 const T& color1,
409 const wgpu::Texture& texture,
410 uint32_t x,
411 uint32_t y,
412 uint32_t level = 0,
413 wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
414 uint32_t bytesPerRow = 0) {
415 return AddTextureExpectationImpl(
416 file, line, new detail::ExpectBetweenColors<T>(color0, color1), texture, {x, y}, {1, 1},
417 level, aspect, sizeof(T), bytesPerRow);
418 }
419
420 std::ostringstream& ExpectSampledFloatData(wgpu::Texture texture,
421 uint32_t width,
422 uint32_t height,
423 uint32_t componentCount,
424 uint32_t arrayLayer,
425 uint32_t mipLevel,
426 detail::Expectation* expectation);
427
428 std::ostringstream& ExpectMultisampledFloatData(wgpu::Texture texture,
429 uint32_t width,
430 uint32_t height,
431 uint32_t componentCount,
432 uint32_t sampleCount,
433 uint32_t arrayLayer,
434 uint32_t mipLevel,
435 detail::Expectation* expectation);
436
437 std::ostringstream& ExpectSampledDepthData(wgpu::Texture depthTexture,
438 uint32_t width,
439 uint32_t height,
440 uint32_t arrayLayer,
441 uint32_t mipLevel,
442 detail::Expectation* expectation);
443
444 // Check depth by uploading expected data to a sampled texture, writing it out as a depth
445 // attachment, and then using the "equals" depth test to check the contents are the same.
446 // Check stencil by rendering a full screen quad and using the "equals" stencil test with
447 // a stencil reference value. Note that checking stencil checks that the entire stencil
448 // buffer is equal to the expected stencil value.
449 std::ostringstream& ExpectAttachmentDepthStencilTestData(wgpu::Texture texture,
450 wgpu::TextureFormat format,
451 uint32_t width,
452 uint32_t height,
453 uint32_t arrayLayer,
454 uint32_t mipLevel,
455 std::vector<float> expectedDepth,
456 uint8_t* expectedStencil);
457
ExpectAttachmentDepthTestData(wgpu::Texture texture,wgpu::TextureFormat format,uint32_t width,uint32_t height,uint32_t arrayLayer,uint32_t mipLevel,std::vector<float> expectedDepth)458 std::ostringstream& ExpectAttachmentDepthTestData(wgpu::Texture texture,
459 wgpu::TextureFormat format,
460 uint32_t width,
461 uint32_t height,
462 uint32_t arrayLayer,
463 uint32_t mipLevel,
464 std::vector<float> expectedDepth) {
465 return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer,
466 mipLevel, std::move(expectedDepth), nullptr);
467 }
468
ExpectAttachmentStencilTestData(wgpu::Texture texture,wgpu::TextureFormat format,uint32_t width,uint32_t height,uint32_t arrayLayer,uint32_t mipLevel,uint8_t expectedStencil)469 std::ostringstream& ExpectAttachmentStencilTestData(wgpu::Texture texture,
470 wgpu::TextureFormat format,
471 uint32_t width,
472 uint32_t height,
473 uint32_t arrayLayer,
474 uint32_t mipLevel,
475 uint8_t expectedStencil) {
476 return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer,
477 mipLevel, {}, &expectedStencil);
478 }
479
480 void WaitABit();
481 void FlushWire();
482 void WaitForAllOperations();
483
484 bool SupportsFeatures(const std::vector<const char*>& features);
485
486 // Called in SetUp() to get the features required to be enabled in the tests. The tests must
487 // check if the required features are supported by the adapter in this function and guarantee
488 // the returned features are all supported by the adapter. The tests may provide different
489 // code path to handle the situation when not all features are supported.
490 virtual std::vector<const char*> GetRequiredFeatures();
491
492 virtual wgpu::RequiredLimits GetRequiredLimits(const wgpu::SupportedLimits&);
493
494 const wgpu::AdapterProperties& GetAdapterProperties() const;
495
496 // TODO(crbug.com/dawn/689): Use limits returned from the wire
497 // This is implemented here because tests need to always query
498 // the |backendDevice| since limits are not implemented in the wire.
499 wgpu::SupportedLimits GetSupportedLimits();
500
501 private:
502 utils::ScopedAutoreleasePool mObjCAutoreleasePool;
503 AdapterTestParam mParam;
504 std::unique_ptr<utils::WireHelper> mWireHelper;
505
506 // Tracking for validation errors
507 static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata);
508 static void OnDeviceLost(WGPUDeviceLostReason reason, const char* message, void* userdata);
509 bool mExpectError = false;
510 bool mError = false;
511 testing::Matcher<std::string> mErrorMatcher;
512 bool mExpectDestruction = false;
513
514 std::ostringstream& AddTextureExpectationImpl(const char* file,
515 int line,
516 detail::Expectation* expectation,
517 const wgpu::Texture& texture,
518 wgpu::Origin3D origin,
519 wgpu::Extent3D extent,
520 uint32_t level,
521 wgpu::TextureAspect aspect,
522 uint32_t dataSize,
523 uint32_t bytesPerRow);
524
525 std::ostringstream& ExpectSampledFloatDataImpl(wgpu::TextureView textureView,
526 const char* wgslTextureType,
527 uint32_t width,
528 uint32_t height,
529 uint32_t componentCount,
530 uint32_t sampleCount,
531 detail::Expectation* expectation);
532
533 // MapRead buffers used to get data for the expectations
534 struct ReadbackSlot {
535 wgpu::Buffer buffer;
536 uint64_t bufferSize;
537 const void* mappedData = nullptr;
538 };
539 std::vector<ReadbackSlot> mReadbackSlots;
540
541 // Maps all the buffers and fill ReadbackSlot::mappedData
542 void MapSlotsSynchronously();
543 static void SlotMapCallback(WGPUBufferMapAsyncStatus status, void* userdata);
544 size_t mNumPendingMapOperations = 0;
545
546 // Reserve space where the data for an expectation can be copied
547 struct ReadbackReservation {
548 wgpu::Buffer buffer;
549 size_t slot;
550 uint64_t offset;
551 };
552 ReadbackReservation ReserveReadback(uint64_t readbackSize);
553
554 struct DeferredExpectation {
555 const char* file;
556 int line;
557 size_t readbackSlot;
558 uint64_t readbackOffset;
559 uint64_t size;
560 uint32_t rowBytes;
561 uint32_t bytesPerRow;
562 std::unique_ptr<detail::Expectation> expectation;
563 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
564 // Use unique_ptr because of missing move/copy constructors on std::basic_ostringstream
565 std::unique_ptr<std::ostringstream> message;
566 };
567 std::vector<DeferredExpectation> mDeferredExpectations;
568
569 // Assuming the data is mapped, checks all expectations
570 void ResolveExpectations();
571
572 dawn_native::Adapter mBackendAdapter;
573
574 std::unique_ptr<dawn_platform::Platform> mTestPlatform;
575 };
576
577 #define DAWN_SKIP_TEST_IF_BASE(condition, type, reason) \
578 do { \
579 if (condition) { \
580 dawn::InfoLog() << "Test " type ": " #reason; \
581 GTEST_SKIP(); \
582 return; \
583 } \
584 } while (0)
585
586 // Skip a test which requires a feature or a toggle to be present / not present or some WIP
587 // features.
588 #define DAWN_TEST_UNSUPPORTED_IF(condition) \
589 DAWN_SKIP_TEST_IF_BASE(condition, "unsupported", condition)
590
591 // Skip a test when the test failing on a specific HW / backend / OS combination. We can disable
592 // this macro with the command line parameter "--run-suppressed-tests".
593 #define DAWN_SUPPRESS_TEST_IF(condition) \
594 DAWN_SKIP_TEST_IF_BASE(!RunSuppressedTests() && condition, "suppressed", condition)
595
596 #define EXPECT_DEPRECATION_WARNINGS(statement, n) \
597 do { \
598 if (UsesWire()) { \
599 statement; \
600 } else { \
601 size_t warningsBefore = \
602 dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \
603 statement; \
604 size_t warningsAfter = \
605 dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \
606 EXPECT_EQ(mLastWarningCount, warningsBefore); \
607 if (!HasToggleEnabled("skip_validation")) { \
608 EXPECT_EQ(warningsAfter, warningsBefore + n); \
609 } \
610 mLastWarningCount = warningsAfter; \
611 } \
612 } while (0)
613 #define EXPECT_DEPRECATION_WARNING(statement) EXPECT_DEPRECATION_WARNINGS(statement, 1)
614
615 template <typename Params = AdapterTestParam>
616 class DawnTestWithParams : public DawnTestBase, public ::testing::TestWithParam<Params> {
617 protected:
618 DawnTestWithParams();
619 ~DawnTestWithParams() override = default;
620
SetUp()621 void SetUp() override {
622 DawnTestBase::SetUp();
623 }
624
TearDown()625 void TearDown() override {
626 DawnTestBase::TearDown();
627 }
628 };
629
630 template <typename Params>
DawnTestWithParams()631 DawnTestWithParams<Params>::DawnTestWithParams() : DawnTestBase(this->GetParam()) {
632 }
633
634 using DawnTest = DawnTestWithParams<>;
635
636 // Instantiate the test once for each backend provided after the first argument. Use it like this:
637 // DAWN_INSTANTIATE_TEST(MyTestFixture, MetalBackend, OpenGLBackend)
638 #define DAWN_INSTANTIATE_TEST(testName, ...) \
639 const decltype(DAWN_PP_GET_HEAD(__VA_ARGS__)) testName##params[] = {__VA_ARGS__}; \
640 INSTANTIATE_TEST_SUITE_P( \
641 , testName, \
642 testing::ValuesIn(::detail::GetAvailableAdapterTestParamsForBackends( \
643 testName##params, sizeof(testName##params) / sizeof(testName##params[0]))), \
644 DawnTestBase::PrintToStringParamName(#testName)); \
645 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName)
646
647 // Instantiate the test once for each backend provided in the first param list.
648 // The test will be parameterized over the following param lists.
649 // Use it like this:
650 // DAWN_INSTANTIATE_TEST_P(MyTestFixture, {MetalBackend(), OpenGLBackend()}, {A, B, C}, {1, 2, 3})
651 // MyTestFixture must extend DawnTestWithParams<Param> where Param is a struct that extends
652 // AdapterTestParam, and whose constructor looks like:
653 // Param(AdapterTestParam, ABorC, 12or3, ..., otherParams... )
654 // You must also teach GTest how to print this struct.
655 // https://github.com/google/googletest/blob/master/docs/advanced.md#teaching-googletest-how-to-print-your-values
656 // Macro DAWN_TEST_PARAM_STRUCT can help generate this struct.
657 #define DAWN_INSTANTIATE_TEST_P(testName, ...) \
658 INSTANTIATE_TEST_SUITE_P( \
659 , testName, ::testing::ValuesIn(MakeParamGenerator<testName::ParamType>(__VA_ARGS__)), \
660 DawnTestBase::PrintToStringParamName(#testName)); \
661 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName)
662
663 // Implementation for DAWN_TEST_PARAM_STRUCT to declare/print struct fields.
664 #define DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD(Type) Type DAWN_PP_CONCATENATE(m, Type);
665 #define DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD(Type) \
666 o << "; " << #Type << "=" << param.DAWN_PP_CONCATENATE(m, Type);
667
668 // Usage: DAWN_TEST_PARAM_STRUCT(Foo, TypeA, TypeB, ...)
669 // Generate a test param struct called Foo which extends AdapterTestParam and generated
670 // struct _Dawn_Foo. _Dawn_Foo has members of types TypeA, TypeB, etc. which are named mTypeA,
671 // mTypeB, etc. in the order they are placed in the macro argument list. Struct Foo should be
672 // constructed with an AdapterTestParam as the first argument, followed by a list of values
673 // to initialize the base _Dawn_Foo struct.
674 // It is recommended to use alias declarations so that stringified types are more readable.
675 // Example:
676 // using MyParam = unsigned int;
677 // DAWN_TEST_PARAM_STRUCT(FooParams, MyParam);
678 #define DAWN_TEST_PARAM_STRUCT(StructName, ...) \
679 struct DAWN_PP_CONCATENATE(_Dawn_, StructName) { \
680 DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD, \
681 __VA_ARGS__)) \
682 }; \
683 std::ostream& operator<<(std::ostream& o, \
684 const DAWN_PP_CONCATENATE(_Dawn_, StructName) & param) { \
685 DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD, \
686 __VA_ARGS__)) \
687 return o; \
688 } \
689 struct StructName : AdapterTestParam, DAWN_PP_CONCATENATE(_Dawn_, StructName) { \
690 template <typename... Args> \
691 StructName(const AdapterTestParam& param, Args&&... args) \
692 : AdapterTestParam(param), \
693 DAWN_PP_CONCATENATE(_Dawn_, StructName){std::forward<Args>(args)...} { \
694 } \
695 }; \
696 std::ostream& operator<<(std::ostream& o, const StructName& param) { \
697 o << static_cast<const AdapterTestParam&>(param); \
698 o << "; " << static_cast<const DAWN_PP_CONCATENATE(_Dawn_, StructName)&>(param); \
699 return o; \
700 } \
701 static_assert(true, "require semicolon")
702
703 namespace detail {
704 // Helper functions used for DAWN_INSTANTIATE_TEST
705 std::vector<AdapterTestParam> GetAvailableAdapterTestParamsForBackends(
706 const BackendTestConfig* params,
707 size_t numParams);
708
709 // All classes used to implement the deferred expectations should inherit from this.
710 class Expectation {
711 public:
712 virtual ~Expectation() = default;
713
714 // Will be called with the buffer or texture data the expectation should check.
715 virtual testing::AssertionResult Check(const void* data, size_t size) = 0;
716 };
717
718 // Expectation that checks the data is equal to some expected values.
719 // T - expected value Type
720 // U - actual value Type (defaults = T)
721 // This is expanded for float16 mostly where T=float, U=uint16_t
722 template <typename T, typename U>
723 class ExpectEq : public Expectation {
724 public:
725 ExpectEq(T singleValue, T tolerance = {});
726 ExpectEq(const T* values, const unsigned int count, T tolerance = {});
727
728 testing::AssertionResult Check(const void* data, size_t size) override;
729
730 private:
731 std::vector<T> mExpected;
732 T mTolerance;
733 };
734 extern template class ExpectEq<uint8_t>;
735 extern template class ExpectEq<int16_t>;
736 extern template class ExpectEq<uint32_t>;
737 extern template class ExpectEq<uint64_t>;
738 extern template class ExpectEq<RGBA8>;
739 extern template class ExpectEq<float>;
740 extern template class ExpectEq<float, uint16_t>;
741
742 template <typename T>
743 class ExpectBetweenColors : public Expectation {
744 public:
745 // Inclusive for now
746 ExpectBetweenColors(T value0, T value1);
747 testing::AssertionResult Check(const void* data, size_t size) override;
748
749 private:
750 std::vector<T> mLowerColorChannels;
751 std::vector<T> mHigherColorChannels;
752
753 // used for printing error
754 std::vector<T> mValues0;
755 std::vector<T> mValues1;
756 };
757 // A color is considered between color0 and color1 when all channel values are within range of
758 // each counterparts. It doesn't matter which value is higher or lower. Essentially color =
759 // lerp(color0, color1, t) where t is [0,1]. But I don't want to be too strict here.
760 extern template class ExpectBetweenColors<RGBA8>;
761
762 class CustomTextureExpectation : public Expectation {
763 public:
764 virtual ~CustomTextureExpectation() = default;
765 virtual uint32_t DataSize() = 0;
766 };
767
768 } // namespace detail
769
770 #endif // TESTS_DAWNTEST_H_
771