1 // Copyright 2021 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/dawn_proc.h"
16 #include "tests/DawnTest.h"
17 #include "utils/SystemUtils.h"
18 #include "utils/WGPUHelpers.h"
19
20 class DeviceInitializationTest : public testing::Test {
21 void SetUp() override {
22 dawnProcSetProcs(&dawn_native::GetProcs());
23 }
24
25 void TearDown() override {
26 dawnProcSetProcs(nullptr);
27 }
28 };
29
30 // Test that device operations are still valid if the reference to the instance
31 // is dropped.
TEST_F(DeviceInitializationTest, DeviceOutlivesInstance)32 TEST_F(DeviceInitializationTest, DeviceOutlivesInstance) {
33 // Get properties of all available adapters and then free the instance.
34 // We want to create a device on a fresh instance and adapter each time.
35 std::vector<wgpu::AdapterProperties> availableAdapterProperties;
36 {
37 auto instance = std::make_unique<dawn_native::Instance>();
38 instance->DiscoverDefaultAdapters();
39 for (const dawn_native::Adapter& adapter : instance->GetAdapters()) {
40 wgpu::AdapterProperties properties;
41 adapter.GetProperties(&properties);
42
43 if (properties.backendType == wgpu::BackendType::Null) {
44 continue;
45 }
46 availableAdapterProperties.push_back(properties);
47 }
48 }
49
50 for (const wgpu::AdapterProperties& desiredProperties : availableAdapterProperties) {
51 wgpu::Device device;
52
53 auto instance = std::make_unique<dawn_native::Instance>();
54 instance->DiscoverDefaultAdapters();
55 for (dawn_native::Adapter& adapter : instance->GetAdapters()) {
56 wgpu::AdapterProperties properties;
57 adapter.GetProperties(&properties);
58
59 if (properties.deviceID == desiredProperties.deviceID &&
60 properties.vendorID == desiredProperties.vendorID &&
61 properties.adapterType == desiredProperties.adapterType &&
62 properties.backendType == desiredProperties.backendType) {
63 // Create the device, destroy the instance, and break out of the loop.
64 dawn_native::DawnDeviceDescriptor deviceDescriptor = {};
65 device = wgpu::Device::Acquire(adapter.CreateDevice(&deviceDescriptor));
66 instance.reset();
67 break;
68 }
69 }
70
71 // Now, test that the device can still be used by testing a buffer copy.
72 wgpu::Buffer src =
73 utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::CopySrc, {1, 2, 3, 4});
74
75 wgpu::Buffer dst = utils::CreateBufferFromData<uint32_t>(
76 device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead, {0, 0, 0, 0});
77
78 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
79 encoder.CopyBufferToBuffer(src, 0, dst, 0, 4 * sizeof(uint32_t));
80
81 wgpu::CommandBuffer commands = encoder.Finish();
82 device.GetQueue().Submit(1, &commands);
83
84 bool done = false;
85 dst.MapAsync(
86 wgpu::MapMode::Read, 0, 4 * sizeof(uint32_t),
87 [](WGPUBufferMapAsyncStatus status, void* userdata) {
88 EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Success);
89 *static_cast<bool*>(userdata) = true;
90 },
91 &done);
92
93 // Note: we can't actually test this if Tick moves over to
94 // wgpuInstanceProcessEvents. We can still test that object creation works
95 // without crashing.
96 while (!done) {
97 device.Tick();
98 utils::USleep(100);
99 }
100
101 const uint32_t* mapping = static_cast<const uint32_t*>(dst.GetConstMappedRange());
102 EXPECT_EQ(mapping[0], 1u);
103 EXPECT_EQ(mapping[1], 2u);
104 EXPECT_EQ(mapping[2], 3u);
105 EXPECT_EQ(mapping[3], 4u);
106 }
107 }
108