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