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 "d3d12_fence.h"
25
26 #include "d3d12_context.h"
27 #include "d3d12_screen.h"
28
29 #include "util/u_memory.h"
30
31 #include <dxguids/dxguids.h>
32
33 static void
destroy_fence(struct d3d12_fence * fence)34 destroy_fence(struct d3d12_fence *fence)
35 {
36 d3d12_fence_close_event(fence->event, fence->event_fd);
37 FREE(fence);
38 }
39
40 struct d3d12_fence *
d3d12_create_fence(struct d3d12_screen * screen)41 d3d12_create_fence(struct d3d12_screen *screen)
42 {
43 struct d3d12_fence *ret = CALLOC_STRUCT(d3d12_fence);
44 if (!ret) {
45 debug_printf("CALLOC_STRUCT failed\n");
46 return NULL;
47 }
48
49 ret->cmdqueue_fence = screen->fence;
50 ret->value = ++screen->fence_value;
51 ret->event = d3d12_fence_create_event(&ret->event_fd);
52 if (FAILED(screen->cmdqueue->Signal(screen->fence, ret->value)))
53 goto fail;
54 if (FAILED(screen->fence->SetEventOnCompletion(ret->value, ret->event)))
55 goto fail;
56
57 pipe_reference_init(&ret->reference, 1);
58 return ret;
59
60 fail:
61 destroy_fence(ret);
62 return NULL;
63 }
64
65 struct d3d12_fence *
d3d12_open_fence(struct d3d12_screen * screen,HANDLE handle,const void * name)66 d3d12_open_fence(struct d3d12_screen *screen, HANDLE handle, const void *name)
67 {
68 struct d3d12_fence *ret = CALLOC_STRUCT(d3d12_fence);
69 if (!ret) {
70 debug_printf("CALLOC_STRUCT failed\n");
71 return NULL;
72 }
73
74 HANDLE handle_to_close = nullptr;
75 assert(!!handle ^ !!name);
76 if (name) {
77 screen->dev->OpenSharedHandleByName((LPCWSTR)name, GENERIC_ALL, &handle_to_close);
78 handle = handle_to_close;
79 }
80
81 screen->dev->OpenSharedHandle(handle, IID_PPV_ARGS(&ret->cmdqueue_fence));
82 if (!ret->cmdqueue_fence) {
83 free(ret);
84 return NULL;
85 }
86
87 /* A new value will be assigned later */
88 ret->value = 0;
89 pipe_reference_init(&ret->reference, 1);
90 return ret;
91 }
92
93 void
d3d12_fence_reference(struct d3d12_fence ** ptr,struct d3d12_fence * fence)94 d3d12_fence_reference(struct d3d12_fence **ptr, struct d3d12_fence *fence)
95 {
96 if (pipe_reference(&(*ptr)->reference, &fence->reference))
97 destroy_fence((struct d3d12_fence *)*ptr);
98
99 *ptr = fence;
100 }
101
102 static void
fence_reference(struct pipe_screen * pscreen,struct pipe_fence_handle ** pptr,struct pipe_fence_handle * pfence)103 fence_reference(struct pipe_screen *pscreen,
104 struct pipe_fence_handle **pptr,
105 struct pipe_fence_handle *pfence)
106 {
107 d3d12_fence_reference((struct d3d12_fence **)pptr, d3d12_fence(pfence));
108 }
109
110 bool
d3d12_fence_finish(struct d3d12_fence * fence,uint64_t timeout_ns)111 d3d12_fence_finish(struct d3d12_fence *fence, uint64_t timeout_ns)
112 {
113 if (fence->signaled)
114 return true;
115
116 bool complete = fence->cmdqueue_fence->GetCompletedValue() >= fence->value;
117 if (!complete && timeout_ns)
118 complete = d3d12_fence_wait_event(fence->event, fence->event_fd, timeout_ns);
119
120 fence->signaled = complete;
121 return complete;
122 }
123
124 static bool
fence_finish(struct pipe_screen * pscreen,struct pipe_context * pctx,struct pipe_fence_handle * pfence,uint64_t timeout_ns)125 fence_finish(struct pipe_screen *pscreen, struct pipe_context *pctx,
126 struct pipe_fence_handle *pfence, uint64_t timeout_ns)
127 {
128 bool ret = d3d12_fence_finish(d3d12_fence(pfence), timeout_ns);
129 if (ret && pctx) {
130 pctx = threaded_context_unwrap_sync(pctx);
131 struct d3d12_context *ctx = d3d12_context(pctx);
132 d3d12_foreach_submitted_batch(ctx, batch)
133 d3d12_reset_batch(ctx, batch, 0);
134 }
135 return ret;
136 }
137
138 void
d3d12_screen_fence_init(struct pipe_screen * pscreen)139 d3d12_screen_fence_init(struct pipe_screen *pscreen)
140 {
141 pscreen->fence_reference = fence_reference;
142 pscreen->fence_finish = fence_finish;
143 }
144