| // |
| // Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // CLPlatformVk.cpp: Implements the class methods for CLPlatformVk. |
| |
| #include "libANGLE/renderer/vulkan/CLPlatformVk.h" |
| #include "common/vulkan/vulkan_icd.h" |
| #include "libANGLE/angletypes.h" |
| #include "libANGLE/renderer/vulkan/CLContextVk.h" |
| #include "libANGLE/renderer/vulkan/CLDeviceVk.h" |
| #include "libANGLE/renderer/vulkan/vk_renderer.h" |
| |
| #include "libANGLE/CLPlatform.h" |
| #include "libANGLE/cl_utils.h" |
| |
| #include "anglebase/no_destructor.h" |
| #include "common/angle_version_info.h" |
| #include "libANGLE/renderer/vulkan/vk_utils.h" |
| #include "vulkan/vulkan_core.h" |
| |
| namespace rx |
| { |
| |
| namespace |
| { |
| #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) |
| constexpr vk::UseDebugLayers kUseDebugLayers = vk::UseDebugLayers::YesIfAvailable; |
| #else |
| constexpr vk::UseDebugLayers kUseDebugLayers = vk::UseDebugLayers::No; |
| #endif |
| |
| #if defined(ANGLE_OPENCL_COMPUTE_ONLY_PIPE) |
| constexpr bool kUseComputeOnlyQueue = true; |
| #else |
| constexpr bool kUseComputeOnlyQueue = false; |
| #endif |
| } // namespace |
| |
| angle::Result CLPlatformVk::initBackendRenderer() |
| { |
| ASSERT(mRenderer != nullptr); |
| |
| angle::FeatureOverrides featureOverrides; |
| |
| // In memory |SizedMRUCache| does not require dual slots, supports zero sized values, and evicts |
| // minumum number of old items when storing a new item. |
| featureOverrides.disabled.push_back("useDualPipelineBlobCacheSlots"); |
| featureOverrides.enabled.push_back("useEmptyBlobsToEraseOldPipelineCacheFromBlobCache"); |
| featureOverrides.enabled.push_back("hasBlobCacheThatEvictsOldItemsFirst"); |
| featureOverrides.disabled.push_back("verifyPipelineCacheInBlobCache"); |
| |
| ANGLE_TRY(mRenderer->initialize(this, this, angle::vk::ICD::Default, 0, 0, nullptr, nullptr, |
| static_cast<VkDriverId>(0), kUseDebugLayers, getWSIExtension(), |
| getWSILayer(), getWindowSystem(), featureOverrides)); |
| |
| return angle::Result::Continue; |
| } |
| |
| CLPlatformVk::~CLPlatformVk() |
| { |
| ASSERT(mRenderer); |
| mRenderer->onDestroy(this); |
| delete mRenderer; |
| } |
| |
| CLPlatformImpl::Info CLPlatformVk::createInfo() const |
| { |
| NameVersionVector extList = { |
| cl_name_version{CL_MAKE_VERSION(1, 0, 0), "cl_khr_icd"}, |
| cl_name_version{CL_MAKE_VERSION(1, 0, 0), "cl_khr_extended_versioning"}}; |
| |
| Info info; |
| info.name.assign("ANGLE Vulkan"); |
| info.profile.assign("FULL_PROFILE"); |
| info.versionStr.assign(GetVersionString()); |
| info.hostTimerRes = 0u; |
| info.version = GetVersion(); |
| |
| info.initializeVersionedExtensions(std::move(extList)); |
| return info; |
| } |
| |
| CLDeviceImpl::CreateDatas CLPlatformVk::createDevices() const |
| { |
| CLDeviceImpl::CreateDatas createDatas; |
| |
| // Convert Vk device type to CL equivalent |
| cl_device_type type = CL_DEVICE_TYPE_DEFAULT; |
| switch (mRenderer->getPhysicalDeviceProperties().deviceType) |
| { |
| case VK_PHYSICAL_DEVICE_TYPE_CPU: |
| type |= CL_DEVICE_TYPE_CPU; |
| break; |
| case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: |
| case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: |
| case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: |
| type |= CL_DEVICE_TYPE_GPU; |
| break; |
| case VK_PHYSICAL_DEVICE_TYPE_OTHER: |
| case VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM: |
| // The default OpenCL device must not be a CL_DEVICE_TYPE_CUSTOM device. |
| // Thus, we override type bitfield to custom only. |
| type = CL_DEVICE_TYPE_CUSTOM; |
| break; |
| } |
| |
| createDatas.emplace_back(type, [this](const cl::Device &device) { |
| return CLDeviceVk::Ptr(new CLDeviceVk(device, mRenderer)); |
| }); |
| return createDatas; |
| } |
| |
| angle::Result CLPlatformVk::createContext(cl::Context &context, |
| const cl::DevicePtrs &devices, |
| bool userSync, |
| CLContextImpl::Ptr *contextOut) |
| { |
| *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices)); |
| if (*contextOut == nullptr) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY); |
| } |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLPlatformVk::createContextFromType(cl::Context &context, |
| cl::DeviceType deviceType, |
| bool userSync, |
| CLContextImpl::Ptr *contextOut) |
| { |
| const VkPhysicalDeviceType &vkPhysicalDeviceType = |
| getRenderer()->getPhysicalDeviceProperties().deviceType; |
| |
| if (deviceType.intersects(CL_DEVICE_TYPE_CPU) && |
| vkPhysicalDeviceType != VK_PHYSICAL_DEVICE_TYPE_CPU) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND); |
| } |
| else if (deviceType.intersects(CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_DEFAULT)) |
| { |
| switch (vkPhysicalDeviceType) |
| { |
| case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: |
| case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: |
| case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: |
| break; |
| default: |
| ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND); |
| } |
| } |
| else |
| { |
| ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND); |
| } |
| |
| cl::DevicePtrs devices; |
| for (const auto &platformDevice : mPlatform.getDevices()) |
| { |
| const auto &platformDeviceInfo = platformDevice->getInfo(); |
| if (platformDeviceInfo.type.intersects(deviceType)) |
| { |
| devices.push_back(platformDevice); |
| } |
| } |
| |
| *contextOut = CLContextImpl::Ptr(new (std::nothrow) CLContextVk(context, devices)); |
| if (*contextOut == nullptr) |
| { |
| ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY); |
| } |
| return angle::Result::Continue; |
| } |
| |
| angle::Result CLPlatformVk::unloadCompiler() |
| { |
| return angle::Result::Continue; |
| } |
| |
| void CLPlatformVk::Initialize(CreateFuncs &createFuncs) |
| { |
| createFuncs.emplace_back([](const cl::Platform &platform) -> CLPlatformImpl::Ptr { |
| CLPlatformVk::Ptr platformVk = CLPlatformVk::Ptr(new (std::nothrow) CLPlatformVk(platform)); |
| if (platformVk == nullptr || IsError(platformVk->initBackendRenderer())) |
| { |
| return Ptr(nullptr); |
| } |
| return Ptr(std::move(platformVk)); |
| }); |
| } |
| |
| const std::string &CLPlatformVk::GetVersionString() |
| { |
| static const angle::base::NoDestructor<const std::string> sVersion( |
| "OpenCL " + std::to_string(CL_VERSION_MAJOR(GetVersion())) + "." + |
| std::to_string(CL_VERSION_MINOR(GetVersion())) + " ANGLE " + |
| angle::GetANGLEVersionString()); |
| return *sVersion; |
| } |
| |
| CLPlatformVk::CLPlatformVk(const cl::Platform &platform) |
| : CLPlatformImpl(platform), vk::ErrorContext(new vk::Renderer()), mBlobCache(1024 * 1024) |
| {} |
| |
| void CLPlatformVk::handleError(VkResult result, |
| const char *file, |
| const char *function, |
| unsigned int line) |
| { |
| ASSERT(result != VK_SUCCESS); |
| |
| std::stringstream errorStream; |
| errorStream << "Internal Vulkan error (" << result << "): " << VulkanResultString(result) |
| << ", in " << file << ", " << function << ":" << line << "."; |
| std::string errorString = errorStream.str(); |
| |
| if (result == VK_ERROR_DEVICE_LOST) |
| { |
| WARN() << errorString; |
| mRenderer->notifyDeviceLost(); |
| } |
| } |
| |
| angle::NativeWindowSystem CLPlatformVk::getWindowSystem() |
| { |
| if (kUseComputeOnlyQueue) |
| { |
| return angle::NativeWindowSystem::NullCompute; |
| } |
| else |
| { |
| return angle::NativeWindowSystem::Other; |
| } |
| } |
| |
| const char *CLPlatformVk::getWSIExtension() |
| { |
| #if defined(ANGLE_ENABLE_VULKAN) |
| # if defined(ANGLE_PLATFORM_LINUX) |
| # if defined(ANGLE_USE_GBM) |
| return nullptr; |
| # elif defined(ANGLE_USE_X11) |
| return VK_KHR_XCB_SURFACE_EXTENSION_NAME; |
| # elif defined(ANGLE_USE_WAYLAND) |
| return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; |
| # else |
| handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__); |
| return nullptr; |
| # endif |
| # elif defined(ANGLE_PLATFORM_ANDROID) |
| return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; |
| # else |
| handleError(VK_ERROR_INCOMPATIBLE_DRIVER, __FILE__, __func__, __LINE__); |
| return nullptr; |
| # endif |
| #elif |
| UNREACHABLE(); |
| #endif |
| } |
| |
| // vk::GlobalOps |
| void CLPlatformVk::putBlob(const angle::BlobCacheKey &key, const angle::MemoryBuffer &value) |
| { |
| std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex); |
| size_t valueSize = value.size(); |
| mBlobCache.put(key, std::move(const_cast<angle::MemoryBuffer &>(value)), valueSize); |
| } |
| |
| bool CLPlatformVk::getBlob(const angle::BlobCacheKey &key, angle::BlobCacheValue *valueOut) |
| { |
| std::scoped_lock<angle::SimpleMutex> lock(mBlobCacheMutex); |
| const angle::MemoryBuffer *entry; |
| bool result = mBlobCache.get(key, &entry); |
| if (result) |
| { |
| *valueOut = angle::BlobCacheValue(entry->data(), entry->size()); |
| } |
| return result; |
| } |
| |
| std::shared_ptr<angle::WaitableEvent> CLPlatformVk::postMultiThreadWorkerTask( |
| const std::shared_ptr<angle::Closure> &task) |
| { |
| return mPlatform.getMultiThreadPool()->postWorkerTask(task); |
| } |
| |
| void CLPlatformVk::notifyDeviceLost() |
| { |
| return; |
| } |
| |
| } // namespace rx |