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