• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CLPlatformVk.cpp: Implements the class methods for CLPlatformVk.
7 
8 #include "libANGLE/renderer/vulkan/CLPlatformVk.h"
9 #include "common/vulkan/vulkan_icd.h"
10 #include "libANGLE/angletypes.h"
11 #include "libANGLE/renderer/vulkan/CLContextVk.h"
12 #include "libANGLE/renderer/vulkan/CLDeviceVk.h"
13 #include "libANGLE/renderer/vulkan/vk_renderer.h"
14 
15 #include "libANGLE/CLPlatform.h"
16 #include "libANGLE/cl_utils.h"
17 
18 #include "anglebase/no_destructor.h"
19 #include "common/angle_version_info.h"
20 #include "libANGLE/renderer/vulkan/vk_utils.h"
21 #include "vulkan/vulkan_core.h"
22 
23 namespace rx
24 {
25 
26 namespace
27 {
28 
CreateExtensionString(const NameVersionVector & extList)29 std::string CreateExtensionString(const NameVersionVector &extList)
30 {
31     std::string extensions;
32     for (const cl_name_version &ext : extList)
33     {
34         extensions += ext.name;
35         extensions += ' ';
36     }
37     if (!extensions.empty())
38     {
39         extensions.pop_back();
40     }
41     return extensions;
42 }
43 
44 }  // namespace
45 
initBackendRenderer()46 angle::Result CLPlatformVk::initBackendRenderer()
47 {
48     ASSERT(mRenderer != nullptr);
49 
50     ANGLE_TRY(mRenderer->initialize(this, this, angle::vk::ICD::Default, 0, 0,
51                                     vk::UseValidationLayers::YesIfAvailable, getWSIExtension(),
52                                     getWSILayer(), getWindowSystem(), angle::FeatureOverrides{}));
53 
54     return angle::Result::Continue;
55 }
56 
~CLPlatformVk()57 CLPlatformVk::~CLPlatformVk()
58 {
59     ASSERT(mRenderer);
60     mRenderer->onDestroy(this);
61     delete mRenderer;
62 }
63 
createInfo() const64 CLPlatformImpl::Info CLPlatformVk::createInfo() const
65 {
66     NameVersionVector extList = {
67         cl_name_version{CL_MAKE_VERSION(3, 0, 0), "cl_khr_icd"},
68         cl_name_version{CL_MAKE_VERSION(3, 0, 0), "cl_khr_extended_versioning"}};
69 
70     Info info;
71     info.name.assign("ANGLE Vulkan");
72     info.profile.assign("FULL_PROFILE");
73     info.versionStr.assign(GetVersionString());
74     info.hostTimerRes          = 0u;
75     info.extensionsWithVersion = std::move(extList);
76     info.version               = GetVersion();
77     info.initializeExtensions(CreateExtensionString(extList));
78     return info;
79 }
80 
createDevices() const81 CLDeviceImpl::CreateDatas CLPlatformVk::createDevices() const
82 {
83     CLDeviceImpl::CreateDatas createDatas;
84 
85     // Convert Vk device type to CL equivalent
86     cl_device_type type = CL_DEVICE_TYPE_DEFAULT;
87     switch (mRenderer->getPhysicalDeviceProperties().deviceType)
88     {
89         case VK_PHYSICAL_DEVICE_TYPE_CPU:
90             type |= CL_DEVICE_TYPE_CPU;
91             break;
92         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
93         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
94         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
95             type |= CL_DEVICE_TYPE_GPU;
96             break;
97         case VK_PHYSICAL_DEVICE_TYPE_OTHER:
98         case VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM:
99             // The default OpenCL device must not be a CL_DEVICE_TYPE_CUSTOM device.
100             // Thus, we override type bitfield to custom only.
101             type = CL_DEVICE_TYPE_CUSTOM;
102             break;
103     }
104 
105     createDatas.emplace_back(type, [this](const cl::Device &device) {
106         return CLDeviceVk::Ptr(new CLDeviceVk(device, mRenderer));
107     });
108     return createDatas;
109 }
110 
createContext(cl::Context & context,const cl::DevicePtrs & devices,bool userSync,CLContextImpl::Ptr * contextOut)111 angle::Result CLPlatformVk::createContext(cl::Context &context,
112                                           const cl::DevicePtrs &devices,
113                                           bool userSync,
114                                           CLContextImpl::Ptr *contextOut)
115 {
116     *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices));
117     if (*contextOut == nullptr)
118     {
119         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
120     }
121     return angle::Result::Continue;
122 }
123 
createContextFromType(cl::Context & context,cl::DeviceType deviceType,bool userSync,CLContextImpl::Ptr * contextOut)124 angle::Result CLPlatformVk::createContextFromType(cl::Context &context,
125                                                   cl::DeviceType deviceType,
126                                                   bool userSync,
127                                                   CLContextImpl::Ptr *contextOut)
128 {
129     const VkPhysicalDeviceType &vkPhysicalDeviceType =
130         getRenderer()->getPhysicalDeviceProperties().deviceType;
131 
132     if (deviceType.isSet(CL_DEVICE_TYPE_CPU) && vkPhysicalDeviceType != VK_PHYSICAL_DEVICE_TYPE_CPU)
133     {
134         ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
135     }
136     else if (deviceType.isSet(CL_DEVICE_TYPE_GPU))
137     {
138         switch (vkPhysicalDeviceType)
139         {
140             case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
141             case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
142             case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
143                 break;
144             default:
145                 ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
146         }
147     }
148     else
149     {
150         ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
151     }
152 
153     cl::DevicePtrs devices;
154     for (const auto &platformDevice : mPlatform.getDevices())
155     {
156         const auto &platformDeviceInfo = platformDevice->getInfo();
157         if (platformDeviceInfo.type.isSet(deviceType))
158         {
159             devices.push_back(platformDevice);
160         }
161     }
162 
163     *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices));
164     if (*contextOut == nullptr)
165     {
166         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
167     }
168     return angle::Result::Continue;
169 }
170 
unloadCompiler()171 angle::Result CLPlatformVk::unloadCompiler()
172 {
173     return angle::Result::Continue;
174 }
175 
Initialize(CreateFuncs & createFuncs)176 void CLPlatformVk::Initialize(CreateFuncs &createFuncs)
177 {
178     createFuncs.emplace_back([](const cl::Platform &platform) -> CLPlatformImpl::Ptr {
179         CLPlatformVk::Ptr platformVk = CLPlatformVk::Ptr(new (std::nothrow) CLPlatformVk(platform));
180         if (platformVk == nullptr || IsError(platformVk->initBackendRenderer()))
181         {
182             return Ptr(nullptr);
183         }
184         return Ptr(std::move(platformVk));
185     });
186 }
187 
GetVersionString()188 const std::string &CLPlatformVk::GetVersionString()
189 {
190     static const angle::base::NoDestructor<const std::string> sVersion(
191         "OpenCL " + std::to_string(CL_VERSION_MAJOR(GetVersion())) + "." +
192         std::to_string(CL_VERSION_MINOR(GetVersion())) + " ANGLE " +
193         angle::GetANGLEVersionString());
194     return *sVersion;
195 }
196 
CLPlatformVk(const cl::Platform & platform)197 CLPlatformVk::CLPlatformVk(const cl::Platform &platform)
198     : CLPlatformImpl(platform), vk::Context(new vk::Renderer()), mBlobCache(1024 * 1024)
199 {}
200 
handleError(VkResult result,const char * file,const char * function,unsigned int line)201 void CLPlatformVk::handleError(VkResult result,
202                                const char *file,
203                                const char *function,
204                                unsigned int line)
205 {
206     ASSERT(result != VK_SUCCESS);
207 
208     std::stringstream errorStream;
209     errorStream << "Internal Vulkan error (" << result << "): " << VulkanResultString(result)
210                 << ", in " << file << ", " << function << ":" << line << ".";
211     std::string errorString = errorStream.str();
212 
213     if (result == VK_ERROR_DEVICE_LOST)
214     {
215         WARN() << errorString;
216         mRenderer->notifyDeviceLost();
217     }
218 }
219 
getWindowSystem()220 angle::NativeWindowSystem CLPlatformVk::getWindowSystem()
221 {
222 #if defined(ANGLE_ENABLE_VULKAN)
223 #    if defined(ANGLE_PLATFORM_LINUX)
224 #        if defined(ANGLE_USE_GBM)
225     return angle::NativeWindowSystem::Gbm;
226 #        elif defined(ANGLE_USE_X11)
227     return angle::NativeWindowSystem::X11;
228 #        elif defined(ANGLE_USE_WAYLAND)
229     return angle::NativeWindowSystem::Wayland;
230 #        else
231     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
232     return angle::NativeWindowSystem::Other;
233 #        endif
234 #    elif defined(ANGLE_PLATFORM_ANDROID)
235     return angle::NativeWindowSystem::Other;
236 #    else
237     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
238     return angle::NativeWindowSystem::Other;
239 #    endif
240 #elif
241     UNREACHABLE();
242 #endif
243 }
244 
getWSIExtension()245 const char *CLPlatformVk::getWSIExtension()
246 {
247 #if defined(ANGLE_ENABLE_VULKAN)
248 #    if defined(ANGLE_PLATFORM_LINUX)
249 #        if defined(ANGLE_USE_GBM)
250     return nullptr;
251 #        elif defined(ANGLE_USE_X11)
252     return VK_KHR_XCB_SURFACE_EXTENSION_NAME;
253 #        elif defined(ANGLE_USE_WAYLAND)
254     return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
255 #        else
256     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
257     return nullptr;
258 #        endif
259 #    elif defined(ANGLE_PLATFORM_ANDROID)
260     return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
261 #    else
262     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
263     return nullptr;
264 #    endif
265 #elif
266     UNREACHABLE();
267 #endif
268 }
269 
270 // vk::GlobalOps
putBlob(const angle::BlobCacheKey & key,const angle::MemoryBuffer & value)271 void CLPlatformVk::putBlob(const angle::BlobCacheKey &key, const angle::MemoryBuffer &value)
272 {
273     std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex);
274     size_t valueSize = value.size();
275     mBlobCache.put(key, std::move(const_cast<angle::MemoryBuffer &>(value)), valueSize);
276 }
277 
getBlob(const angle::BlobCacheKey & key,angle::BlobCacheValue * valueOut)278 bool CLPlatformVk::getBlob(const angle::BlobCacheKey &key, angle::BlobCacheValue *valueOut)
279 {
280     std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex);
281     const angle::MemoryBuffer *entry;
282     bool result = mBlobCache.get(key, &entry);
283     if (result)
284     {
285         *valueOut = angle::BlobCacheValue(entry->data(), entry->size());
286     }
287     return result;
288 }
289 
postMultiThreadWorkerTask(const std::shared_ptr<angle::Closure> & task)290 std::shared_ptr<angle::WaitableEvent> CLPlatformVk::postMultiThreadWorkerTask(
291     const std::shared_ptr<angle::Closure> &task)
292 {
293     return mPlatform.getMultiThreadPool()->postWorkerTask(task);
294 }
295 
notifyDeviceLost()296 void CLPlatformVk::notifyDeviceLost()
297 {
298     return;
299 }
300 
301 }  // namespace rx
302