• 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.changeQueue(rendererQueueFamilyIndex, commandBuffer);
125         }
126     }
127 
128     if (!textureBarriers.empty())
129     {
130         // Perform a queue ownership transfer for each texture.  Additionally, we are being
131         // informed that the layout of the image has been externally transitioned, so we need to
132         // update our internal state tracking.
133         for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
134         {
135             TextureVk *textureVk   = vk::GetImpl(textureAndLayout.texture);
136             vk::ImageHelper &image = textureVk->getImage();
137             vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
138 
139             // Inform the image that the layout has been externally changed.
140             image.onExternalLayoutChange(layout);
141 
142             vk::CommandBuffer *commandBuffer;
143             ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
144 
145             // Queue ownership transfer.
146             image.changeLayoutAndQueue(image.getAspectFlags(), layout, rendererQueueFamilyIndex,
147                                        commandBuffer);
148         }
149     }
150 
151     contextVk->insertWaitSemaphore(&mSemaphore);
152     return angle::Result::Continue;
153 }
154 
signal(gl::Context * context,const gl::BufferBarrierVector & bufferBarriers,const gl::TextureBarrierVector & textureBarriers)155 angle::Result SemaphoreVk::signal(gl::Context *context,
156                                   const gl::BufferBarrierVector &bufferBarriers,
157                                   const gl::TextureBarrierVector &textureBarriers)
158 {
159     ContextVk *contextVk = vk::GetImpl(context);
160 
161     if (!bufferBarriers.empty())
162     {
163         // Perform a queue ownership transfer for each buffer.
164         for (gl::Buffer *buffer : bufferBarriers)
165         {
166             BufferVk *bufferVk             = vk::GetImpl(buffer);
167             vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
168 
169             vk::CommandBuffer *commandBuffer;
170             ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
171 
172             // Queue ownership transfer.
173             bufferHelper.changeQueue(VK_QUEUE_FAMILY_EXTERNAL, commandBuffer);
174         }
175     }
176 
177     if (!textureBarriers.empty())
178     {
179         // Perform a queue ownership transfer for each texture.  Additionally, transition the image
180         // to the requested layout.
181         for (const gl::TextureAndLayout &textureAndLayout : textureBarriers)
182         {
183             TextureVk *textureVk   = vk::GetImpl(textureAndLayout.texture);
184             vk::ImageHelper &image = textureVk->getImage();
185             vk::ImageLayout layout = GetVulkanImageLayout(textureAndLayout.layout);
186 
187             // Don't transition to Undefined layout.  If external wants to transition the image away
188             // from Undefined after this operation, it's perfectly fine to keep the layout as is in
189             // ANGLE.  Note that vk::ImageHelper doesn't expect transitions to Undefined.
190             if (layout == vk::ImageLayout::Undefined)
191             {
192                 layout = image.getCurrentImageLayout();
193             }
194 
195             vk::CommandBuffer *commandBuffer;
196             ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
197 
198             // Queue ownership transfer and layout transition.
199             image.changeLayoutAndQueue(image.getAspectFlags(), layout, VK_QUEUE_FAMILY_EXTERNAL,
200                                        commandBuffer);
201         }
202     }
203 
204     if (!bufferBarriers.empty() || !textureBarriers.empty())
205     {
206         // Create one global memory barrier to cover all barriers.
207         ANGLE_TRY(contextVk->syncExternalMemory());
208     }
209 
210     return contextVk->flushImpl(&mSemaphore);
211 }
212 
importOpaqueFd(ContextVk * contextVk,GLint fd)213 angle::Result SemaphoreVk::importOpaqueFd(ContextVk *contextVk, GLint fd)
214 {
215     RendererVk *renderer = contextVk->getRenderer();
216 
217     if (!mSemaphore.valid())
218     {
219         mSemaphore.init(renderer->getDevice());
220     }
221 
222     ASSERT(mSemaphore.valid());
223 
224     VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo = {};
225     importSemaphoreFdInfo.sType      = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
226     importSemaphoreFdInfo.semaphore  = mSemaphore.getHandle();
227     importSemaphoreFdInfo.flags      = 0;
228     importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
229     importSemaphoreFdInfo.fd         = fd;
230 
231     ANGLE_VK_TRY(contextVk, vkImportSemaphoreFdKHR(renderer->getDevice(), &importSemaphoreFdInfo));
232 
233     return angle::Result::Continue;
234 }
235 
importZirconEvent(ContextVk * contextVk,GLuint handle)236 angle::Result SemaphoreVk::importZirconEvent(ContextVk *contextVk, GLuint handle)
237 {
238     RendererVk *renderer = contextVk->getRenderer();
239 
240     if (!mSemaphore.valid())
241     {
242         mSemaphore.init(renderer->getDevice());
243     }
244 
245     ASSERT(mSemaphore.valid());
246 
247     VkImportSemaphoreZirconHandleInfoFUCHSIA importSemaphoreZirconHandleInfo = {};
248     importSemaphoreZirconHandleInfo.sType =
249         VK_STRUCTURE_TYPE_TEMP_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA;
250     importSemaphoreZirconHandleInfo.semaphore = mSemaphore.getHandle();
251     importSemaphoreZirconHandleInfo.flags     = 0;
252     importSemaphoreZirconHandleInfo.handleType =
253         VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA;
254     importSemaphoreZirconHandleInfo.handle = handle;
255 
256     // TODO(spang): Add vkImportSemaphoreZirconHandleFUCHSIA to volk.
257     static PFN_vkImportSemaphoreZirconHandleFUCHSIA vkImportSemaphoreZirconHandleFUCHSIA =
258         reinterpret_cast<PFN_vkImportSemaphoreZirconHandleFUCHSIA>(
259             vkGetInstanceProcAddr(renderer->getInstance(), "vkImportSemaphoreZirconHandleFUCHSIA"));
260 
261     ANGLE_VK_TRY(contextVk, vkImportSemaphoreZirconHandleFUCHSIA(renderer->getDevice(),
262                                                                  &importSemaphoreZirconHandleInfo));
263 
264     return angle::Result::Continue;
265 }
266 
267 }  // namespace rx
268