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