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 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
119
120 vk::CommandBuffer *commandBuffer;
121 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
122
123 // Queue ownership transfer.
124 bufferHelper.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL,
125 rendererQueueFamilyIndex, commandBuffer);
126 }
127 }
128
129 if (!textureBarriers.empty())
130 {
131 // Perform a queue ownership transfer for each texture. Additionally, we are being
132 // informed that the layout of the image has been externally transitioned, so we need to
133 // update our internal state tracking.
134 for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
135 {
136 TextureVk *textureVk = vk::GetImpl(textureAndLayout.texture);
137 vk::ImageHelper &image = textureVk->getImage();
138 vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
139
140 vk::CommandBuffer *commandBuffer;
141 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
142
143 // Image should not be accessed while unowned.
144 ASSERT(!textureVk->getImage().hasStagedUpdates());
145
146 // Queue ownership transfer and layout transition.
147 image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex,
148 layout, commandBuffer);
149 }
150 }
151
152 contextVk->addWaitSemaphore(mSemaphore.getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
153 return angle::Result::Continue;
154 }
155
signal(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)156 angle::Result SemaphoreVk::signal(gl::Context *context,
157 const gl::BufferBarrierVector &bufferBarriers,
158 const gl::TextureBarrierVector &textureBarriers)
159 {
160 ContextVk *contextVk = vk::GetImpl(context);
161
162 uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
163
164 if (!bufferBarriers.empty())
165 {
166 // Perform a queue ownership transfer for each buffer.
167 for (gl::Buffer *buffer : bufferBarriers)
168 {
169 BufferVk *bufferVk = vk::GetImpl(buffer);
170 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
171
172 vk::CommandBuffer *commandBuffer;
173 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
174
175 // Queue ownership transfer.
176 bufferHelper.releaseToExternal(contextVk, rendererQueueFamilyIndex,
177 VK_QUEUE_FAMILY_EXTERNAL, commandBuffer);
178 }
179 }
180
181 if (!textureBarriers.empty())
182 {
183 // Perform a queue ownership transfer for each texture. Additionally, transition the image
184 // to the requested layout.
185 for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
186 {
187 TextureVk *textureVk = vk::GetImpl(textureAndLayout.texture);
188 vk::ImageHelper &image = textureVk->getImage();
189 vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
190
191 // Don't transition to Undefined layout. If external wants to transition the image away
192 // from Undefined after this operation, it's perfectly fine to keep the layout as is in
193 // ANGLE. Note that vk::ImageHelper doesn't expect transitions to Undefined.
194 if (layout == vk::ImageLayout::Undefined)
195 {
196 layout = image.getCurrentImageLayout();
197 }
198
199 ANGLE_TRY(textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
200
201 vk::CommandBuffer *commandBuffer;
202 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
203
204 // Queue ownership transfer and layout transition.
205 image.releaseToExternal(contextVk, rendererQueueFamilyIndex, VK_QUEUE_FAMILY_EXTERNAL,
206 layout, commandBuffer);
207 }
208 }
209
210 if (!bufferBarriers.empty() || !textureBarriers.empty())
211 {
212 // Create one global memory barrier to cover all barriers.
213 ANGLE_TRY(contextVk->syncExternalMemory());
214 }
215
216 return contextVk->flushImpl(&mSemaphore);
217 }
218
importOpaqueFd(ContextVk * contextVk,GLint fd)219 angle::Result SemaphoreVk::importOpaqueFd(ContextVk *contextVk, GLint fd)
220 {
221 RendererVk *renderer = contextVk->getRenderer();
222
223 if (!mSemaphore.valid())
224 {
225 mSemaphore.init(renderer->getDevice());
226 }
227
228 ASSERT(mSemaphore.valid());
229
230 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo = {};
231 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
232 importSemaphoreFdInfo.semaphore = mSemaphore.getHandle();
233 importSemaphoreFdInfo.flags = 0;
234 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
235 importSemaphoreFdInfo.fd = fd;
236
237 ANGLE_VK_TRY(contextVk, vkImportSemaphoreFdKHR(renderer->getDevice(), &importSemaphoreFdInfo));
238
239 return angle::Result::Continue;
240 }
241
importZirconEvent(ContextVk * contextVk,GLuint handle)242 angle::Result SemaphoreVk::importZirconEvent(ContextVk *contextVk, GLuint handle)
243 {
244 RendererVk *renderer = contextVk->getRenderer();
245
246 if (!mSemaphore.valid())
247 {
248 mSemaphore.init(renderer->getDevice());
249 }
250
251 ASSERT(mSemaphore.valid());
252
253 VkImportSemaphoreZirconHandleInfoFUCHSIA importSemaphoreZirconHandleInfo = {};
254 importSemaphoreZirconHandleInfo.sType =
255 VK_STRUCTURE_TYPE_TEMP_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA;
256 importSemaphoreZirconHandleInfo.semaphore = mSemaphore.getHandle();
257 importSemaphoreZirconHandleInfo.flags = 0;
258 importSemaphoreZirconHandleInfo.handleType =
259 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA;
260 importSemaphoreZirconHandleInfo.handle = handle;
261
262 // TODO(spang): Add vkImportSemaphoreZirconHandleFUCHSIA to volk.
263 static PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA =
264 reinterpret_cast<PFN_vkImportSemaphoreZirconHandleFUCHSIA>(
265 vkGetInstanceProcAddr(renderer->getInstance(), "vkImportSemaphoreZirconHandleFUCHSIA"));
266
267 ANGLE_VK_TRY(contextVk, vkImportSemaphoreZirconHandleFUCHSIA(renderer->getDevice(),
268 &importSemaphoreZirconHandleInfo));
269
270 return angle::Result::Continue;
271 }
272
273 } // namespace rx
274