• 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 SemaphoreVk::SemaphoreVk() = default;
21 
22 SemaphoreVk::~SemaphoreVk() = default;
23 
onDestroy(const gl::Context * context)24 void SemaphoreVk::onDestroy(const gl::Context *context)
25 {
26     ContextVk *contextVk = vk::GetImpl(context);
27     contextVk->addGarbage(&mSemaphore);
28 }
29 
importFd(gl::Context * context,gl::HandleType handleType,GLint fd)30 angle::Result SemaphoreVk::importFd(gl::Context *context, gl::HandleType handleType, GLint fd)
31 {
32     ContextVk *contextVk = vk::GetImpl(context);
33 
34     switch (handleType)
35     {
36         case gl::HandleType::OpaqueFd:
37             return importOpaqueFd(contextVk, fd);
38 
39         default:
40             ANGLE_VK_UNREACHABLE(contextVk);
41             return angle::Result::Stop;
42     }
43 }
44 
importZirconHandle(gl::Context * context,gl::HandleType handleType,GLuint handle)45 angle::Result SemaphoreVk::importZirconHandle(gl::Context *context,
46                                               gl::HandleType handleType,
47                                               GLuint handle)
48 {
49     ContextVk *contextVk = vk::GetImpl(context);
50 
51     switch (handleType)
52     {
53         case gl::HandleType::ZirconEvent:
54             return importZirconEvent(contextVk, handle);
55 
56         default:
57             ANGLE_VK_UNREACHABLE(contextVk);
58             return angle::Result::Stop;
59     }
60 }
61 
wait(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)62 angle::Result SemaphoreVk::wait(gl::Context *context,
63                                 const gl::BufferBarrierVector &bufferBarriers,
64                                 const gl::TextureBarrierVector &textureBarriers)
65 {
66     ContextVk *contextVk = vk::GetImpl(context);
67 
68     if (!bufferBarriers.empty() || !textureBarriers.empty())
69     {
70         // Create one global memory barrier to cover all barriers.
71         ANGLE_TRY(contextVk->syncExternalMemory());
72     }
73 
74     uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
75 
76     if (!bufferBarriers.empty())
77     {
78         // Perform a queue ownership transfer for each buffer.
79         for (gl::Buffer *buffer : bufferBarriers)
80         {
81             BufferVk *bufferVk             = vk::GetImpl(buffer);
82             vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
83 
84             vk::OutsideRenderPassCommandBuffer *commandBuffer;
85             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
86 
87             // Queue ownership transfer.
88             bufferHelper.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL,
89                                              rendererQueueFamilyIndex, commandBuffer);
90         }
91     }
92 
93     if (!textureBarriers.empty())
94     {
95         // Perform a queue ownership transfer for each texture.  Additionally, we are being
96         // informed that the layout of the image has been externally transitioned, so we need to
97         // update our internal state tracking.
98         for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
99         {
100             TextureVk *textureVk   = vk::GetImpl(textureBarrier.texture);
101             vk::ImageHelper &image = textureVk->getImage();
102             vk::ImageLayout layout = vk::GetImageLayoutFromGLImageLayout(textureBarrier.layout);
103 
104             vk::OutsideRenderPassCommandBuffer *commandBuffer;
105             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
106 
107             // Image should not be accessed while unowned. Emulated formats may have staged updates
108             // to clear the image after initialization.
109             ASSERT(!image.hasStagedUpdatesInAllocatedLevels() || image.hasEmulatedImageChannels());
110 
111             // Queue ownership transfer and layout transition.
112             image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex,
113                                       layout, commandBuffer);
114         }
115     }
116 
117     contextVk->addWaitSemaphore(mSemaphore.getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
118     return angle::Result::Continue;
119 }
120 
signal(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)121 angle::Result SemaphoreVk::signal(gl::Context *context,
122                                   const gl::BufferBarrierVector &bufferBarriers,
123                                   const gl::TextureBarrierVector &textureBarriers)
124 {
125     ContextVk *contextVk = vk::GetImpl(context);
126     RendererVk *renderer = contextVk->getRenderer();
127 
128     uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
129 
130     if (!bufferBarriers.empty())
131     {
132         // Perform a queue ownership transfer for each buffer.
133         for (gl::Buffer *buffer : bufferBarriers)
134         {
135             BufferVk *bufferVk             = vk::GetImpl(buffer);
136             vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
137 
138             ANGLE_TRY(contextVk->onBufferReleaseToExternal(bufferHelper));
139             vk::OutsideRenderPassCommandBuffer *commandBuffer;
140             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
141 
142             // Queue ownership transfer.
143             bufferHelper.releaseToExternal(contextVk, rendererQueueFamilyIndex,
144                                            VK_QUEUE_FAMILY_EXTERNAL, commandBuffer);
145         }
146     }
147 
148     if (!textureBarriers.empty())
149     {
150         // Perform a queue ownership transfer for each texture.  Additionally, transition the image
151         // to the requested layout.
152         for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
153         {
154             TextureVk *textureVk   = vk::GetImpl(textureBarrier.texture);
155             vk::ImageHelper &image = textureVk->getImage();
156             vk::ImageLayout layout = vk::GetImageLayoutFromGLImageLayout(textureBarrier.layout);
157 
158             // Don't transition to Undefined layout.  If external wants to transition the image away
159             // from Undefined after this operation, it's perfectly fine to keep the layout as is in
160             // ANGLE.  Note that vk::ImageHelper doesn't expect transitions to Undefined.
161             if (layout == vk::ImageLayout::Undefined)
162             {
163                 layout = image.getCurrentImageLayout();
164             }
165 
166             ANGLE_TRY(textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
167 
168             ANGLE_TRY(contextVk->onImageReleaseToExternal(image));
169             vk::OutsideRenderPassCommandBuffer *commandBuffer;
170             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
171 
172             // Queue ownership transfer and layout transition.
173             image.releaseToExternal(contextVk, rendererQueueFamilyIndex, VK_QUEUE_FAMILY_EXTERNAL,
174                                     layout, commandBuffer);
175         }
176     }
177 
178     if (!bufferBarriers.empty() || !textureBarriers.empty())
179     {
180         // Create one global memory barrier to cover all barriers.
181         ANGLE_TRY(contextVk->syncExternalMemory());
182     }
183 
184     ANGLE_TRY(contextVk->flushImpl(&mSemaphore, RenderPassClosureReason::ExternalSemaphoreSignal));
185 
186     // The external has asked for the semaphore to be signaled.  It will wait on this semaphore and
187     // so we must ensure that the above flush (resulting in vkQueueSubmit) has actually been
188     // submitted (as opposed to simply being scheduled as a task for another thread).  Per the
189     // Vulkan spec:
190     //
191     // > ... when a semaphore wait operation is submitted to a queue:
192     // >
193     // > - A binary semaphore must be signaled, or have an associated semaphore signal operation
194     // >   that is pending execution.
195     //
196     return renderer->ensureNoPendingWork(contextVk);
197 }
198 
importOpaqueFd(ContextVk * contextVk,GLint fd)199 angle::Result SemaphoreVk::importOpaqueFd(ContextVk *contextVk, GLint fd)
200 {
201     RendererVk *renderer = contextVk->getRenderer();
202 
203     if (!mSemaphore.valid())
204     {
205         mSemaphore.init(renderer->getDevice());
206     }
207 
208     ASSERT(mSemaphore.valid());
209 
210     VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo = {};
211     importSemaphoreFdInfo.sType      = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
212     importSemaphoreFdInfo.semaphore  = mSemaphore.getHandle();
213     importSemaphoreFdInfo.flags      = 0;
214     importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
215     importSemaphoreFdInfo.fd         = fd;
216 
217     ANGLE_VK_TRY(contextVk, vkImportSemaphoreFdKHR(renderer->getDevice(), &importSemaphoreFdInfo));
218 
219     return angle::Result::Continue;
220 }
221 
importZirconEvent(ContextVk * contextVk,GLuint handle)222 angle::Result SemaphoreVk::importZirconEvent(ContextVk *contextVk, GLuint handle)
223 {
224     RendererVk *renderer = contextVk->getRenderer();
225 
226     if (!mSemaphore.valid())
227     {
228         mSemaphore.init(renderer->getDevice());
229     }
230 
231     ASSERT(mSemaphore.valid());
232 
233     VkImportSemaphoreZirconHandleInfoFUCHSIA importSemaphoreZirconHandleInfo = {};
234     importSemaphoreZirconHandleInfo.sType =
235         VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA;
236     importSemaphoreZirconHandleInfo.semaphore = mSemaphore.getHandle();
237     importSemaphoreZirconHandleInfo.flags     = 0;
238     importSemaphoreZirconHandleInfo.handleType =
239         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA;
240     importSemaphoreZirconHandleInfo.zirconHandle = handle;
241 
242     // TODO(spang): Add vkImportSemaphoreZirconHandleFUCHSIA to volk.
243     static PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA =
244         reinterpret_cast<PFN_vkImportSemaphoreZirconHandleFUCHSIA>(
245             vkGetInstanceProcAddr(renderer->getInstance(), "vkImportSemaphoreZirconHandleFUCHSIA"));
246 
247     ANGLE_VK_TRY(contextVk, vkImportSemaphoreZirconHandleFUCHSIA(renderer->getDevice(),
248                                                                  &importSemaphoreZirconHandleInfo));
249 
250     return angle::Result::Continue;
251 }
252 
253 }  // namespace rx
254