• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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