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