1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "d3d12_fence.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "d3d12_context.h"
27bf215546Sopenharmony_ci#include "d3d12_screen.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "util/u_memory.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include <dxguids/dxguids.h>
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ciconstexpr uint64_t NsPerMs = 1000000;
34bf215546Sopenharmony_ciconstexpr uint64_t MaxTimeoutInNs = (uint64_t)UINT_MAX * NsPerMs;
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#ifdef _WIN32
37bf215546Sopenharmony_cistatic void
38bf215546Sopenharmony_ciclose_event(HANDLE event, int fd)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci   if (event)
41bf215546Sopenharmony_ci      CloseHandle(event);
42bf215546Sopenharmony_ci}
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_cistatic HANDLE
45bf215546Sopenharmony_cicreate_event(int *fd)
46bf215546Sopenharmony_ci{
47bf215546Sopenharmony_ci   *fd = -1;
48bf215546Sopenharmony_ci   return CreateEvent(NULL, FALSE, FALSE, NULL);
49bf215546Sopenharmony_ci}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_cistatic bool
52bf215546Sopenharmony_ciwait_event(HANDLE event, int event_fd, uint64_t timeout_ns)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   DWORD timeout_ms = (timeout_ns == PIPE_TIMEOUT_INFINITE || timeout_ns > MaxTimeoutInNs) ? INFINITE : timeout_ns / NsPerMs;
55bf215546Sopenharmony_ci   return WaitForSingleObject(event, timeout_ms) == WAIT_OBJECT_0;
56bf215546Sopenharmony_ci}
57bf215546Sopenharmony_ci#else
58bf215546Sopenharmony_ci#include <sys/eventfd.h>
59bf215546Sopenharmony_ci#include <poll.h>
60bf215546Sopenharmony_ci#include <util/libsync.h>
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistatic void
63bf215546Sopenharmony_ciclose_event(HANDLE event, int fd)
64bf215546Sopenharmony_ci{
65bf215546Sopenharmony_ci   if (fd != -1)
66bf215546Sopenharmony_ci      close(fd);
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cistatic HANDLE
70bf215546Sopenharmony_cicreate_event(int *fd)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   *fd = eventfd(0, 0);
73bf215546Sopenharmony_ci   return (HANDLE)(size_t)*fd;
74bf215546Sopenharmony_ci}
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic bool
77bf215546Sopenharmony_ciwait_event(HANDLE event, int event_fd, uint64_t timeout_ns)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   int timeout_ms = (timeout_ns == PIPE_TIMEOUT_INFINITE || timeout_ns > MaxTimeoutInNs) ? -1 : timeout_ns / NsPerMs;
80bf215546Sopenharmony_ci   return sync_wait(event_fd, timeout_ms) == 0;
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci#endif
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_cistatic void
85bf215546Sopenharmony_cidestroy_fence(struct d3d12_fence *fence)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci   close_event(fence->event, fence->event_fd);
88bf215546Sopenharmony_ci   FREE(fence);
89bf215546Sopenharmony_ci}
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_cistruct d3d12_fence *
92bf215546Sopenharmony_cid3d12_create_fence(struct d3d12_screen *screen)
93bf215546Sopenharmony_ci{
94bf215546Sopenharmony_ci   struct d3d12_fence *ret = CALLOC_STRUCT(d3d12_fence);
95bf215546Sopenharmony_ci   if (!ret) {
96bf215546Sopenharmony_ci      debug_printf("CALLOC_STRUCT failed\n");
97bf215546Sopenharmony_ci      return NULL;
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   ret->cmdqueue_fence = screen->fence;
101bf215546Sopenharmony_ci   ret->value = ++screen->fence_value;
102bf215546Sopenharmony_ci   ret->event = create_event(&ret->event_fd);
103bf215546Sopenharmony_ci   if (FAILED(screen->fence->SetEventOnCompletion(ret->value, ret->event)))
104bf215546Sopenharmony_ci      goto fail;
105bf215546Sopenharmony_ci   if (FAILED(screen->cmdqueue->Signal(screen->fence, ret->value)))
106bf215546Sopenharmony_ci      goto fail;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   pipe_reference_init(&ret->reference, 1);
109bf215546Sopenharmony_ci   return ret;
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_cifail:
112bf215546Sopenharmony_ci   destroy_fence(ret);
113bf215546Sopenharmony_ci   return NULL;
114bf215546Sopenharmony_ci}
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_cistruct d3d12_fence *
117bf215546Sopenharmony_cid3d12_open_fence(struct d3d12_screen *screen, HANDLE handle, const void *name)
118bf215546Sopenharmony_ci{
119bf215546Sopenharmony_ci   struct d3d12_fence *ret = CALLOC_STRUCT(d3d12_fence);
120bf215546Sopenharmony_ci   if (!ret) {
121bf215546Sopenharmony_ci      debug_printf("CALLOC_STRUCT failed\n");
122bf215546Sopenharmony_ci      return NULL;
123bf215546Sopenharmony_ci   }
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   HANDLE handle_to_close = nullptr;
126bf215546Sopenharmony_ci   assert(!!handle ^ !!name);
127bf215546Sopenharmony_ci   if (name) {
128bf215546Sopenharmony_ci      screen->dev->OpenSharedHandleByName((LPCWSTR)name, GENERIC_ALL, &handle_to_close);
129bf215546Sopenharmony_ci      handle = handle_to_close;
130bf215546Sopenharmony_ci   }
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   screen->dev->OpenSharedHandle(handle, IID_PPV_ARGS(&ret->cmdqueue_fence));
133bf215546Sopenharmony_ci   if (!ret->cmdqueue_fence) {
134bf215546Sopenharmony_ci      free(ret);
135bf215546Sopenharmony_ci      return NULL;
136bf215546Sopenharmony_ci   }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   /* A new value will be assigned later */
139bf215546Sopenharmony_ci   ret->value = 0;
140bf215546Sopenharmony_ci   pipe_reference_init(&ret->reference, 1);
141bf215546Sopenharmony_ci   return ret;
142bf215546Sopenharmony_ci}
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_civoid
145bf215546Sopenharmony_cid3d12_fence_reference(struct d3d12_fence **ptr, struct d3d12_fence *fence)
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   if (pipe_reference(&(*ptr)->reference, &fence->reference))
148bf215546Sopenharmony_ci      destroy_fence((struct d3d12_fence *)*ptr);
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   *ptr = fence;
151bf215546Sopenharmony_ci}
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_cistatic void
154bf215546Sopenharmony_cifence_reference(struct pipe_screen *pscreen,
155bf215546Sopenharmony_ci                struct pipe_fence_handle **pptr,
156bf215546Sopenharmony_ci                struct pipe_fence_handle *pfence)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci   d3d12_fence_reference((struct d3d12_fence **)pptr, d3d12_fence(pfence));
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_cibool
162bf215546Sopenharmony_cid3d12_fence_finish(struct d3d12_fence *fence, uint64_t timeout_ns)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   if (fence->signaled)
165bf215546Sopenharmony_ci      return true;
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci   bool complete = fence->cmdqueue_fence->GetCompletedValue() >= fence->value;
168bf215546Sopenharmony_ci   if (!complete && timeout_ns)
169bf215546Sopenharmony_ci      complete = wait_event(fence->event, fence->event_fd, timeout_ns);
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   fence->signaled = complete;
172bf215546Sopenharmony_ci   return complete;
173bf215546Sopenharmony_ci}
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_cistatic bool
176bf215546Sopenharmony_cifence_finish(struct pipe_screen *pscreen, struct pipe_context *pctx,
177bf215546Sopenharmony_ci             struct pipe_fence_handle *pfence, uint64_t timeout_ns)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci   bool ret = d3d12_fence_finish(d3d12_fence(pfence), timeout_ns);
180bf215546Sopenharmony_ci   if (ret && pctx) {
181bf215546Sopenharmony_ci      pctx = threaded_context_unwrap_sync(pctx);
182bf215546Sopenharmony_ci      struct d3d12_context *ctx = d3d12_context(pctx);
183bf215546Sopenharmony_ci      d3d12_foreach_submitted_batch(ctx, batch)
184bf215546Sopenharmony_ci         d3d12_reset_batch(ctx, batch, 0);
185bf215546Sopenharmony_ci   }
186bf215546Sopenharmony_ci   return ret;
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_civoid
190bf215546Sopenharmony_cid3d12_screen_fence_init(struct pipe_screen *pscreen)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   pscreen->fence_reference = fence_reference;
193bf215546Sopenharmony_ci   pscreen->fence_finish = fence_finish;
194bf215546Sopenharmony_ci}
195