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 namespace
21 {
GetVulkanImageLayout(GLenum layout)22 vk::ImageLayout GetVulkanImageLayout(GLenum layout)
23 {
24 switch (layout)
25 {
26 case GL_NONE:
27 return vk::ImageLayout::Undefined;
28 case GL_LAYOUT_GENERAL_EXT:
29 return vk::ImageLayout::ExternalShadersWrite;
30 case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
31 return vk::ImageLayout::ColorAttachment;
32 case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
33 case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
34 case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
35 case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
36 // Note: once VK_KHR_separate_depth_stencil_layouts becomes core or ubiquitous, we
37 // should optimize depth/stencil image layout transitions to only be performed on the
38 // aspect that needs transition. In that case, these four layouts can be distinguished
39 // and optimized. Note that the exact equivalent of these layouts are specified in
40 // VK_KHR_maintenance2, which are also usable, granted we transition the pair of
41 // depth/stencil layouts accordingly elsewhere in ANGLE.
42 return vk::ImageLayout::DepthStencilAttachment;
43 case GL_LAYOUT_SHADER_READ_ONLY_EXT:
44 return vk::ImageLayout::ExternalShadersReadOnly;
45 case GL_LAYOUT_TRANSFER_SRC_EXT:
46 return vk::ImageLayout::TransferSrc;
47 case GL_LAYOUT_TRANSFER_DST_EXT:
48 return vk::ImageLayout::TransferDst;
49 default:
50 UNREACHABLE();
51 return vk::ImageLayout::Undefined;
52 }
53 }
54 } // anonymous namespace
55
56 SemaphoreVk::SemaphoreVk() = default;
57
58 SemaphoreVk::~SemaphoreVk() = default;
59
onDestroy(const gl::Context * context)60 void SemaphoreVk::onDestroy(const gl::Context *context)
61 {
62 ContextVk *contextVk = vk::GetImpl(context);
63 contextVk->addGarbage(&mSemaphore);
64 }
65
importFd(gl::Context * context,gl::HandleType handleType,GLint fd)66 angle::Result SemaphoreVk::importFd(gl::Context *context, gl::HandleType handleType, GLint fd)
67 {
68 ContextVk *contextVk = vk::GetImpl(context);
69
70 switch (handleType)
71 {
72 case gl::HandleType::OpaqueFd:
73 return importOpaqueFd(contextVk, fd);
74
75 default:
76 ANGLE_VK_UNREACHABLE(contextVk);
77 return angle::Result::Stop;
78 }
79 }
80
importZirconHandle(gl::Context * context,gl::HandleType handleType,GLuint handle)81 angle::Result SemaphoreVk::importZirconHandle(gl::Context *context,
82 gl::HandleType handleType,
83 GLuint handle)
84 {
85 ContextVk *contextVk = vk::GetImpl(context);
86
87 switch (handleType)
88 {
89 case gl::HandleType::ZirconEvent:
90 return importZirconEvent(contextVk, handle);
91
92 default:
93 ANGLE_VK_UNREACHABLE(contextVk);
94 return angle::Result::Stop;
95 }
96 }
97
wait(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)98 angle::Result SemaphoreVk::wait(gl::Context *context,
99 const gl::BufferBarrierVector &bufferBarriers,
100 const gl::TextureBarrierVector &textureBarriers)
101 {
102 ContextVk *contextVk = vk::GetImpl(context);
103
104 if (!bufferBarriers.empty() || !textureBarriers.empty())
105 {
106 // Create one global memory barrier to cover all barriers.
107 ANGLE_TRY(contextVk->syncExternalMemory());
108 }
109
110 uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
111
112 if (!bufferBarriers.empty())
113 {
114 // Perform a queue ownership transfer for each buffer.
115 for (gl::Buffer *buffer : bufferBarriers)
116 {
117 BufferVk *bufferVk = vk::GetImpl(buffer);
118 VkDeviceSize bufferOffset = 0;
119 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
120
121 vk::CommandBuffer *commandBuffer;
122 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
123
124 // Queue ownership transfer.
125 bufferHelper.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL,
126 rendererQueueFamilyIndex, commandBuffer);
127 }
128 }
129
130 if (!textureBarriers.empty())
131 {
132 // Perform a queue ownership transfer for each texture. Additionally, we are being
133 // informed that the layout of the image has been externally transitioned, so we need to
134 // update our internal state tracking.
135 for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
136 {
137 TextureVk *textureVk = vk::GetImpl(textureAndLayout.texture);
138 vk::ImageHelper &image = textureVk->getImage();
139 vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
140
141 vk::CommandBuffer *commandBuffer;
142 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
143
144 // Image should not be accessed while unowned. Emulated formats may have staged updates
145 // to clear the image after initialization.
146 ASSERT(!image.hasStagedUpdatesInAllocatedLevels() ||
147 image.getFormat().hasEmulatedImageChannels());
148
149 // Queue ownership transfer and layout transition.
150 image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex,
151 layout, commandBuffer);
152 }
153 }
154
155 contextVk->addWaitSemaphore(mSemaphore.getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
156 return angle::Result::Continue;
157 }
158
signal(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)159 angle::Result SemaphoreVk::signal(gl::Context *context,
160 const gl::BufferBarrierVector &bufferBarriers,
161 const gl::TextureBarrierVector &textureBarriers)
162 {
163 ContextVk *contextVk = vk::GetImpl(context);
164
165 uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
166
167 if (!bufferBarriers.empty())
168 {
169 // Perform a queue ownership transfer for each buffer.
170 for (gl::Buffer *buffer : bufferBarriers)
171 {
172 BufferVk *bufferVk = vk::GetImpl(buffer);
173 VkDeviceSize bufferOffset = 0;
174 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
175
176 ANGLE_TRY(contextVk->onBufferReleaseToExternal(bufferHelper));
177 vk::CommandBuffer *commandBuffer;
178 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
179
180 // Queue ownership transfer.
181 bufferHelper.releaseToExternal(contextVk, rendererQueueFamilyIndex,
182 VK_QUEUE_FAMILY_EXTERNAL, commandBuffer);
183 }
184 }
185
186 if (!textureBarriers.empty())
187 {
188 // Perform a queue ownership transfer for each texture. Additionally, transition the image
189 // to the requested layout.
190 for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
191 {
192 TextureVk *textureVk = vk::GetImpl(textureAndLayout.texture);
193 vk::ImageHelper &image = textureVk->getImage();
194 vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
195
196 // Don't transition to Undefined layout. If external wants to transition the image away
197 // from Undefined after this operation, it's perfectly fine to keep the layout as is in
198 // ANGLE. Note that vk::ImageHelper doesn't expect transitions to Undefined.
199 if (layout == vk::ImageLayout::Undefined)
200 {
201 layout = image.getCurrentImageLayout();
202 }
203
204 ANGLE_TRY(textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
205
206 ANGLE_TRY(contextVk->onImageReleaseToExternal(image));
207 vk::CommandBuffer *commandBuffer;
208 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
209
210 // Queue ownership transfer and layout transition.
211 image.releaseToExternal(contextVk, rendererQueueFamilyIndex, VK_QUEUE_FAMILY_EXTERNAL,
212 layout, commandBuffer);
213 }
214 }
215
216 if (!bufferBarriers.empty() || !textureBarriers.empty())
217 {
218 // Create one global memory barrier to cover all barriers.
219 ANGLE_TRY(contextVk->syncExternalMemory());
220 }
221
222 return contextVk->flushImpl(&mSemaphore);
223 }
224
importOpaqueFd(ContextVk * contextVk,GLint fd)225 angle::Result SemaphoreVk::importOpaqueFd(ContextVk *contextVk, GLint fd)
226 {
227 RendererVk *renderer = contextVk->getRenderer();
228
229 if (!mSemaphore.valid())
230 {
231 mSemaphore.init(renderer->getDevice());
232 }
233
234 ASSERT(mSemaphore.valid());
235
236 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo = {};
237 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
238 importSemaphoreFdInfo.semaphore = mSemaphore.getHandle();
239 importSemaphoreFdInfo.flags = 0;
240 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
241 importSemaphoreFdInfo.fd = fd;
242
243 ANGLE_VK_TRY(contextVk, vkImportSemaphoreFdKHR(renderer->getDevice(), &importSemaphoreFdInfo));
244
245 return angle::Result::Continue;
246 }
247
importZirconEvent(ContextVk * contextVk,GLuint handle)248 angle::Result SemaphoreVk::importZirconEvent(ContextVk *contextVk, GLuint handle)
249 {
250 RendererVk *renderer = contextVk->getRenderer();
251
252 if (!mSemaphore.valid())
253 {
254 mSemaphore.init(renderer->getDevice());
255 }
256
257 ASSERT(mSemaphore.valid());
258
259 VkImportSemaphoreZirconHandleInfoFUCHSIA importSemaphoreZirconHandleInfo = {};
260 importSemaphoreZirconHandleInfo.sType =
261 VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA;
262 importSemaphoreZirconHandleInfo.semaphore = mSemaphore.getHandle();
263 importSemaphoreZirconHandleInfo.flags = 0;
264 importSemaphoreZirconHandleInfo.handleType =
265 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA;
266 importSemaphoreZirconHandleInfo.zirconHandle = handle;
267
268 // TODO(spang): Add vkImportSemaphoreZirconHandleFUCHSIA to volk.
269 static PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA =
270 reinterpret_cast<PFN_vkImportSemaphoreZirconHandleFUCHSIA>(
271 vkGetInstanceProcAddr(renderer->getInstance(), "vkImportSemaphoreZirconHandleFUCHSIA"));
272
273 ANGLE_VK_TRY(contextVk, vkImportSemaphoreZirconHandleFUCHSIA(renderer->getDevice(),
274 &importSemaphoreZirconHandleInfo));
275
276 return angle::Result::Continue;
277 }
278
279 } // namespace rx
280