• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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