• 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 // MemoryObjectVk.cpp: Defines the class interface for MemoryObjectVk, implementing
6 // MemoryObjectImpl.
7 
8 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
9 
10 #include "common/debug.h"
11 #include "common/vulkan/vk_headers.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/renderer/vulkan/ContextVk.h"
14 #include "libANGLE/renderer/vulkan/RendererVk.h"
15 #include "vulkan/vulkan_fuchsia_ext.h"
16 
17 #if !defined(ANGLE_PLATFORM_WINDOWS)
18 #    include <unistd.h>
19 #else
20 #    include <io.h>
21 #endif
22 
23 #if defined(ANGLE_PLATFORM_FUCHSIA)
24 #    include <zircon/status.h>
25 #    include <zircon/syscalls.h>
26 #endif
27 
28 namespace rx
29 {
30 
31 namespace
32 {
33 
34 #if defined(ANGLE_PLATFORM_WINDOWS)
close(int fd)35 int close(int fd)
36 {
37     return _close(fd);
38 }
39 #endif
40 
CloseZirconVmo(zx_handle_t handle)41 void CloseZirconVmo(zx_handle_t handle)
42 {
43 #if defined(ANGLE_PLATFORM_FUCHSIA)
44     zx_handle_close(handle);
45 #else
46     UNREACHABLE();
47 #endif
48 }
49 
DuplicateZirconVmo(ContextVk * contextVk,zx_handle_t handle,zx_handle_t * duplicate)50 angle::Result DuplicateZirconVmo(ContextVk *contextVk, zx_handle_t handle, zx_handle_t *duplicate)
51 {
52 #if defined(ANGLE_PLATFORM_FUCHSIA)
53     zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, duplicate);
54     ANGLE_VK_CHECK(contextVk, status == ZX_OK, VK_ERROR_INVALID_EXTERNAL_HANDLE);
55     return angle::Result::Continue;
56 #else
57     UNREACHABLE();
58     return angle::Result::Stop;
59 #endif
60 }
61 
ToVulkanHandleType(gl::HandleType handleType)62 VkExternalMemoryHandleTypeFlagBits ToVulkanHandleType(gl::HandleType handleType)
63 {
64     switch (handleType)
65     {
66         case gl::HandleType::OpaqueFd:
67             return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
68         case gl::HandleType::ZirconVmo:
69             return VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
70         default:
71             // Not a memory handle type.
72             UNREACHABLE();
73             return VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
74     }
75 }
76 
77 }  // namespace
78 
MemoryObjectVk()79 MemoryObjectVk::MemoryObjectVk() {}
80 
81 MemoryObjectVk::~MemoryObjectVk() = default;
82 
onDestroy(const gl::Context * context)83 void MemoryObjectVk::onDestroy(const gl::Context *context)
84 {
85     if (mFd != kInvalidFd)
86     {
87         close(mFd);
88         mFd = kInvalidFd;
89     }
90 
91     if (mZirconHandle != ZX_HANDLE_INVALID)
92     {
93         CloseZirconVmo(mZirconHandle);
94         mZirconHandle = ZX_HANDLE_INVALID;
95     }
96 }
97 
setDedicatedMemory(const gl::Context * context,bool dedicatedMemory)98 angle::Result MemoryObjectVk::setDedicatedMemory(const gl::Context *context, bool dedicatedMemory)
99 {
100     mDedicatedMemory = dedicatedMemory;
101     return angle::Result::Continue;
102 }
103 
setProtectedMemory(const gl::Context * context,bool protectedMemory)104 angle::Result MemoryObjectVk::setProtectedMemory(const gl::Context *context, bool protectedMemory)
105 {
106     mProtectedMemory = protectedMemory;
107     return angle::Result::Continue;
108 }
109 
importFd(gl::Context * context,GLuint64 size,gl::HandleType handleType,GLint fd)110 angle::Result MemoryObjectVk::importFd(gl::Context *context,
111                                        GLuint64 size,
112                                        gl::HandleType handleType,
113                                        GLint fd)
114 {
115     ContextVk *contextVk = vk::GetImpl(context);
116 
117     switch (handleType)
118     {
119         case gl::HandleType::OpaqueFd:
120             return importOpaqueFd(contextVk, size, fd);
121 
122         default:
123             UNREACHABLE();
124             return angle::Result::Stop;
125     }
126 }
127 
importZirconHandle(gl::Context * context,GLuint64 size,gl::HandleType handleType,GLuint handle)128 angle::Result MemoryObjectVk::importZirconHandle(gl::Context *context,
129                                                  GLuint64 size,
130                                                  gl::HandleType handleType,
131                                                  GLuint handle)
132 {
133     ContextVk *contextVk = vk::GetImpl(context);
134 
135     switch (handleType)
136     {
137         case gl::HandleType::ZirconVmo:
138             return importZirconVmo(contextVk, size, handle);
139 
140         default:
141             UNREACHABLE();
142             return angle::Result::Stop;
143     }
144 }
145 
importOpaqueFd(ContextVk * contextVk,GLuint64 size,GLint fd)146 angle::Result MemoryObjectVk::importOpaqueFd(ContextVk *contextVk, GLuint64 size, GLint fd)
147 {
148     ASSERT(mHandleType == gl::HandleType::InvalidEnum);
149     ASSERT(mFd == kInvalidFd);
150     ASSERT(fd != kInvalidFd);
151     mHandleType = gl::HandleType::OpaqueFd;
152     mFd         = fd;
153     mSize       = size;
154     return angle::Result::Continue;
155 }
156 
importZirconVmo(ContextVk * contextVk,GLuint64 size,GLuint handle)157 angle::Result MemoryObjectVk::importZirconVmo(ContextVk *contextVk, GLuint64 size, GLuint handle)
158 {
159     ASSERT(mHandleType == gl::HandleType::InvalidEnum);
160     ASSERT(mZirconHandle == ZX_HANDLE_INVALID);
161     ASSERT(handle != ZX_HANDLE_INVALID);
162     mHandleType   = gl::HandleType::ZirconVmo;
163     mZirconHandle = handle;
164     mSize         = size;
165     return angle::Result::Continue;
166 }
167 
createImage(ContextVk * contextVk,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,GLuint64 offset,vk::ImageHelper * image,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)168 angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
169                                           gl::TextureType type,
170                                           size_t levels,
171                                           GLenum internalFormat,
172                                           const gl::Extents &size,
173                                           GLuint64 offset,
174                                           vk::ImageHelper *image,
175                                           GLbitfield createFlags,
176                                           GLbitfield usageFlags,
177                                           const void *imageCreateInfoPNext)
178 {
179     RendererVk *renderer = contextVk->getRenderer();
180 
181     const vk::Format &vkFormat     = renderer->getFormat(internalFormat);
182     angle::FormatID actualFormatID = vkFormat.getActualRenderableImageFormatID();
183 
184     // EXT_external_objects issue 13 says that all supported usage flags must be specified.
185     // However, ANGLE_external_objects_flags allows these flags to be masked.  Note that the GL enum
186     // values constituting the bits of |usageFlags| are identical to their corresponding Vulkan
187     // value.
188     const VkImageUsageFlags imageUsageFlags =
189         vk::GetMaximalImageUsageFlags(renderer, actualFormatID) & usageFlags;
190 
191     VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
192     externalMemoryImageCreateInfo.sType       = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
193     externalMemoryImageCreateInfo.pNext       = imageCreateInfoPNext;
194     externalMemoryImageCreateInfo.handleTypes = ToVulkanHandleType(mHandleType);
195 
196     VkExtent3D vkExtents;
197     uint32_t layerCount;
198     gl_vk::GetExtentsAndLayerCount(type, size, &vkExtents, &layerCount);
199 
200     // ANGLE_external_objects_flags allows create flags to be specified by the application instead
201     // of getting defaulted to zero.  Note that the GL enum values constituting the bits of
202     // |createFlags| are identical to their corresponding Vulkan value.  There are no additional
203     // structs allowed to be chained to VkImageCreateInfo other than
204     // VkExternalMemoryImageCreateInfo.
205     bool hasProtectedContent = mProtectedMemory;
206     ANGLE_TRY(image->initExternal(
207         contextVk, type, vkExtents, vkFormat.getIntendedFormatID(), actualFormatID, 1,
208         imageUsageFlags, createFlags, vk::ImageLayout::ExternalPreInitialized,
209         &externalMemoryImageCreateInfo, gl::LevelIndex(0), static_cast<uint32_t>(levels),
210         layerCount, contextVk->isRobustResourceInitEnabled(), hasProtectedContent));
211 
212     VkMemoryRequirements externalMemoryRequirements;
213     image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
214 
215     const void *importMemoryInfo                              = nullptr;
216     VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {};
217     if (mDedicatedMemory)
218     {
219         memoryDedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
220         memoryDedicatedAllocateInfo.image = image->getImage().getHandle();
221         importMemoryInfo                  = &memoryDedicatedAllocateInfo;
222     }
223 
224     VkImportMemoryFdInfoKHR importMemoryFdInfo                         = {};
225     VkImportMemoryZirconHandleInfoFUCHSIA importMemoryZirconHandleInfo = {};
226     switch (mHandleType)
227     {
228         case gl::HandleType::OpaqueFd:
229             ASSERT(mFd != kInvalidFd);
230             importMemoryFdInfo.sType      = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
231             importMemoryFdInfo.pNext      = importMemoryInfo;
232             importMemoryFdInfo.handleType = ToVulkanHandleType(mHandleType);
233             importMemoryFdInfo.fd         = dup(mFd);
234             importMemoryInfo              = &importMemoryFdInfo;
235             break;
236         case gl::HandleType::ZirconVmo:
237             ASSERT(mZirconHandle != ZX_HANDLE_INVALID);
238             importMemoryZirconHandleInfo.sType =
239                 VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA;
240             importMemoryZirconHandleInfo.pNext      = importMemoryInfo;
241             importMemoryZirconHandleInfo.handleType = ToVulkanHandleType(mHandleType);
242             ANGLE_TRY(
243                 DuplicateZirconVmo(contextVk, mZirconHandle, &importMemoryZirconHandleInfo.handle));
244             importMemoryInfo = &importMemoryZirconHandleInfo;
245             break;
246         default:
247             UNREACHABLE();
248     }
249 
250     // TODO(jmadill, spang): Memory sub-allocation. http://anglebug.com/2162
251     ASSERT(offset == 0);
252     ASSERT(externalMemoryRequirements.size <= mSize);
253 
254     VkMemoryPropertyFlags flags = hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0;
255     ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
256                                         externalMemoryRequirements, 1, &importMemoryInfo,
257                                         renderer->getQueueFamilyIndex(), flags));
258 
259     return angle::Result::Continue;
260 }
261 
262 }  // namespace rx
263