1 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // SemaphoreVk.cpp: Defines the class interface for SemaphoreVk, implementing
6 // SemaphoreImpl.
7
8 #include "libANGLE/renderer/vulkan/SemaphoreVk.h"
9
10 #include "common/debug.h"
11 #include "libANGLE/Context.h"
12 #include "libANGLE/renderer/vulkan/BufferVk.h"
13 #include "libANGLE/renderer/vulkan/ContextVk.h"
14 #include "libANGLE/renderer/vulkan/RendererVk.h"
15 #include "libANGLE/renderer/vulkan/TextureVk.h"
16
17 namespace rx
18 {
19
20 SemaphoreVk::SemaphoreVk() = default;
21
22 SemaphoreVk::~SemaphoreVk() = default;
23
onDestroy(const gl::Context * context)24 void SemaphoreVk::onDestroy(const gl::Context *context)
25 {
26 ContextVk *contextVk = vk::GetImpl(context);
27 contextVk->addGarbage(&mSemaphore);
28 }
29
importFd(gl::Context * context,gl::HandleType handleType,GLint fd)30 angle::Result SemaphoreVk::importFd(gl::Context *context, gl::HandleType handleType, GLint fd)
31 {
32 ContextVk *contextVk = vk::GetImpl(context);
33
34 switch (handleType)
35 {
36 case gl::HandleType::OpaqueFd:
37 return importOpaqueFd(contextVk, fd);
38
39 default:
40 ANGLE_VK_UNREACHABLE(contextVk);
41 return angle::Result::Stop;
42 }
43 }
44
importZirconHandle(gl::Context * context,gl::HandleType handleType,GLuint handle)45 angle::Result SemaphoreVk::importZirconHandle(gl::Context *context,
46 gl::HandleType handleType,
47 GLuint handle)
48 {
49 ContextVk *contextVk = vk::GetImpl(context);
50
51 switch (handleType)
52 {
53 case gl::HandleType::ZirconEvent:
54 return importZirconEvent(contextVk, handle);
55
56 default:
57 ANGLE_VK_UNREACHABLE(contextVk);
58 return angle::Result::Stop;
59 }
60 }
61
wait(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)62 angle::Result SemaphoreVk::wait(gl::Context *context,
63 const gl::BufferBarrierVector &bufferBarriers,
64 const gl::TextureBarrierVector &textureBarriers)
65 {
66 ContextVk *contextVk = vk::GetImpl(context);
67
68 if (!bufferBarriers.empty() || !textureBarriers.empty())
69 {
70 // Create one global memory barrier to cover all barriers.
71 ANGLE_TRY(contextVk->syncExternalMemory());
72 }
73
74 uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
75
76 if (!bufferBarriers.empty())
77 {
78 // Perform a queue ownership transfer for each buffer.
79 for (gl::Buffer *buffer : bufferBarriers)
80 {
81 BufferVk *bufferVk = vk::GetImpl(buffer);
82 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
83
84 vk::CommandBufferAccess access;
85 vk::OutsideRenderPassCommandBuffer *commandBuffer;
86 access.onBufferExternalAcquireRelease(&bufferHelper);
87 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
88
89 // Queue ownership transfer.
90 bufferHelper.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL,
91 rendererQueueFamilyIndex, commandBuffer);
92 }
93 }
94
95 if (!textureBarriers.empty())
96 {
97 // Perform a queue ownership transfer for each texture. Additionally, we are being
98 // informed that the layout of the image has been externally transitioned, so we need to
99 // update our internal state tracking.
100 for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
101 {
102 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
103 vk::ImageHelper &image = textureVk->getImage();
104 vk::ImageLayout layout =
105 vk::GetImageLayoutFromGLImageLayout(contextVk, textureBarrier.layout);
106
107 vk::CommandBufferAccess access;
108 vk::OutsideRenderPassCommandBuffer *commandBuffer;
109 access.onExternalAcquireRelease(&image);
110 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
111
112 // Image should not be accessed while unowned. Emulated formats may have staged updates
113 // to clear the image after initialization.
114 ASSERT(!image.hasStagedUpdatesInAllocatedLevels() || image.hasEmulatedImageChannels());
115
116 // Queue ownership transfer and layout transition.
117 image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex,
118 layout, commandBuffer);
119 }
120 }
121
122 contextVk->addWaitSemaphore(mSemaphore.getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
123 return angle::Result::Continue;
124 }
125
signal(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)126 angle::Result SemaphoreVk::signal(gl::Context *context,
127 const gl::BufferBarrierVector &bufferBarriers,
128 const gl::TextureBarrierVector &textureBarriers)
129 {
130 ContextVk *contextVk = vk::GetImpl(context);
131 RendererVk *renderer = contextVk->getRenderer();
132
133 uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
134
135 if (!bufferBarriers.empty())
136 {
137 // Perform a queue ownership transfer for each buffer.
138 for (gl::Buffer *buffer : bufferBarriers)
139 {
140 BufferVk *bufferVk = vk::GetImpl(buffer);
141 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
142
143 ANGLE_TRY(contextVk->onBufferReleaseToExternal(bufferHelper));
144 vk::CommandBufferAccess access;
145 vk::OutsideRenderPassCommandBuffer *commandBuffer;
146 access.onBufferExternalAcquireRelease(&bufferHelper);
147 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
148
149 // Queue ownership transfer.
150 bufferHelper.releaseToExternal(contextVk, rendererQueueFamilyIndex,
151 VK_QUEUE_FAMILY_EXTERNAL, commandBuffer);
152 }
153 }
154
155 if (!textureBarriers.empty())
156 {
157 // Perform a queue ownership transfer for each texture. Additionally, transition the image
158 // to the requested layout.
159 for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
160 {
161 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
162 vk::ImageHelper &image = textureVk->getImage();
163 vk::ImageLayout layout =
164 vk::GetImageLayoutFromGLImageLayout(contextVk, textureBarrier.layout);
165
166 // Don't transition to Undefined layout. If external wants to transition the image away
167 // from Undefined after this operation, it's perfectly fine to keep the layout as is in
168 // ANGLE. Note that vk::ImageHelper doesn't expect transitions to Undefined.
169 if (layout == vk::ImageLayout::Undefined)
170 {
171 layout = image.getCurrentImageLayout();
172 }
173
174 ANGLE_TRY(textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
175
176 ANGLE_TRY(contextVk->onImageReleaseToExternal(image));
177 vk::CommandBufferAccess access;
178 vk::OutsideRenderPassCommandBuffer *commandBuffer;
179 access.onExternalAcquireRelease(&image);
180 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
181
182 // Queue ownership transfer and layout transition.
183 image.releaseToExternal(contextVk, rendererQueueFamilyIndex, VK_QUEUE_FAMILY_EXTERNAL,
184 layout, commandBuffer);
185 }
186 }
187
188 if (!bufferBarriers.empty() || !textureBarriers.empty())
189 {
190 // Create one global memory barrier to cover all barriers.
191 ANGLE_TRY(contextVk->syncExternalMemory());
192 }
193
194 ANGLE_TRY(contextVk->flushImpl(&mSemaphore, nullptr,
195 RenderPassClosureReason::ExternalSemaphoreSignal));
196
197 // The external has asked for the semaphore to be signaled. It will wait on this semaphore and
198 // so we must ensure that the above flush (resulting in vkQueueSubmit) has actually been
199 // submitted (as opposed to simply being scheduled as a task for another thread). Per the
200 // Vulkan spec:
201 //
202 // > ... when a semaphore wait operation is submitted to a queue:
203 // >
204 // > - A binary semaphore must be signaled, or have an associated semaphore signal operation
205 // > that is pending execution.
206 //
207 return renderer->waitForQueueSerialToBeSubmittedToDevice(
208 contextVk, contextVk->getLastSubmittedQueueSerial());
209 }
210
importOpaqueFd(ContextVk * contextVk,GLint fd)211 angle::Result SemaphoreVk::importOpaqueFd(ContextVk *contextVk, GLint fd)
212 {
213 RendererVk *renderer = contextVk->getRenderer();
214
215 if (!mSemaphore.valid())
216 {
217 mSemaphore.init(renderer->getDevice());
218 }
219
220 ASSERT(mSemaphore.valid());
221
222 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo = {};
223 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
224 importSemaphoreFdInfo.semaphore = mSemaphore.getHandle();
225 importSemaphoreFdInfo.flags = 0;
226 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
227 importSemaphoreFdInfo.fd = fd;
228
229 ANGLE_VK_TRY(contextVk, vkImportSemaphoreFdKHR(renderer->getDevice(), &importSemaphoreFdInfo));
230
231 return angle::Result::Continue;
232 }
233
importZirconEvent(ContextVk * contextVk,GLuint handle)234 angle::Result SemaphoreVk::importZirconEvent(ContextVk *contextVk, GLuint handle)
235 {
236 RendererVk *renderer = contextVk->getRenderer();
237
238 if (!mSemaphore.valid())
239 {
240 mSemaphore.init(renderer->getDevice());
241 }
242
243 ASSERT(mSemaphore.valid());
244
245 VkImportSemaphoreZirconHandleInfoFUCHSIA importSemaphoreZirconHandleInfo = {};
246 importSemaphoreZirconHandleInfo.sType =
247 VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA;
248 importSemaphoreZirconHandleInfo.semaphore = mSemaphore.getHandle();
249 importSemaphoreZirconHandleInfo.flags = 0;
250 importSemaphoreZirconHandleInfo.handleType =
251 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA;
252 importSemaphoreZirconHandleInfo.zirconHandle = handle;
253
254 // TODO(spang): Add vkImportSemaphoreZirconHandleFUCHSIA to volk.
255 static PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA =
256 reinterpret_cast<PFN_vkImportSemaphoreZirconHandleFUCHSIA>(
257 vkGetInstanceProcAddr(renderer->getInstance(), "vkImportSemaphoreZirconHandleFUCHSIA"));
258
259 ANGLE_VK_TRY(contextVk, vkImportSemaphoreZirconHandleFUCHSIA(renderer->getDevice(),
260 &importSemaphoreZirconHandleInfo));
261
262 return angle::Result::Continue;
263 }
264
265 } // namespace rx
266