• 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 #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT)
29 constexpr vk::UseDebugLayers kUseDebugLayers = vk::UseDebugLayers::YesIfAvailable;
30 #else
31 constexpr vk::UseDebugLayers kUseDebugLayers = vk::UseDebugLayers::No;
32 #endif
33 
34 #if defined(ANGLE_OPENCL_COMPUTE_ONLY_PIPE)
35 constexpr bool kUseComputeOnlyQueue = true;
36 #else
37 constexpr bool kUseComputeOnlyQueue = false;
38 #endif
39 }  // namespace
40 
initBackendRenderer()41 angle::Result CLPlatformVk::initBackendRenderer()
42 {
43     ASSERT(mRenderer != nullptr);
44 
45     angle::FeatureOverrides featureOverrides;
46 
47     // In memory |SizedMRUCache| does not require dual slots, supports zero sized values, and evicts
48     // minumum number of old items when storing a new item.
49     featureOverrides.disabled.push_back("useDualPipelineBlobCacheSlots");
50     featureOverrides.enabled.push_back("useEmptyBlobsToEraseOldPipelineCacheFromBlobCache");
51     featureOverrides.enabled.push_back("hasBlobCacheThatEvictsOldItemsFirst");
52     featureOverrides.disabled.push_back("verifyPipelineCacheInBlobCache");
53 
54     ANGLE_TRY(mRenderer->initialize(this, this, angle::vk::ICD::Default, 0, 0, nullptr, nullptr,
55                                     static_cast<VkDriverId>(0), kUseDebugLayers, getWSIExtension(),
56                                     getWSILayer(), getWindowSystem(), featureOverrides));
57 
58     return angle::Result::Continue;
59 }
60 
~CLPlatformVk()61 CLPlatformVk::~CLPlatformVk()
62 {
63     ASSERT(mRenderer);
64     mRenderer->onDestroy(this);
65     delete mRenderer;
66 }
67 
createInfo() const68 CLPlatformImpl::Info CLPlatformVk::createInfo() const
69 {
70     NameVersionVector extList = {
71         cl_name_version{CL_MAKE_VERSION(1, 0, 0), "cl_khr_icd"},
72         cl_name_version{CL_MAKE_VERSION(1, 0, 0), "cl_khr_extended_versioning"}};
73 
74     Info info;
75     info.name.assign("ANGLE Vulkan");
76     info.profile.assign("FULL_PROFILE");
77     info.versionStr.assign(GetVersionString());
78     info.hostTimerRes = 0u;
79     info.version      = GetVersion();
80 
81     info.initializeVersionedExtensions(std::move(extList));
82     return info;
83 }
84 
createDevices() const85 CLDeviceImpl::CreateDatas CLPlatformVk::createDevices() const
86 {
87     CLDeviceImpl::CreateDatas createDatas;
88 
89     // Convert Vk device type to CL equivalent
90     cl_device_type type = CL_DEVICE_TYPE_DEFAULT;
91     switch (mRenderer->getPhysicalDeviceProperties().deviceType)
92     {
93         case VK_PHYSICAL_DEVICE_TYPE_CPU:
94             type |= CL_DEVICE_TYPE_CPU;
95             break;
96         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
97         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
98         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
99             type |= CL_DEVICE_TYPE_GPU;
100             break;
101         case VK_PHYSICAL_DEVICE_TYPE_OTHER:
102         case VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM:
103             // The default OpenCL device must not be a CL_DEVICE_TYPE_CUSTOM device.
104             // Thus, we override type bitfield to custom only.
105             type = CL_DEVICE_TYPE_CUSTOM;
106             break;
107     }
108 
109     createDatas.emplace_back(type, [this](const cl::Device &device) {
110         return CLDeviceVk::Ptr(new CLDeviceVk(device, mRenderer));
111     });
112     return createDatas;
113 }
114 
createContext(cl::Context & context,const cl::DevicePtrs & devices,bool userSync,CLContextImpl::Ptr * contextOut)115 angle::Result CLPlatformVk::createContext(cl::Context &context,
116                                           const cl::DevicePtrs &devices,
117                                           bool userSync,
118                                           CLContextImpl::Ptr *contextOut)
119 {
120     *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices));
121     if (*contextOut == nullptr)
122     {
123         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
124     }
125     return angle::Result::Continue;
126 }
127 
createContextFromType(cl::Context & context,cl::DeviceType deviceType,bool userSync,CLContextImpl::Ptr * contextOut)128 angle::Result CLPlatformVk::createContextFromType(cl::Context &context,
129                                                   cl::DeviceType deviceType,
130                                                   bool userSync,
131                                                   CLContextImpl::Ptr *contextOut)
132 {
133     const VkPhysicalDeviceType &vkPhysicalDeviceType =
134         getRenderer()->getPhysicalDeviceProperties().deviceType;
135 
136     if (deviceType.intersects(CL_DEVICE_TYPE_CPU) &&
137         vkPhysicalDeviceType != VK_PHYSICAL_DEVICE_TYPE_CPU)
138     {
139         ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
140     }
141     else if (deviceType.intersects(CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_DEFAULT))
142     {
143         switch (vkPhysicalDeviceType)
144         {
145             case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
146             case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
147             case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
148                 break;
149             default:
150                 ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
151         }
152     }
153     else
154     {
155         ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
156     }
157 
158     cl::DevicePtrs devices;
159     for (const auto &platformDevice : mPlatform.getDevices())
160     {
161         const auto &platformDeviceInfo = platformDevice->getInfo();
162         if (platformDeviceInfo.type.intersects(deviceType))
163         {
164             devices.push_back(platformDevice);
165         }
166     }
167 
168     *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices));
169     if (*contextOut == nullptr)
170     {
171         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
172     }
173     return angle::Result::Continue;
174 }
175 
unloadCompiler()176 angle::Result CLPlatformVk::unloadCompiler()
177 {
178     return angle::Result::Continue;
179 }
180 
Initialize(CreateFuncs & createFuncs)181 void CLPlatformVk::Initialize(CreateFuncs &createFuncs)
182 {
183     createFuncs.emplace_back([](const cl::Platform &platform) -> CLPlatformImpl::Ptr {
184         CLPlatformVk::Ptr platformVk = CLPlatformVk::Ptr(new (std::nothrow) CLPlatformVk(platform));
185         if (platformVk == nullptr || IsError(platformVk->initBackendRenderer()))
186         {
187             return Ptr(nullptr);
188         }
189         return Ptr(std::move(platformVk));
190     });
191 }
192 
GetVersionString()193 const std::string &CLPlatformVk::GetVersionString()
194 {
195     static const angle::base::NoDestructor<const std::string> sVersion(
196         "OpenCL " + std::to_string(CL_VERSION_MAJOR(GetVersion())) + "." +
197         std::to_string(CL_VERSION_MINOR(GetVersion())) + " ANGLE " +
198         angle::GetANGLEVersionString());
199     return *sVersion;
200 }
201 
CLPlatformVk(const cl::Platform & platform)202 CLPlatformVk::CLPlatformVk(const cl::Platform &platform)
203     : CLPlatformImpl(platform), vk::ErrorContext(new vk::Renderer()), mBlobCache(1024 * 1024)
204 {}
205 
handleError(VkResult result,const char * file,const char * function,unsigned int line)206 void CLPlatformVk::handleError(VkResult result,
207                                const char *file,
208                                const char *function,
209                                unsigned int line)
210 {
211     ASSERT(result != VK_SUCCESS);
212 
213     std::stringstream errorStream;
214     errorStream << "Internal Vulkan error (" << result << "): " << VulkanResultString(result)
215                 << ", in " << file << ", " << function << ":" << line << ".";
216     std::string errorString = errorStream.str();
217 
218     if (result == VK_ERROR_DEVICE_LOST)
219     {
220         WARN() << errorString;
221         mRenderer->notifyDeviceLost();
222     }
223 }
224 
getWindowSystem()225 angle::NativeWindowSystem CLPlatformVk::getWindowSystem()
226 {
227     if (kUseComputeOnlyQueue)
228     {
229         return angle::NativeWindowSystem::NullCompute;
230     }
231     else
232     {
233         return angle::NativeWindowSystem::Other;
234     }
235 }
236 
getWSIExtension()237 const char *CLPlatformVk::getWSIExtension()
238 {
239 #if defined(ANGLE_ENABLE_VULKAN)
240 #    if defined(ANGLE_PLATFORM_LINUX)
241 #        if defined(ANGLE_USE_GBM)
242     return nullptr;
243 #        elif defined(ANGLE_USE_X11)
244     return VK_KHR_XCB_SURFACE_EXTENSION_NAME;
245 #        elif defined(ANGLE_USE_WAYLAND)
246     return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
247 #        else
248     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
249     return nullptr;
250 #        endif
251 #    elif defined(ANGLE_PLATFORM_ANDROID)
252     return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
253 #    else
254     handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__);
255     return nullptr;
256 #    endif
257 #elif
258     UNREACHABLE();
259 #endif
260 }
261 
262 // vk::GlobalOps
putBlob(const angle::BlobCacheKey & key,const angle::MemoryBuffer & value)263 void CLPlatformVk::putBlob(const angle::BlobCacheKey &key, const angle::MemoryBuffer &value)
264 {
265     std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex);
266     size_t valueSize = value.size();
267     mBlobCache.put(key, std::move(const_cast<angle::MemoryBuffer &>(value)), valueSize);
268 }
269 
getBlob(const angle::BlobCacheKey & key,angle::BlobCacheValue * valueOut)270 bool CLPlatformVk::getBlob(const angle::BlobCacheKey &key, angle::BlobCacheValue *valueOut)
271 {
272     std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex);
273     const angle::MemoryBuffer *entry;
274     bool result = mBlobCache.get(key, &entry);
275     if (result)
276     {
277         *valueOut = angle::BlobCacheValue(entry->data(), entry->size());
278     }
279     return result;
280 }
281 
postMultiThreadWorkerTask(const std::shared_ptr<angle::Closure> & task)282 std::shared_ptr<angle::WaitableEvent> CLPlatformVk::postMultiThreadWorkerTask(
283     const std::shared_ptr<angle::Closure> &task)
284 {
285     return mPlatform.getMultiThreadPool()->postWorkerTask(task);
286 }
287 
notifyDeviceLost()288 void CLPlatformVk::notifyDeviceLost()
289 {
290     return;
291 }
292 
293 }  // namespace rx
294