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/vk_renderer.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 vk::Renderer *renderer = contextVk->getRenderer();
180
181 const vk::Format &vkFormat = renderer->getFormat(internalFormat);
182 angle::FormatID actualFormatID = vkFormat.getActualRenderableImageFormatID();
183
184 VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
185 externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
186 externalMemoryImageCreateInfo.pNext = imageCreateInfoPNext;
187 externalMemoryImageCreateInfo.handleTypes = ToVulkanHandleType(mHandleType);
188
189 VkExtent3D vkExtents;
190 uint32_t layerCount;
191 gl_vk::GetExtentsAndLayerCount(type, size, &vkExtents, &layerCount);
192
193 // ANGLE_external_objects_flags allows create flags to be specified by the application instead
194 // of getting defaulted to zero. Note that the GL enum values constituting the bits of
195 // |createFlags| are identical to their corresponding Vulkan value. There are no additional
196 // structs allowed to be chained to VkImageCreateInfo other than
197 // VkExternalMemoryImageCreateInfo.
198 bool hasProtectedContent = mProtectedMemory;
199 ANGLE_TRY(image->initExternal(
200 contextVk, type, vkExtents, vkFormat.getIntendedFormatID(), actualFormatID, 1, usageFlags,
201 createFlags, vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo,
202 gl::LevelIndex(0), static_cast<uint32_t>(levels), layerCount,
203 contextVk->isRobustResourceInitEnabled(), hasProtectedContent, vk::YcbcrConversionDesc{},
204 nullptr));
205
206 VkMemoryRequirements externalMemoryRequirements;
207 image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
208
209 const void *importMemoryInfo = nullptr;
210 VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {};
211 if (mDedicatedMemory)
212 {
213 memoryDedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
214 memoryDedicatedAllocateInfo.image = image->getImage().getHandle();
215 importMemoryInfo = &memoryDedicatedAllocateInfo;
216 }
217
218 VkImportMemoryFdInfoKHR importMemoryFdInfo = {};
219 VkImportMemoryZirconHandleInfoFUCHSIA importMemoryZirconHandleInfo = {};
220 switch (mHandleType)
221 {
222 case gl::HandleType::OpaqueFd:
223 ASSERT(mFd != kInvalidFd);
224 importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
225 importMemoryFdInfo.pNext = importMemoryInfo;
226 importMemoryFdInfo.handleType = ToVulkanHandleType(mHandleType);
227 importMemoryFdInfo.fd = dup(mFd);
228 importMemoryInfo = &importMemoryFdInfo;
229 break;
230 case gl::HandleType::ZirconVmo:
231 ASSERT(mZirconHandle != ZX_HANDLE_INVALID);
232 importMemoryZirconHandleInfo.sType =
233 VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA;
234 importMemoryZirconHandleInfo.pNext = importMemoryInfo;
235 importMemoryZirconHandleInfo.handleType = ToVulkanHandleType(mHandleType);
236 ANGLE_TRY(
237 DuplicateZirconVmo(contextVk, mZirconHandle, &importMemoryZirconHandleInfo.handle));
238 importMemoryInfo = &importMemoryZirconHandleInfo;
239 break;
240 default:
241 UNREACHABLE();
242 }
243
244 // TODO(jmadill, spang): Memory sub-allocation. http://anglebug.com/40096464
245 ASSERT(offset == 0);
246 ASSERT(externalMemoryRequirements.size == mSize);
247
248 VkMemoryPropertyFlags flags = hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0;
249 ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
250 externalMemoryRequirements, 1, &importMemoryInfo,
251 contextVk->getDeviceQueueIndex(), flags));
252
253 return angle::Result::Continue;
254 }
255
256 } // namespace rx
257