| // |
| // 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. |
| // |
| // CLPlatform.cpp: Implements the cl::Platform class. |
| |
| #include "libANGLE/CLPlatform.h" |
| |
| #include <cstdint> |
| #include <cstring> |
| |
| namespace cl |
| { |
| |
| namespace |
| { |
| |
| bool IsDeviceTypeMatch(cl_device_type select, cl_device_type type) |
| { |
| // The type 'cl_device_type' is a bitfield, so masking out the selected bits indicates |
| // if a given type is a match. A custom device is an exception, which only matches |
| // if it was explicitely selected, as defined here: |
| // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceIDs |
| return type == CL_DEVICE_TYPE_CUSTOM ? select == CL_DEVICE_TYPE_CUSTOM : (type & select) != 0u; |
| } |
| |
| Context::PropArray ParseContextProperties(const cl_context_properties *properties, |
| Platform *&platform, |
| bool &userSync) |
| { |
| Context::PropArray propArray; |
| if (properties != nullptr) |
| { |
| const cl_context_properties *propIt = properties; |
| while (*propIt != 0) |
| { |
| switch (*propIt++) |
| { |
| case CL_CONTEXT_PLATFORM: |
| platform = reinterpret_cast<Platform *>(*propIt++); |
| break; |
| case CL_CONTEXT_INTEROP_USER_SYNC: |
| userSync = *propIt++ != CL_FALSE; |
| break; |
| } |
| } |
| // Include the trailing zero |
| ++propIt; |
| propArray.reserve(propIt - properties); |
| propArray.insert(propArray.cend(), properties, propIt); |
| } |
| if (platform == nullptr) |
| { |
| platform = Platform::GetDefault(); |
| } |
| return propArray; |
| } |
| |
| } // namespace |
| |
| Platform::~Platform() |
| { |
| removeRef(); |
| } |
| |
| cl_int Platform::getInfo(PlatformInfo name, size_t valueSize, void *value, size_t *valueSizeRet) |
| { |
| const void *copyValue = nullptr; |
| size_t copySize = 0u; |
| |
| switch (name) |
| { |
| case PlatformInfo::Profile: |
| copyValue = mInfo.mProfile.c_str(); |
| copySize = mInfo.mProfile.length() + 1u; |
| break; |
| case PlatformInfo::Version: |
| copyValue = mInfo.mVersionStr.c_str(); |
| copySize = mInfo.mVersionStr.length() + 1u; |
| break; |
| case PlatformInfo::NumericVersion: |
| if (mInfo.mVersion < CL_MAKE_VERSION(3, 0, 0)) |
| { |
| return CL_INVALID_VALUE; |
| } |
| copyValue = &mInfo.mVersion; |
| copySize = sizeof(mInfo.mVersion); |
| break; |
| case PlatformInfo::Name: |
| copyValue = mInfo.mName.c_str(); |
| copySize = mInfo.mName.length() + 1u; |
| break; |
| case PlatformInfo::Vendor: |
| copyValue = kVendor; |
| copySize = sizeof(kVendor); |
| break; |
| case PlatformInfo::Extensions: |
| copyValue = mInfo.mExtensions.c_str(); |
| copySize = mInfo.mExtensions.length() + 1u; |
| break; |
| case PlatformInfo::ExtensionsWithVersion: |
| if (mInfo.mVersion < CL_MAKE_VERSION(3, 0, 0)) |
| { |
| return CL_INVALID_VALUE; |
| } |
| copyValue = mInfo.mExtensionsWithVersion.data(); |
| copySize = mInfo.mExtensionsWithVersion.size() * |
| sizeof(decltype(mInfo.mExtensionsWithVersion)::value_type); |
| break; |
| case PlatformInfo::HostTimerResolution: |
| if (mInfo.mVersion < CL_MAKE_VERSION(2, 1, 0)) |
| { |
| return CL_INVALID_VALUE; |
| } |
| copyValue = &mInfo.mHostTimerRes; |
| copySize = sizeof(mInfo.mHostTimerRes); |
| break; |
| case PlatformInfo::IcdSuffix: |
| copyValue = kIcdSuffix; |
| copySize = sizeof(kIcdSuffix); |
| break; |
| default: |
| return CL_INVALID_VALUE; |
| } |
| |
| if (value != nullptr) |
| { |
| if (valueSize < copySize) |
| { |
| return CL_INVALID_VALUE; |
| } |
| if (copyValue != nullptr) |
| { |
| std::memcpy(value, copyValue, copySize); |
| } |
| } |
| if (valueSizeRet != nullptr) |
| { |
| *valueSizeRet = copySize; |
| } |
| return CL_SUCCESS; |
| } |
| |
| cl_int Platform::getDeviceIDs(cl_device_type deviceType, |
| cl_uint numEntries, |
| cl_device_id *devices, |
| cl_uint *numDevices) const |
| { |
| cl_uint found = 0u; |
| for (const DevicePtr &device : mDevices) |
| { |
| cl_device_type type = 0u; |
| if (device->getInfoULong(DeviceInfo::Type, &type) == CL_SUCCESS && |
| IsDeviceTypeMatch(deviceType, type)) |
| { |
| if (devices != nullptr && found < numEntries) |
| { |
| devices[found] = device.get(); |
| } |
| ++found; |
| } |
| } |
| if (numDevices != nullptr) |
| { |
| *numDevices = found; |
| } |
| return found == 0u ? CL_DEVICE_NOT_FOUND : CL_SUCCESS; |
| } |
| |
| void Platform::CreatePlatform(const cl_icd_dispatch &dispatch, const CreateImplFunc &createImplFunc) |
| { |
| PlatformPtr platform(new Platform(dispatch, createImplFunc)); |
| if (platform->mInfo.isValid() && !platform->mDevices.empty()) |
| { |
| GetList().emplace_back(std::move(platform)); |
| } |
| } |
| |
| cl_int Platform::GetPlatformIDs(cl_uint num_entries, |
| cl_platform_id *platforms, |
| cl_uint *num_platforms) |
| { |
| const PtrList &platformList = GetList(); |
| if (num_platforms != nullptr) |
| { |
| *num_platforms = static_cast<cl_uint>(platformList.size()); |
| } |
| if (platforms != nullptr) |
| { |
| cl_uint entry = 0u; |
| auto platformIt = platformList.cbegin(); |
| while (entry < num_entries && platformIt != platformList.cend()) |
| { |
| platforms[entry++] = (*platformIt++).get(); |
| } |
| } |
| return CL_SUCCESS; |
| } |
| |
| cl_context Platform::CreateContext(const cl_context_properties *properties, |
| cl_uint numDevices, |
| const cl_device_id *devices, |
| ContextErrorCB notify, |
| void *userData, |
| cl_int *errcodeRet) |
| { |
| Platform *platform = nullptr; |
| bool userSync = false; |
| Context::PropArray propArray = ParseContextProperties(properties, platform, userSync); |
| ASSERT(platform != nullptr); |
| DeviceRefList refDevices; |
| while (numDevices-- != 0u) |
| { |
| refDevices.emplace_back(static_cast<Device *>(*devices++)); |
| } |
| |
| platform->mContexts.emplace_back(new Context(*platform, std::move(propArray), |
| std::move(refDevices), notify, userData, userSync, |
| errcodeRet)); |
| if (!platform->mContexts.back()->mImpl) |
| { |
| platform->mContexts.back()->release(); |
| return nullptr; |
| } |
| return platform->mContexts.back().get(); |
| } |
| |
| cl_context Platform::CreateContextFromType(const cl_context_properties *properties, |
| cl_device_type deviceType, |
| ContextErrorCB notify, |
| void *userData, |
| cl_int *errcodeRet) |
| { |
| Platform *platform = nullptr; |
| bool userSync = false; |
| Context::PropArray propArray = ParseContextProperties(properties, platform, userSync); |
| ASSERT(platform != nullptr); |
| |
| platform->mContexts.emplace_back(new Context(*platform, std::move(propArray), deviceType, |
| notify, userData, userSync, errcodeRet)); |
| if (!platform->mContexts.back()->mImpl || platform->mContexts.back()->mDevices.empty()) |
| { |
| platform->mContexts.back()->release(); |
| return nullptr; |
| } |
| return platform->mContexts.back().get(); |
| } |
| |
| Platform::Platform(const cl_icd_dispatch &dispatch, const CreateImplFunc &createImplFunc) |
| : _cl_platform_id(dispatch), |
| mImpl(createImplFunc(*this)), |
| mInfo(mImpl->createInfo()), |
| mDevices(mImpl->createDevices(*this)) |
| {} |
| |
| void Platform::destroyContext(Context *context) |
| { |
| auto contextIt = mContexts.cbegin(); |
| while (contextIt != mContexts.cend() && contextIt->get() != context) |
| { |
| ++contextIt; |
| } |
| if (contextIt != mContexts.cend()) |
| { |
| mContexts.erase(contextIt); |
| } |
| else |
| { |
| ERR() << "Context not found"; |
| } |
| } |
| |
| constexpr char Platform::kVendor[]; |
| constexpr char Platform::kIcdSuffix[]; |
| |
| } // namespace cl |