• 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             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