• 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 #include "dawn/dawncpp.h"
16 #include "dawn_native/DawnNative.h"
17 
18 #include <gtest/gtest.h>
19 
20 #include <memory>
21 #include <unordered_map>
22 #include <vector>
23 
24 // Getting data back from Dawn is done in an async manners so all expectations are "deferred"
25 // until the end of the test. Also expectations use a copy to a MapRead buffer to get the data
26 // so resources should have the CopySrc allowed usage bit if you want to add expectations on
27 // them.
28 #define EXPECT_BUFFER_U32_EQ(expected, buffer, offset)                         \
29     AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t), \
30                          new detail::ExpectEq<uint32_t>(expected))
31 
32 #define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count)                    \
33     AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t) * count, \
34                          new detail::ExpectEq<uint32_t>(expected, count))
35 
36 // Test a pixel of the mip level 0 of a 2D texture.
37 #define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y)                                  \
38     AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, 0, 0, sizeof(RGBA8), \
39                           new detail::ExpectEq<RGBA8>(expected))
40 
41 #define EXPECT_TEXTURE_RGBA8_EQ(expected, texture, x, y, width, height, level, slice)     \
42     AddTextureExpectation(__FILE__, __LINE__, texture, x, y, width, height, level, slice, \
43                           sizeof(RGBA8),                                                  \
44                           new detail::ExpectEq<RGBA8>(expected, (width) * (height)))
45 
46 // Should only be used to test validation of function that can't be tested by regular validation
47 // tests;
48 #define ASSERT_DEVICE_ERROR(statement) \
49     StartExpectDeviceError();          \
50     statement;                         \
51     FlushWire();                       \
52     ASSERT_TRUE(EndExpectDeviceError());
53 
54 struct RGBA8 {
RGBA8RGBA855     constexpr RGBA8() : RGBA8(0, 0, 0, 0) {
56     }
RGBA8RGBA857     constexpr RGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {
58     }
59     bool operator==(const RGBA8& other) const;
60     bool operator!=(const RGBA8& other) const;
61 
62     uint8_t r, g, b, a;
63 };
64 std::ostream& operator<<(std::ostream& stream, const RGBA8& color);
65 
66 struct DawnTestParam {
DawnTestParamDawnTestParam67     explicit DawnTestParam(dawn_native::BackendType backendType) : backendType(backendType) {
68     }
69 
70     dawn_native::BackendType backendType;
71 
72     std::vector<const char*> forceEnabledWorkarounds;
73     std::vector<const char*> forceDisabledWorkarounds;
74 };
75 
76 // Shorthands for backend types used in the DAWN_INSTANTIATE_TEST
77 extern const DawnTestParam D3D12Backend;
78 extern const DawnTestParam MetalBackend;
79 extern const DawnTestParam OpenGLBackend;
80 extern const DawnTestParam VulkanBackend;
81 
82 DawnTestParam ForceWorkarounds(const DawnTestParam& originParam,
83                                std::initializer_list<const char*> forceEnabledWorkarounds,
84                                std::initializer_list<const char*> forceDisabledWorkarounds = {});
85 
86 struct GLFWwindow;
87 
88 namespace utils {
89     class BackendBinding;
90     class TerribleCommandBuffer;
91 }  // namespace utils
92 
93 namespace detail {
94     class Expectation;
95 }  // namespace detail
96 
97 namespace dawn_wire {
98     class WireClient;
99     class WireServer;
100 }  // namespace dawn_wire
101 
102 void InitDawnEnd2EndTestEnvironment(int argc, char** argv);
103 
104 class DawnTestEnvironment : public testing::Environment {
105   public:
106     DawnTestEnvironment(int argc, char** argv);
107     ~DawnTestEnvironment() = default;
108 
109     void SetUp() override;
110 
111     bool UsesWire() const;
112     bool IsBackendValidationEnabled() const;
113     dawn_native::Instance* GetInstance() const;
114     GLFWwindow* GetWindowForBackend(dawn_native::BackendType type) const;
115     bool HasVendorIdFilter() const;
116     uint32_t GetVendorIdFilter() const;
117 
118   private:
119     void CreateBackendWindow(dawn_native::BackendType type);
120 
121     bool mUseWire = false;
122     bool mEnableBackendValidation = false;
123     bool mBeginCaptureOnStartup = false;
124     bool mHasVendorIdFilter = false;
125     uint32_t mVendorIdFilter = 0;
126     std::unique_ptr<dawn_native::Instance> mInstance;
127 
128     // Windows don't usually like to be bound to one API than the other, for example switching
129     // from Vulkan to OpenGL causes crashes on some drivers. Because of this, we lazily created
130     // a window for each backing API.
131     std::unordered_map<dawn_native::BackendType, GLFWwindow*> mWindows;
132 };
133 
134 class DawnTest : public ::testing::TestWithParam<DawnTestParam> {
135   public:
136     DawnTest();
137     ~DawnTest();
138 
139     void SetUp() override;
140     void TearDown() override;
141 
142     bool IsD3D12() const;
143     bool IsMetal() const;
144     bool IsOpenGL() const;
145     bool IsVulkan() const;
146 
147     bool IsAMD() const;
148     bool IsARM() const;
149     bool IsImgTec() const;
150     bool IsIntel() const;
151     bool IsNvidia() const;
152     bool IsQualcomm() const;
153 
154     bool IsWindows() const;
155     bool IsLinux() const;
156     bool IsMacOS() const;
157 
158     bool UsesWire() const;
159     bool IsBackendValidationEnabled() const;
160 
161     void StartExpectDeviceError();
162     bool EndExpectDeviceError();
163 
164     bool HasVendorIdFilter() const;
165     uint32_t GetVendorIdFilter() const;
166 
167   protected:
168     dawn::Device device;
169     dawn::Queue queue;
170     dawn::SwapChain swapchain;
171 
172     DawnProcTable backendProcs = {};
173     DawnDevice backendDevice = nullptr;
174 
175     // Helper methods to implement the EXPECT_ macros
176     std::ostringstream& AddBufferExpectation(const char* file,
177                                              int line,
178                                              const dawn::Buffer& buffer,
179                                              uint64_t offset,
180                                              uint64_t size,
181                                              detail::Expectation* expectation);
182     std::ostringstream& AddTextureExpectation(const char* file,
183                                               int line,
184                                               const dawn::Texture& texture,
185                                               uint32_t x,
186                                               uint32_t y,
187                                               uint32_t width,
188                                               uint32_t height,
189                                               uint32_t level,
190                                               uint32_t slice,
191                                               uint32_t pixelSize,
192                                               detail::Expectation* expectation);
193 
194     void WaitABit();
195     void FlushWire();
196 
197     void SwapBuffersForCapture();
198 
199   private:
200     // Things used to set up testing through the Wire.
201     std::unique_ptr<dawn_wire::WireServer> mWireServer;
202     std::unique_ptr<dawn_wire::WireClient> mWireClient;
203     std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf;
204     std::unique_ptr<utils::TerribleCommandBuffer> mS2cBuf;
205 
206     // Tracking for validation errors
207     static void OnDeviceError(const char* message, void* userdata);
208     bool mExpectError = false;
209     bool mError = false;
210 
211     // MapRead buffers used to get data for the expectations
212     struct ReadbackSlot {
213         dawn::Buffer buffer;
214         uint64_t bufferSize;
215         const void* mappedData = nullptr;
216     };
217     std::vector<ReadbackSlot> mReadbackSlots;
218 
219     // Maps all the buffers and fill ReadbackSlot::mappedData
220     void MapSlotsSynchronously();
221     static void SlotMapReadCallback(DawnBufferMapAsyncStatus status,
222                                     const void* data,
223                                     uint64_t dataLength,
224                                     void* userdata);
225     size_t mNumPendingMapOperations = 0;
226 
227     // Reserve space where the data for an expectation can be copied
228     struct ReadbackReservation {
229         dawn::Buffer buffer;
230         size_t slot;
231         uint64_t offset;
232     };
233     ReadbackReservation ReserveReadback(uint64_t readbackSize);
234 
235     struct DeferredExpectation {
236         const char* file;
237         int line;
238         size_t readbackSlot;
239         uint64_t readbackOffset;
240         uint64_t size;
241         uint32_t rowBytes;
242         uint32_t rowPitch;
243         std::unique_ptr<detail::Expectation> expectation;
244         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
245         // Use unique_ptr because of missing move/copy constructors on std::basic_ostringstream
246         std::unique_ptr<std::ostringstream> message;
247     };
248     std::vector<DeferredExpectation> mDeferredExpectations;
249 
250     // Assuming the data is mapped, checks all expectations
251     void ResolveExpectations();
252 
253     std::unique_ptr<utils::BackendBinding> mBinding;
254 
255     dawn_native::PCIInfo mPCIInfo;
256 };
257 
258 // Instantiate the test once for each backend provided after the first argument. Use it like this:
259 //     DAWN_INSTANTIATE_TEST(MyTestFixture, MetalBackend, OpenGLBackend)
260 #define DAWN_INSTANTIATE_TEST(testName, firstParam, ...)                         \
261     const decltype(firstParam) testName##params[] = {firstParam, ##__VA_ARGS__}; \
262     INSTANTIATE_TEST_SUITE_P(                                                    \
263         , testName,                                                              \
264         testing::ValuesIn(::detail::FilterBackends(                              \
265             testName##params, sizeof(testName##params) / sizeof(firstParam))),   \
266         ::detail::GetParamName)
267 
268 // Skip a test when the given condition is satisfied.
269 #define DAWN_SKIP_TEST_IF(condition)                               \
270     if (condition) {                                               \
271         std::cout << "Test skipped: " #condition "." << std::endl; \
272         return;                                                    \
273     }
274 
275 namespace detail {
276     // Helper functions used for DAWN_INSTANTIATE_TEST
277     bool IsBackendAvailable(dawn_native::BackendType type);
278     std::vector<DawnTestParam> FilterBackends(const DawnTestParam* params, size_t numParams);
279     std::string GetParamName(const testing::TestParamInfo<DawnTestParam>& info);
280 
281     // All classes used to implement the deferred expectations should inherit from this.
282     class Expectation {
283       public:
284         virtual ~Expectation() = default;
285 
286         // Will be called with the buffer or texture data the expectation should check.
287         virtual testing::AssertionResult Check(const void* data, size_t size) = 0;
288     };
289 
290     // Expectation that checks the data is equal to some expected values.
291     template <typename T>
292     class ExpectEq : public Expectation {
293       public:
294         ExpectEq(T singleValue);
295         ExpectEq(const T* values, const unsigned int count);
296 
297         testing::AssertionResult Check(const void* data, size_t size) override;
298 
299       private:
300         std::vector<T> mExpected;
301     };
302     extern template class ExpectEq<uint8_t>;
303     extern template class ExpectEq<uint32_t>;
304     extern template class ExpectEq<RGBA8>;
305 }  // namespace detail
306