// Copyright 2019 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "dawn/dawn_proc.h" #include "dawn_native/Instance.h" #include "dawn_native/null/DeviceNull.h" #include "dawn_wire/WireClient.h" #include "utils/TerribleCommandBuffer.h" namespace { // dawn_wire and dawn_native contain duplicated code for the handling of GetProcAddress // so we run the tests against both implementations. This enum is used as a test parameters to // know which implementation to test. enum class DawnFlavor { Native, Wire, }; std::ostream& operator<<(std::ostream& stream, DawnFlavor flavor) { switch (flavor) { case DawnFlavor::Native: stream << "dawn_native"; break; case DawnFlavor::Wire: stream << "dawn_wire"; break; default: UNREACHABLE(); break; } return stream; } class GetProcAddressTests : public testing::TestWithParam { public: GetProcAddressTests() : testing::TestWithParam(), mNativeInstance(dawn_native::InstanceBase::Create()), mNativeAdapter(mNativeInstance.Get()) { } void SetUp() override { switch (GetParam()) { case DawnFlavor::Native: { mDevice = wgpu::Device::Acquire( reinterpret_cast(mNativeAdapter.CreateDevice(nullptr))); mProcs = dawn_native::GetProcs(); break; } case DawnFlavor::Wire: { mC2sBuf = std::make_unique(); dawn_wire::WireClientDescriptor clientDesc = {}; clientDesc.serializer = mC2sBuf.get(); mWireClient = std::make_unique(clientDesc); mDevice = wgpu::Device::Acquire(mWireClient->ReserveDevice().device); mProcs = dawn_wire::client::GetProcs(); break; } default: UNREACHABLE(); break; } dawnProcSetProcs(&mProcs); } void TearDown() override { // Destroy the device before freeing the instance or the wire client in the destructor mDevice = wgpu::Device(); } protected: Ref mNativeInstance; dawn_native::null::Adapter mNativeAdapter; std::unique_ptr mC2sBuf; std::unique_ptr mWireClient; wgpu::Device mDevice; DawnProcTable mProcs; }; // Test GetProcAddress with and without devices on some valid examples TEST_P(GetProcAddressTests, ValidExamples) { ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuDeviceCreateBuffer"), reinterpret_cast(mProcs.deviceCreateBuffer)); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuDeviceCreateBuffer"), reinterpret_cast(mProcs.deviceCreateBuffer)); ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuQueueSubmit"), reinterpret_cast(mProcs.queueSubmit)); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuQueueSubmit"), reinterpret_cast(mProcs.queueSubmit)); } // Test GetProcAddress with and without devices on nullptr procName TEST_P(GetProcAddressTests, Nullptr) { ASSERT_EQ(mProcs.getProcAddress(nullptr, nullptr), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), nullptr), nullptr); } // Test GetProcAddress with and without devices on some invalid TEST_P(GetProcAddressTests, InvalidExamples) { ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuDeviceDoSomething"), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuDeviceDoSomething"), nullptr); // Trigger the condition where lower_bound will return the end of the procMap. ASSERT_EQ(mProcs.getProcAddress(nullptr, "zzzzzzz"), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "zzzzzzz"), nullptr); ASSERT_EQ(mProcs.getProcAddress(nullptr, "ZZ"), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "ZZ"), nullptr); // Some more potential corner cases. ASSERT_EQ(mProcs.getProcAddress(nullptr, ""), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), ""), nullptr); ASSERT_EQ(mProcs.getProcAddress(nullptr, "0"), nullptr); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "0"), nullptr); } // Test that GetProcAddress supports freestanding function that are handled specially TEST_P(GetProcAddressTests, FreeStandingFunctions) { ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuGetProcAddress"), reinterpret_cast(mProcs.getProcAddress)); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuGetProcAddress"), reinterpret_cast(mProcs.getProcAddress)); ASSERT_EQ(mProcs.getProcAddress(nullptr, "wgpuCreateInstance"), reinterpret_cast(mProcs.createInstance)); ASSERT_EQ(mProcs.getProcAddress(mDevice.Get(), "wgpuCreateInstance"), reinterpret_cast(mProcs.createInstance)); } INSTANTIATE_TEST_SUITE_P(, GetProcAddressTests, testing::Values(DawnFlavor::Native, DawnFlavor::Wire), testing::PrintToStringParamName()); TEST(GetProcAddressInternalTests, CheckDawnNativeProcMapOrder) { std::vector names = dawn_native::GetProcMapNamesForTesting(); for (size_t i = 1; i < names.size(); i++) { ASSERT_LT(std::string(names[i - 1]), std::string(names[i])); } } TEST(GetProcAddressInternalTests, CheckDawnWireClientProcMapOrder) { std::vector names = dawn_wire::client::GetProcMapNamesForTesting(); for (size_t i = 1; i < names.size(); i++) { ASSERT_LT(std::string(names[i - 1]), std::string(names[i])); } } } // anonymous namespace