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