1 // Copyright 2019 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 <gtest/gtest.h> 16 17 #include "dawn/dawn_proc.h" 18 #include "dawn_native/Instance.h" 19 #include "dawn_native/null/DeviceNull.h" 20 #include "dawn_wire/WireClient.h" 21 #include "utils/TerribleCommandBuffer.h" 22 23 namespace { 24 25 // dawn_wire and dawn_native contain duplicated code for the handling of GetProcAddress 26 // so we run the tests against both implementations. This enum is used as a test parameters to 27 // know which implementation to test. 28 enum class DawnFlavor { 29 Native, 30 Wire, 31 }; 32 operator <<(std::ostream & stream,DawnFlavor flavor)33 std::ostream& operator<<(std::ostream& stream, DawnFlavor flavor) { 34 switch (flavor) { 35 case DawnFlavor::Native: 36 stream << "dawn_native"; 37 break; 38 39 case DawnFlavor::Wire: 40 stream << "dawn_wire"; 41 break; 42 43 default: 44 UNREACHABLE(); 45 break; 46 } 47 return stream; 48 } 49 50 class GetProcAddressTests : public testing::TestWithParam<DawnFlavor> { 51 public: GetProcAddressTests()52 GetProcAddressTests() 53 : testing::TestWithParam<DawnFlavor>(), 54 mNativeInstance(dawn_native::InstanceBase::Create()), 55 mNativeAdapter(mNativeInstance.Get()) { 56 } 57 SetUp()58 void SetUp() override { 59 switch (GetParam()) { 60 case DawnFlavor::Native: { 61 mDevice = wgpu::Device::Acquire( 62 reinterpret_cast<WGPUDevice>(mNativeAdapter.CreateDevice(nullptr))); 63 mProcs = dawn_native::GetProcs(); 64 break; 65 } 66 67 case DawnFlavor::Wire: { 68 mC2sBuf = std::make_unique<utils::TerribleCommandBuffer>(); 69 70 dawn_wire::WireClientDescriptor clientDesc = {}; 71 clientDesc.serializer = mC2sBuf.get(); 72 mWireClient = std::make_unique<dawn_wire::WireClient>(clientDesc); 73 74 mDevice = wgpu::Device::Acquire(mWireClient->ReserveDevice().device); 75 mProcs = dawn_wire::client::GetProcs(); 76 break; 77 } 78 79 default: 80 UNREACHABLE(); 81 break; 82 } 83 84 dawnProcSetProcs(&mProcs); 85 } 86 TearDown()87 void TearDown() override { 88 // Destroy the device before freeing the instance or the wire client in the destructor 89 mDevice = wgpu::Device(); 90 } 91 92 protected: 93 Ref<dawn_native::InstanceBase> mNativeInstance; 94 dawn_native::null::Adapter mNativeAdapter; 95 96 std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf; 97 std::unique_ptr<dawn_wire::WireClient> mWireClient; 98 99 wgpu::Device mDevice; 100 DawnProcTable mProcs; 101 }; 102 103 // Test GetProcAddress with and without devices on some valid examples TEST_P(GetProcAddressTests,ValidExamples)104 TEST_P(GetProcAddressTests, ValidExamples) { 105 ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuDeviceCreateBuffer"), 106 reinterpret_cast<WGPUProc>(mProcs.deviceCreateBuffer)); 107 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuDeviceCreateBuffer"), 108 reinterpret_cast<WGPUProc>(mProcs.deviceCreateBuffer)); 109 ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuQueueSubmit"), 110 reinterpret_cast<WGPUProc>(mProcs.queueSubmit)); 111 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuQueueSubmit"), 112 reinterpret_cast<WGPUProc>(mProcs.queueSubmit)); 113 } 114 115 // Test GetProcAddress with and without devices on nullptr procName TEST_P(GetProcAddressTests,Nullptr)116 TEST_P(GetProcAddressTests, Nullptr) { 117 ASSERT_EQ(mProcs.getProcAddress(nullptr, nullptr), nullptr); 118 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), nullptr), nullptr); 119 } 120 121 // Test GetProcAddress with and without devices on some invalid TEST_P(GetProcAddressTests,InvalidExamples)122 TEST_P(GetProcAddressTests, InvalidExamples) { 123 ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuDeviceDoSomething"), nullptr); 124 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuDeviceDoSomething"), nullptr); 125 126 // Trigger the condition where lower_bound will return the end of the procMap. 127 ASSERT_EQ(mProcs.getProcAddress(nullptr, "zzzzzzz"), nullptr); 128 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "zzzzzzz"), nullptr); 129 ASSERT_EQ(mProcs.getProcAddress(nullptr, "ZZ"), nullptr); 130 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "ZZ"), nullptr); 131 132 // Some more potential corner cases. 133 ASSERT_EQ(mProcs.getProcAddress(nullptr, ""), nullptr); 134 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), ""), nullptr); 135 ASSERT_EQ(mProcs.getProcAddress(nullptr, "0"), nullptr); 136 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "0"), nullptr); 137 } 138 139 // Test that GetProcAddress supports freestanding function that are handled specially TEST_P(GetProcAddressTests,FreeStandingFunctions)140 TEST_P(GetProcAddressTests, FreeStandingFunctions) { 141 ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuGetProcAddress"), 142 reinterpret_cast<WGPUProc>(mProcs.getProcAddress)); 143 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuGetProcAddress"), 144 reinterpret_cast<WGPUProc>(mProcs.getProcAddress)); 145 146 ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuCreateInstance"), 147 reinterpret_cast<WGPUProc>(mProcs.createInstance)); 148 ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuCreateInstance"), 149 reinterpret_cast<WGPUProc>(mProcs.createInstance)); 150 } 151 152 INSTANTIATE_TEST_SUITE_P(, 153 GetProcAddressTests, 154 testing::Values(DawnFlavor::Native, DawnFlavor::Wire), 155 testing::PrintToStringParamName()); 156 TEST(GetProcAddressInternalTests,CheckDawnNativeProcMapOrder)157 TEST(GetProcAddressInternalTests, CheckDawnNativeProcMapOrder) { 158 std::vector<const char*> names = dawn_native::GetProcMapNamesForTesting(); 159 for (size_t i = 1; i < names.size(); i++) { 160 ASSERT_LT(std::string(names[i - 1]), std::string(names[i])); 161 } 162 } 163 TEST(GetProcAddressInternalTests,CheckDawnWireClientProcMapOrder)164 TEST(GetProcAddressInternalTests, CheckDawnWireClientProcMapOrder) { 165 std::vector<const char*> names = dawn_wire::client::GetProcMapNamesForTesting(); 166 for (size_t i = 1; i < names.size(); i++) { 167 ASSERT_LT(std::string(names[i - 1]), std::string(names[i])); 168 } 169 } 170 } // anonymous namespace 171