• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SyncVk.cpp:
7 //    Implements the class methods for SyncVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/SyncVk.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/DisplayVk.h"
17 
18 namespace rx
19 {
20 namespace vk
21 {
SyncHelper()22 SyncHelper::SyncHelper()
23 {
24     mUse.init();
25 }
26 
~SyncHelper()27 SyncHelper::~SyncHelper()
28 {
29     mUse.release();
30 }
31 
releaseToRenderer(RendererVk * renderer)32 void SyncHelper::releaseToRenderer(RendererVk *renderer)
33 {
34     renderer->collectGarbageAndReinit(&mUse, &mEvent);
35     mFence.reset(renderer->getDevice());
36 }
37 
initialize(ContextVk * contextVk)38 angle::Result SyncHelper::initialize(ContextVk *contextVk)
39 {
40     ASSERT(!mEvent.valid());
41 
42     RendererVk *renderer = contextVk->getRenderer();
43     VkDevice device      = renderer->getDevice();
44 
45     VkEventCreateInfo eventCreateInfo = {};
46     eventCreateInfo.sType             = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
47     eventCreateInfo.flags             = 0;
48 
49     DeviceScoped<Event> event(device);
50     ANGLE_VK_TRY(contextVk, event.get().init(device, eventCreateInfo));
51     ANGLE_TRY(contextVk->getNextSubmitFence(&mFence));
52 
53     mEvent = event.release();
54 
55     vk::PrimaryCommandBuffer *primary;
56     ANGLE_TRY(contextVk->flushAndGetPrimaryCommandBuffer(&primary));
57     primary->setEvent(mEvent.getHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
58     contextVk->getResourceUseList().add(mUse);
59 
60     return angle::Result::Continue;
61 }
62 
clientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,VkResult * outResult)63 angle::Result SyncHelper::clientWait(Context *context,
64                                      ContextVk *contextVk,
65                                      bool flushCommands,
66                                      uint64_t timeout,
67                                      VkResult *outResult)
68 {
69     RendererVk *renderer = context->getRenderer();
70 
71     // If the event is already set, don't wait
72     bool alreadySignaled = false;
73     ANGLE_TRY(getStatus(context, &alreadySignaled));
74     if (alreadySignaled)
75     {
76         *outResult = VK_EVENT_SET;
77         return angle::Result::Continue;
78     }
79 
80     // If timeout is zero, there's no need to wait, so return timeout already.
81     if (timeout == 0)
82     {
83         *outResult = VK_TIMEOUT;
84         return angle::Result::Continue;
85     }
86 
87     if (flushCommands && contextVk)
88     {
89         ANGLE_TRY(contextVk->flushImpl(nullptr));
90     }
91 
92     // Wait on the fence that's expected to be signaled on the first vkQueueSubmit after
93     // `initialize` was called. The first fence is the fence created to signal this sync.
94     ASSERT(mFence.get().valid());
95     VkResult status = mFence.get().wait(renderer->getDevice(), timeout);
96 
97     // Check for errors, but don't consider timeout as such.
98     if (status != VK_TIMEOUT)
99     {
100         ANGLE_VK_TRY(context, status);
101     }
102 
103     *outResult = status;
104     return angle::Result::Continue;
105 }
106 
serverWait(ContextVk * contextVk)107 angle::Result SyncHelper::serverWait(ContextVk *contextVk)
108 {
109     vk::PrimaryCommandBuffer *primary;
110     ANGLE_TRY(contextVk->flushAndGetPrimaryCommandBuffer(&primary));
111     primary->waitEvents(1, mEvent.ptr(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
112                         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr);
113     contextVk->getResourceUseList().add(mUse);
114     return angle::Result::Continue;
115 }
116 
getStatus(Context * context,bool * signaled)117 angle::Result SyncHelper::getStatus(Context *context, bool *signaled)
118 {
119     VkResult result = mEvent.getStatus(context->getDevice());
120     if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
121     {
122         ANGLE_VK_TRY(context, result);
123     }
124     *signaled = result == VK_EVENT_SET;
125     return angle::Result::Continue;
126 }
127 }  // namespace vk
128 
SyncVk()129 SyncVk::SyncVk() : SyncImpl() {}
130 
~SyncVk()131 SyncVk::~SyncVk() {}
132 
onDestroy(const gl::Context * context)133 void SyncVk::onDestroy(const gl::Context *context)
134 {
135     mFenceSync.releaseToRenderer(vk::GetImpl(context)->getRenderer());
136 }
137 
set(const gl::Context * context,GLenum condition,GLbitfield flags)138 angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags)
139 {
140     ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE);
141     ASSERT(flags == 0);
142 
143     return mFenceSync.initialize(vk::GetImpl(context));
144 }
145 
clientWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout,GLenum * outResult)146 angle::Result SyncVk::clientWait(const gl::Context *context,
147                                  GLbitfield flags,
148                                  GLuint64 timeout,
149                                  GLenum *outResult)
150 {
151     ContextVk *contextVk = vk::GetImpl(context);
152 
153     ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
154 
155     bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
156     VkResult result;
157 
158     ANGLE_TRY(mFenceSync.clientWait(contextVk, contextVk, flush, static_cast<uint64_t>(timeout),
159                                     &result));
160 
161     switch (result)
162     {
163         case VK_EVENT_SET:
164             *outResult = GL_ALREADY_SIGNALED;
165             return angle::Result::Continue;
166 
167         case VK_SUCCESS:
168             *outResult = GL_CONDITION_SATISFIED;
169             return angle::Result::Continue;
170 
171         case VK_TIMEOUT:
172             *outResult = GL_TIMEOUT_EXPIRED;
173             return angle::Result::Incomplete;
174 
175         default:
176             UNREACHABLE();
177             *outResult = GL_WAIT_FAILED;
178             return angle::Result::Stop;
179     }
180 }
181 
serverWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout)182 angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
183 {
184     ASSERT(flags == 0);
185     ASSERT(timeout == GL_TIMEOUT_IGNORED);
186 
187     ContextVk *contextVk = vk::GetImpl(context);
188     return mFenceSync.serverWait(contextVk);
189 }
190 
getStatus(const gl::Context * context,GLint * outResult)191 angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
192 {
193     bool signaled = false;
194     ANGLE_TRY(mFenceSync.getStatus(vk::GetImpl(context), &signaled));
195 
196     *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
197     return angle::Result::Continue;
198 }
199 
EGLSyncVk(const egl::AttributeMap & attribs)200 EGLSyncVk::EGLSyncVk(const egl::AttributeMap &attribs) : EGLSyncImpl()
201 {
202     ASSERT(attribs.isEmpty());
203 }
204 
~EGLSyncVk()205 EGLSyncVk::~EGLSyncVk() {}
206 
onDestroy(const egl::Display * display)207 void EGLSyncVk::onDestroy(const egl::Display *display)
208 {
209     mFenceSync.releaseToRenderer(vk::GetImpl(display)->getRenderer());
210 }
211 
initialize(const egl::Display * display,const gl::Context * context,EGLenum type)212 egl::Error EGLSyncVk::initialize(const egl::Display *display,
213                                  const gl::Context *context,
214                                  EGLenum type)
215 {
216     ASSERT(type == EGL_SYNC_FENCE_KHR);
217     ASSERT(context != nullptr);
218 
219     if (mFenceSync.initialize(vk::GetImpl(context)) == angle::Result::Stop)
220     {
221         return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
222     }
223 
224     return egl::NoError();
225 }
226 
clientWait(const egl::Display * display,const gl::Context * context,EGLint flags,EGLTime timeout,EGLint * outResult)227 egl::Error EGLSyncVk::clientWait(const egl::Display *display,
228                                  const gl::Context *context,
229                                  EGLint flags,
230                                  EGLTime timeout,
231                                  EGLint *outResult)
232 {
233     ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
234 
235     bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
236     VkResult result;
237 
238     ContextVk *contextVk = context ? vk::GetImpl(context) : nullptr;
239     if (mFenceSync.clientWait(vk::GetImpl(display), contextVk, flush,
240                               static_cast<uint64_t>(timeout), &result) == angle::Result::Stop)
241     {
242         return egl::Error(EGL_BAD_ALLOC);
243     }
244 
245     switch (result)
246     {
247         case VK_EVENT_SET:
248             // fall through.  EGL doesn't differentiate between event being already set, or set
249             // before timeout.
250         case VK_SUCCESS:
251             *outResult = EGL_CONDITION_SATISFIED_KHR;
252             return egl::NoError();
253 
254         case VK_TIMEOUT:
255             *outResult = EGL_TIMEOUT_EXPIRED_KHR;
256             return egl::NoError();
257 
258         default:
259             UNREACHABLE();
260             *outResult = EGL_FALSE;
261             return egl::Error(EGL_BAD_ALLOC);
262     }
263 }
264 
serverWait(const egl::Display * display,const gl::Context * context,EGLint flags)265 egl::Error EGLSyncVk::serverWait(const egl::Display *display,
266                                  const gl::Context *context,
267                                  EGLint flags)
268 {
269     // Server wait requires a valid bound context.
270     ASSERT(context);
271 
272     // No flags are currently implemented.
273     ASSERT(flags == 0);
274 
275     DisplayVk *displayVk = vk::GetImpl(display);
276     ContextVk *contextVk = vk::GetImpl(context);
277 
278     return angle::ToEGL(mFenceSync.serverWait(contextVk), displayVk, EGL_BAD_ALLOC);
279 }
280 
getStatus(const egl::Display * display,EGLint * outStatus)281 egl::Error EGLSyncVk::getStatus(const egl::Display *display, EGLint *outStatus)
282 {
283     bool signaled = false;
284     if (mFenceSync.getStatus(vk::GetImpl(display), &signaled) == angle::Result::Stop)
285     {
286         return egl::Error(EGL_BAD_ALLOC);
287     }
288 
289     *outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
290     return egl::NoError();
291 }
292 
dupNativeFenceFD(const egl::Display * display,EGLint * result) const293 egl::Error EGLSyncVk::dupNativeFenceFD(const egl::Display *display, EGLint *result) const
294 {
295     UNREACHABLE();
296     return egl::EglBadDisplay();
297 }
298 
299 }  // namespace rx
300