• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "dzn_private.h"
25 
26 #include "vk_alloc.h"
27 #include "vk_debug_report.h"
28 #include "vk_util.h"
29 
30 #include "util/macros.h"
31 #include "util/os_time.h"
32 
33 #ifndef _WIN32
34 #include <sys/eventfd.h>
35 #include <libsync.h>
36 #endif
37 
38 static VkResult
dzn_sync_init(struct vk_device * device,struct vk_sync * sync,uint64_t initial_value)39 dzn_sync_init(struct vk_device *device,
40               struct vk_sync *sync,
41               uint64_t initial_value)
42 {
43    struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
44    struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
45 
46    assert(!(sync->flags & VK_SYNC_IS_SHAREABLE));
47 
48    if (FAILED(ID3D12Device1_CreateFence(ddev->dev, initial_value,
49                                         D3D12_FENCE_FLAG_NONE,
50                                         &IID_ID3D12Fence,
51                                         (void **)&dsync->fence)))
52       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
53 
54    return VK_SUCCESS;
55 }
56 
57 static void
dzn_sync_finish(struct vk_device * device,struct vk_sync * sync)58 dzn_sync_finish(struct vk_device *device,
59                 struct vk_sync *sync)
60 {
61    struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
62 
63    ID3D12Fence_Release(dsync->fence);
64 }
65 
66 static VkResult
dzn_sync_signal(struct vk_device * device,struct vk_sync * sync,uint64_t value)67 dzn_sync_signal(struct vk_device *device,
68                 struct vk_sync *sync,
69                 uint64_t value)
70 {
71    struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
72 
73    if (!(sync->flags & VK_SYNC_IS_TIMELINE))
74       value = 1;
75 
76    if (FAILED(ID3D12Fence_Signal(dsync->fence, value)))
77       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
78 
79    return VK_SUCCESS;
80 }
81 
82 static VkResult
dzn_sync_get_value(struct vk_device * device,struct vk_sync * sync,uint64_t * value)83 dzn_sync_get_value(struct vk_device *device,
84                    struct vk_sync *sync,
85                    uint64_t *value)
86 {
87    struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
88 
89    *value = ID3D12Fence_GetCompletedValue(dsync->fence);
90    return VK_SUCCESS;
91 }
92 
93 static VkResult
dzn_sync_reset(struct vk_device * device,struct vk_sync * sync)94 dzn_sync_reset(struct vk_device *device,
95                struct vk_sync *sync)
96 {
97    struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
98 
99    if (FAILED(ID3D12Fence_Signal(dsync->fence, 0)))
100       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
101 
102    return VK_SUCCESS;
103 }
104 
105 static VkResult
dzn_sync_move(struct vk_device * device,struct vk_sync * dst,struct vk_sync * src)106 dzn_sync_move(struct vk_device *device,
107               struct vk_sync *dst,
108               struct vk_sync *src)
109 {
110    struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
111    struct dzn_sync *ddst = container_of(dst, struct dzn_sync, vk);
112    struct dzn_sync *dsrc = container_of(src, struct dzn_sync, vk);
113    ID3D12Fence *new_fence;
114 
115    if (FAILED(ID3D12Device1_CreateFence(ddev->dev, 0,
116                                         D3D12_FENCE_FLAG_NONE,
117                                         &IID_ID3D12Fence,
118                                         (void **)&new_fence)))
119       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
120 
121    ID3D12Fence_Release(ddst->fence);
122    ddst->fence = dsrc->fence;
123    dsrc->fence = new_fence;
124    return VK_SUCCESS;
125 }
126 
127 static VkResult
dzn_sync_wait(struct vk_device * device,uint32_t wait_count,const struct vk_sync_wait * waits,enum vk_sync_wait_flags wait_flags,uint64_t abs_timeout_ns)128 dzn_sync_wait(struct vk_device *device,
129               uint32_t wait_count,
130               const struct vk_sync_wait *waits,
131               enum vk_sync_wait_flags wait_flags,
132               uint64_t abs_timeout_ns)
133 {
134    struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
135 
136 #ifdef _WIN32
137    HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
138    if (event == NULL)
139       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
140 #else
141    int event_fd = eventfd(0, EFD_CLOEXEC);
142    if (event_fd == -1)
143       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
144    /* The D3D12 event-based APIs in WSL expect an eventfd file descriptor cast to HANDLE */
145    HANDLE event = (HANDLE)(intptr_t)event_fd;
146 #endif
147 
148    STACK_ARRAY(ID3D12Fence *, fences, wait_count);
149    STACK_ARRAY(uint64_t, values, wait_count);
150 
151    for (uint32_t i = 0; i < wait_count; i++) {
152       struct dzn_sync *sync = container_of(waits[i].sync, struct dzn_sync, vk);
153 
154       fences[i] = sync->fence;
155       values[i] = (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? waits[i].wait_value : 1;
156    }
157 
158    D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags =
159       (wait_flags & VK_SYNC_WAIT_ANY) ?
160       D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY :
161       D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL;
162 
163    if (FAILED(ID3D12Device1_SetEventOnMultipleFenceCompletion(ddev->dev,
164                                                               fences,
165                                                               values,
166                                                               wait_count,
167                                                               flags,
168                                                               event))) {
169       STACK_ARRAY_FINISH(fences);
170       STACK_ARRAY_FINISH(values);
171 #ifdef _WIN32
172       CloseHandle(event);
173 #else
174       close(event_fd);
175 #endif
176       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
177    }
178 
179 #ifdef _WIN32
180    DWORD timeout_ms;
181    static const DWORD timeout_infinite = INFINITE;
182 #else
183    int timeout_ms;
184    static const int timeout_infinite = -1;
185 #endif
186 
187    if (abs_timeout_ns == OS_TIMEOUT_INFINITE) {
188       timeout_ms = timeout_infinite;
189    } else {
190       uint64_t cur_time = os_time_get_nano();
191       uint64_t rel_timeout_ns =
192          abs_timeout_ns > cur_time ? abs_timeout_ns - cur_time : 0;
193 
194       timeout_ms = (rel_timeout_ns / 1000000) + (rel_timeout_ns % 1000000 ? 1 : 0);
195    }
196 
197 #ifdef _WIN32
198    DWORD res =
199       WaitForSingleObject(event, timeout_ms);
200 
201    CloseHandle(event);
202    VkResult ret = VK_SUCCESS;
203    if (res == WAIT_TIMEOUT)
204       ret = VK_TIMEOUT;
205    else if (res != WAIT_OBJECT_0)
206       ret = vk_error(device, VK_ERROR_UNKNOWN);
207 #else
208    VkResult ret = sync_wait(event_fd, timeout_ms) != 0 ? VK_TIMEOUT : VK_SUCCESS;
209    close(event_fd);
210 #endif
211 
212    STACK_ARRAY_FINISH(fences);
213    STACK_ARRAY_FINISH(values);
214 
215    return ret;
216 }
217 
218 const struct vk_sync_type dzn_sync_type = {
219    .size = sizeof(struct dzn_sync),
220    .features = (enum vk_sync_features)
221       (VK_SYNC_FEATURE_TIMELINE |
222        VK_SYNC_FEATURE_GPU_WAIT |
223        VK_SYNC_FEATURE_CPU_WAIT |
224        VK_SYNC_FEATURE_CPU_SIGNAL |
225        VK_SYNC_FEATURE_WAIT_ANY |
226        VK_SYNC_FEATURE_WAIT_BEFORE_SIGNAL),
227 
228    .init = dzn_sync_init,
229    .finish = dzn_sync_finish,
230    .signal = dzn_sync_signal,
231    .get_value = dzn_sync_get_value,
232    .reset = dzn_sync_reset,
233    .move = dzn_sync_move,
234    .wait_many = dzn_sync_wait,
235 };
236